blob: 2007c8c2c52b534ad0e848bd73d92ae46e88e21e [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 Melo514f1c62012-09-26 20:05:56 -0300565static struct syscall_fmt {
566 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300567 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300568 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300569 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300570 bool errmsg;
571 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300572 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300573} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300574 { .name = "access", .errmsg = true,
575 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300576 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300577 { .name = "brk", .hexret = true,
578 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300579 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300580 { .name = "epoll_ctl", .errmsg = true,
581 .arg_scnprintf = { [1] = SCA_STRARRAY, /* op */ },
582 .arg_parm = { [1] = &strarray__epoll_ctl_ops, /* op */ }, },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300583 { .name = "eventfd2", .errmsg = true,
584 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300585 { .name = "fcntl", .errmsg = true,
586 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
587 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
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 Melo1f115cb2013-09-03 15:50:28 -0300594 { .name = "getitimer", .errmsg = true,
595 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
596 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300597 { .name = "getrlimit", .errmsg = true,
598 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
599 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300600 { .name = "ioctl", .errmsg = true,
601 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300602 { .name = "kill", .errmsg = true,
603 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo579e7862013-09-02 15:37:32 -0300604 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300605 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
606 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300607 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300608 { .name = "madvise", .errmsg = true,
609 .arg_scnprintf = { [0] = SCA_HEX, /* start */
610 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300611 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300612 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300613 [2] = SCA_MMAP_PROT, /* prot */
614 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300615 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300616 .arg_scnprintf = { [0] = SCA_HEX, /* start */
617 [2] = SCA_MMAP_PROT, /* prot */ }, },
618 { .name = "mremap", .hexret = true,
619 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
620 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300621 { .name = "munmap", .errmsg = true,
622 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300623 { .name = "open", .errmsg = true,
624 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300625 { .name = "open_by_handle_at", .errmsg = true,
626 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
627 { .name = "openat", .errmsg = true,
628 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300629 { .name = "poll", .errmsg = true, .timeout = true, },
630 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300631 { .name = "pread", .errmsg = true, .alias = "pread64", },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300632 { .name = "prlimit64", .errmsg = true,
633 .arg_scnprintf = { [1] = SCA_STRARRAY, /* resource */ },
634 .arg_parm = { [1] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300635 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300636 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300637 { .name = "recvfrom", .errmsg = true,
638 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
639 { .name = "recvmmsg", .errmsg = true,
640 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
641 { .name = "recvmsg", .errmsg = true,
642 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300643 { .name = "rt_sigaction", .errmsg = true,
644 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300645 { .name = "rt_sigprocmask", .errmsg = true,
646 .arg_scnprintf = { [0] = SCA_STRARRAY, /* how */ },
647 .arg_parm = { [0] = &strarray__sighow, /* how */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300648 { .name = "rt_sigqueueinfo", .errmsg = true,
649 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
650 { .name = "rt_tgsigqueueinfo", .errmsg = true,
651 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300652 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300653 { .name = "sendmmsg", .errmsg = true,
654 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
655 { .name = "sendmsg", .errmsg = true,
656 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
657 { .name = "sendto", .errmsg = true,
658 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300659 { .name = "setitimer", .errmsg = true,
660 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
661 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300662 { .name = "setrlimit", .errmsg = true,
663 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
664 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300665 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300666 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
667 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300668 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300669 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300670 { .name = "tgkill", .errmsg = true,
671 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
672 { .name = "tkill", .errmsg = true,
673 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300674 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300675};
676
677static int syscall_fmt__cmp(const void *name, const void *fmtp)
678{
679 const struct syscall_fmt *fmt = fmtp;
680 return strcmp(name, fmt->name);
681}
682
683static struct syscall_fmt *syscall_fmt__find(const char *name)
684{
685 const int nmemb = ARRAY_SIZE(syscall_fmts);
686 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
687}
688
689struct syscall {
690 struct event_format *tp_format;
691 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300692 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300693 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300694 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300695 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300696};
697
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200698static size_t fprintf_duration(unsigned long t, FILE *fp)
699{
700 double duration = (double)t / NSEC_PER_MSEC;
701 size_t printed = fprintf(fp, "(");
702
703 if (duration >= 1.0)
704 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
705 else if (duration >= 0.01)
706 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
707 else
708 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300709 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200710}
711
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300712struct thread_trace {
713 u64 entry_time;
714 u64 exit_time;
715 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300716 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300717 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300718 double runtime_ms;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300719};
720
721static struct thread_trace *thread_trace__new(void)
722{
723 return zalloc(sizeof(struct thread_trace));
724}
725
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300726static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300727{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300728 struct thread_trace *ttrace;
729
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300730 if (thread == NULL)
731 goto fail;
732
733 if (thread->priv == NULL)
734 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300735
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300736 if (thread->priv == NULL)
737 goto fail;
738
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300739 ttrace = thread->priv;
740 ++ttrace->nr_events;
741
742 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300743fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300744 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300745 "WARNING: not enough memory, dropping samples!\n");
746 return NULL;
747}
748
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300749struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300750 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300751 int audit_machine;
752 struct {
753 int max;
754 struct syscall *table;
755 } syscalls;
756 struct perf_record_opts opts;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300757 struct machine host;
758 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600759 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300760 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300761 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300762 struct strlist *ev_qualifier;
763 bool not_ev_qualifier;
David Ahernbdc89662013-08-28 22:29:53 -0600764 struct intlist *tid_list;
765 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300766 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300767 bool multiple_threads;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300768 bool show_comm;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300769 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300770 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300771};
772
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300773static bool trace__filter_duration(struct trace *trace, double t)
774{
775 return t < (trace->duration_filter * NSEC_PER_MSEC);
776}
777
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300778static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
779{
780 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
781
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200782 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300783}
784
Namhyung Kimf15eb532012-10-05 14:02:16 +0900785static bool done = false;
786
787static void sig_handler(int sig __maybe_unused)
788{
789 done = true;
790}
791
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300792static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200793 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300794{
795 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200796 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300797
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300798 if (trace->multiple_threads) {
799 if (trace->show_comm)
800 printed += fprintf(fp, "%.14s/", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +0300801 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300802 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300803
804 return printed;
805}
806
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300807static int trace__process_event(struct trace *trace, struct machine *machine,
808 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300809{
810 int ret = 0;
811
812 switch (event->header.type) {
813 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300814 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300815 "LOST %" PRIu64 " events!\n", event->lost.lost);
816 ret = machine__process_lost_event(machine, event);
817 default:
818 ret = machine__process_event(machine, event);
819 break;
820 }
821
822 return ret;
823}
824
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300825static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300826 union perf_event *event,
827 struct perf_sample *sample __maybe_unused,
828 struct machine *machine)
829{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300830 struct trace *trace = container_of(tool, struct trace, tool);
831 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300832}
833
834static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
835{
836 int err = symbol__init();
837
838 if (err)
839 return err;
840
841 machine__init(&trace->host, "", HOST_KERNEL_ID);
842 machine__create_kernel_maps(&trace->host);
843
844 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300845 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300846 trace__tool_process,
847 &trace->host);
848 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300849 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300850 &trace->host);
851 }
852
853 if (err)
854 symbol__exit();
855
856 return err;
857}
858
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300859static int syscall__set_arg_fmts(struct syscall *sc)
860{
861 struct format_field *field;
862 int idx = 0;
863
864 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
865 if (sc->arg_scnprintf == NULL)
866 return -1;
867
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300868 if (sc->fmt)
869 sc->arg_parm = sc->fmt->arg_parm;
870
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300871 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300872 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
873 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
874 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300875 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
876 ++idx;
877 }
878
879 return 0;
880}
881
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300882static int trace__read_syscall_info(struct trace *trace, int id)
883{
884 char tp_name[128];
885 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300886 const char *name = audit_syscall_to_name(id, trace->audit_machine);
887
888 if (name == NULL)
889 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300890
891 if (id > trace->syscalls.max) {
892 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
893
894 if (nsyscalls == NULL)
895 return -1;
896
897 if (trace->syscalls.max != -1) {
898 memset(nsyscalls + trace->syscalls.max + 1, 0,
899 (id - trace->syscalls.max) * sizeof(*sc));
900 } else {
901 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
902 }
903
904 trace->syscalls.table = nsyscalls;
905 trace->syscalls.max = id;
906 }
907
908 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300909 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300910
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300911 if (trace->ev_qualifier) {
912 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
913
914 if (!(in ^ trace->not_ev_qualifier)) {
915 sc->filtered = true;
916 /*
917 * No need to do read tracepoint information since this will be
918 * filtered out.
919 */
920 return 0;
921 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300922 }
923
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300924 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300925
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300926 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
927 sc->tp_format = event_format__new("syscalls", tp_name);
928
929 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
930 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
931 sc->tp_format = event_format__new("syscalls", tp_name);
932 }
933
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300934 if (sc->tp_format == NULL)
935 return -1;
936
937 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300938}
939
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300940static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
941 unsigned long *args)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300942{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300943 size_t printed = 0;
944
945 if (sc->tp_format != NULL) {
946 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300947 u8 bit = 1;
948 struct syscall_arg arg = {
949 .idx = 0,
950 .mask = 0,
951 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300952
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300953 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300954 field = field->next, ++arg.idx, bit <<= 1) {
955 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300956 continue;
957
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -0300958 if (args[arg.idx] == 0)
959 continue;
960
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300961 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300962 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300963 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
964 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300965 if (sc->arg_parm)
966 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300967 printed += sc->arg_scnprintf[arg.idx](bf + printed,
968 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300969 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300970 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300971 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300972 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300973 }
974 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300975 int i = 0;
976
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300977 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300978 printed += scnprintf(bf + printed, size - printed,
979 "%sarg%d: %ld",
980 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300981 ++i;
982 }
983 }
984
985 return printed;
986}
987
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300988typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
989 struct perf_sample *sample);
990
991static struct syscall *trace__syscall_info(struct trace *trace,
992 struct perf_evsel *evsel,
993 struct perf_sample *sample)
994{
995 int id = perf_evsel__intval(evsel, sample, "id");
996
997 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -0300998
999 /*
1000 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1001 * before that, leaving at a higher verbosity level till that is
1002 * explained. Reproduced with plain ftrace with:
1003 *
1004 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1005 * grep "NR -1 " /t/trace_pipe
1006 *
1007 * After generating some load on the machine.
1008 */
1009 if (verbose > 1) {
1010 static u64 n;
1011 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1012 id, perf_evsel__name(evsel), ++n);
1013 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001014 return NULL;
1015 }
1016
1017 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1018 trace__read_syscall_info(trace, id))
1019 goto out_cant_read;
1020
1021 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1022 goto out_cant_read;
1023
1024 return &trace->syscalls.table[id];
1025
1026out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001027 if (verbose) {
1028 fprintf(trace->output, "Problems reading syscall %d", id);
1029 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1030 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1031 fputs(" information\n", trace->output);
1032 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001033 return NULL;
1034}
1035
1036static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1037 struct perf_sample *sample)
1038{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001039 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001040 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001041 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001042 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001043 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001044 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001045
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001046 if (sc == NULL)
1047 return -1;
1048
1049 if (sc->filtered)
1050 return 0;
1051
Adrian Hunter314add62013-08-27 11:23:03 +03001052 thread = machine__findnew_thread(&trace->host, sample->pid,
1053 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001054 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001055 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001056 return -1;
1057
1058 args = perf_evsel__rawptr(evsel, sample, "args");
1059 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001060 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001061 return -1;
1062 }
1063
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001064 ttrace = thread->priv;
1065
1066 if (ttrace->entry_str == NULL) {
1067 ttrace->entry_str = malloc(1024);
1068 if (!ttrace->entry_str)
1069 return -1;
1070 }
1071
1072 ttrace->entry_time = sample->time;
1073 msg = ttrace->entry_str;
1074 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1075
1076 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
1077
1078 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001079 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001080 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1081 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001082 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001083 } else
1084 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001085
1086 return 0;
1087}
1088
1089static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1090 struct perf_sample *sample)
1091{
1092 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001093 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001094 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001095 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001096 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001097
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001098 if (sc == NULL)
1099 return -1;
1100
1101 if (sc->filtered)
1102 return 0;
1103
Adrian Hunter314add62013-08-27 11:23:03 +03001104 thread = machine__findnew_thread(&trace->host, sample->pid,
1105 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001106 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001107 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001108 return -1;
1109
1110 ret = perf_evsel__intval(evsel, sample, "ret");
1111
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001112 ttrace = thread->priv;
1113
1114 ttrace->exit_time = sample->time;
1115
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001116 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001117 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001118 if (trace__filter_duration(trace, duration))
1119 goto out;
1120 } else if (trace->duration_filter)
1121 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001122
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001123 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001124
1125 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001126 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001127 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001128 fprintf(trace->output, " ... [");
1129 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1130 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001131 }
1132
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001133 if (sc->fmt == NULL) {
1134signed_print:
1135 fprintf(trace->output, ") = %d", ret);
1136 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001137 char bf[256];
1138 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1139 *e = audit_errno_to_name(-ret);
1140
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001141 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001142 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001143 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001144 else if (sc->fmt->hexret)
1145 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001146 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001147 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001148
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001149 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001150out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001151 ttrace->entry_pending = false;
1152
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001153 return 0;
1154}
1155
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001156static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1157 struct perf_sample *sample)
1158{
1159 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1160 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
Adrian Hunter314add62013-08-27 11:23:03 +03001161 struct thread *thread = machine__findnew_thread(&trace->host,
1162 sample->pid,
1163 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001164 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001165
1166 if (ttrace == NULL)
1167 goto out_dump;
1168
1169 ttrace->runtime_ms += runtime_ms;
1170 trace->runtime_ms += runtime_ms;
1171 return 0;
1172
1173out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001174 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001175 evsel->name,
1176 perf_evsel__strval(evsel, sample, "comm"),
1177 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1178 runtime,
1179 perf_evsel__intval(evsel, sample, "vruntime"));
1180 return 0;
1181}
1182
David Ahernbdc89662013-08-28 22:29:53 -06001183static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1184{
1185 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1186 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1187 return false;
1188
1189 if (trace->pid_list || trace->tid_list)
1190 return true;
1191
1192 return false;
1193}
1194
David Ahern6810fc92013-08-28 22:29:52 -06001195static int trace__process_sample(struct perf_tool *tool,
1196 union perf_event *event __maybe_unused,
1197 struct perf_sample *sample,
1198 struct perf_evsel *evsel,
1199 struct machine *machine __maybe_unused)
1200{
1201 struct trace *trace = container_of(tool, struct trace, tool);
1202 int err = 0;
1203
1204 tracepoint_handler handler = evsel->handler.func;
1205
David Ahernbdc89662013-08-28 22:29:53 -06001206 if (skip_sample(trace, sample))
1207 return 0;
1208
David Ahern4bb09192013-09-04 12:37:43 -06001209 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001210 trace->base_time = sample->time;
1211
1212 if (handler)
1213 handler(trace, evsel, sample);
1214
1215 return err;
1216}
1217
1218static bool
1219perf_session__has_tp(struct perf_session *session, const char *name)
1220{
1221 struct perf_evsel *evsel;
1222
1223 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1224
1225 return evsel != NULL;
1226}
1227
David Ahernbdc89662013-08-28 22:29:53 -06001228static int parse_target_str(struct trace *trace)
1229{
1230 if (trace->opts.target.pid) {
1231 trace->pid_list = intlist__new(trace->opts.target.pid);
1232 if (trace->pid_list == NULL) {
1233 pr_err("Error parsing process id string\n");
1234 return -EINVAL;
1235 }
1236 }
1237
1238 if (trace->opts.target.tid) {
1239 trace->tid_list = intlist__new(trace->opts.target.tid);
1240 if (trace->tid_list == NULL) {
1241 pr_err("Error parsing thread id string\n");
1242 return -EINVAL;
1243 }
1244 }
1245
1246 return 0;
1247}
1248
Namhyung Kimf15eb532012-10-05 14:02:16 +09001249static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001250{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001251 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001252 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001253 int err = -1, i;
1254 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001255 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001256
1257 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001258 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001259 goto out;
1260 }
1261
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001262 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1263 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001264 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001265 goto out_delete_evlist;
1266 }
1267
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001268 if (trace->sched &&
1269 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1270 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001271 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001272 goto out_delete_evlist;
1273 }
1274
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001275 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1276 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001277 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001278 goto out_delete_evlist;
1279 }
1280
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001281 err = trace__symbols_init(trace, evlist);
1282 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001283 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001284 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001285 }
1286
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001287 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001288
Namhyung Kimf15eb532012-10-05 14:02:16 +09001289 signal(SIGCHLD, sig_handler);
1290 signal(SIGINT, sig_handler);
1291
1292 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001293 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001294 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001295 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001296 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001297 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001298 }
1299 }
1300
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001301 err = perf_evlist__open(evlist);
1302 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001303 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001304 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001305 }
1306
1307 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1308 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001309 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001310 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001311 }
1312
1313 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001314
1315 if (forks)
1316 perf_evlist__start_workload(evlist);
1317
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001318 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001319again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001320 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001321
1322 for (i = 0; i < evlist->nr_mmaps; i++) {
1323 union perf_event *event;
1324
1325 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1326 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001327 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001328 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001329
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001330 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001331
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001332 err = perf_evlist__parse_sample(evlist, event, &sample);
1333 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001334 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001335 continue;
1336 }
1337
David Ahern4bb09192013-09-04 12:37:43 -06001338 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001339 trace->base_time = sample.time;
1340
1341 if (type != PERF_RECORD_SAMPLE) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001342 trace__process_event(trace, &trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001343 continue;
1344 }
1345
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001346 evsel = perf_evlist__id2evsel(evlist, sample.id);
1347 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001348 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001349 continue;
1350 }
1351
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001352 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001353 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 -03001354 perf_evsel__name(evsel), sample.tid,
1355 sample.cpu, sample.raw_size);
1356 continue;
1357 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001358
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001359 handler = evsel->handler.func;
1360 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001361
1362 if (done)
1363 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001364 }
1365 }
1366
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001367 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001368 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001369 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001370
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001371 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001372 }
1373
1374 if (done)
1375 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001376
1377 goto again;
1378
Namhyung Kim3beb0862013-03-15 14:48:50 +09001379out_unmap_evlist:
1380 perf_evlist__munmap(evlist);
1381out_close_evlist:
1382 perf_evlist__close(evlist);
1383out_delete_maps:
1384 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001385out_delete_evlist:
1386 perf_evlist__delete(evlist);
1387out:
1388 return err;
1389}
1390
David Ahern6810fc92013-08-28 22:29:52 -06001391static int trace__replay(struct trace *trace)
1392{
1393 const struct perf_evsel_str_handler handlers[] = {
1394 { "raw_syscalls:sys_enter", trace__sys_enter, },
1395 { "raw_syscalls:sys_exit", trace__sys_exit, },
1396 };
1397
1398 struct perf_session *session;
1399 int err = -1;
1400
1401 trace->tool.sample = trace__process_sample;
1402 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001403 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001404 trace->tool.comm = perf_event__process_comm;
1405 trace->tool.exit = perf_event__process_exit;
1406 trace->tool.fork = perf_event__process_fork;
1407 trace->tool.attr = perf_event__process_attr;
1408 trace->tool.tracing_data = perf_event__process_tracing_data;
1409 trace->tool.build_id = perf_event__process_build_id;
1410
1411 trace->tool.ordered_samples = true;
1412 trace->tool.ordering_requires_timestamps = true;
1413
1414 /* add tid to output */
1415 trace->multiple_threads = true;
1416
1417 if (symbol__init() < 0)
1418 return -1;
1419
1420 session = perf_session__new(input_name, O_RDONLY, 0, false,
1421 &trace->tool);
1422 if (session == NULL)
1423 return -ENOMEM;
1424
1425 err = perf_session__set_tracepoints_handlers(session, handlers);
1426 if (err)
1427 goto out;
1428
1429 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1430 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1431 goto out;
1432 }
1433
1434 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1435 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1436 goto out;
1437 }
1438
David Ahernbdc89662013-08-28 22:29:53 -06001439 err = parse_target_str(trace);
1440 if (err != 0)
1441 goto out;
1442
David Ahern6810fc92013-08-28 22:29:52 -06001443 setup_pager();
1444
1445 err = perf_session__process_events(session, &trace->tool);
1446 if (err)
1447 pr_err("Failed to process events, error %d", err);
1448
1449out:
1450 perf_session__delete(session);
1451
1452 return err;
1453}
1454
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001455static size_t trace__fprintf_threads_header(FILE *fp)
1456{
1457 size_t printed;
1458
1459 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1460 printed += fprintf(fp," __) Summary of events (__\n\n");
1461 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1462 printed += fprintf(fp," _____________________________________________________________________\n\n");
1463
1464 return printed;
1465}
1466
1467static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1468{
1469 size_t printed = trace__fprintf_threads_header(fp);
1470 struct rb_node *nd;
1471
1472 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1473 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1474 struct thread_trace *ttrace = thread->priv;
1475 const char *color;
1476 double ratio;
1477
1478 if (ttrace == NULL)
1479 continue;
1480
1481 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1482
1483 color = PERF_COLOR_NORMAL;
1484 if (ratio > 50.0)
1485 color = PERF_COLOR_RED;
1486 else if (ratio > 25.0)
1487 color = PERF_COLOR_GREEN;
1488 else if (ratio > 5.0)
1489 color = PERF_COLOR_YELLOW;
1490
1491 printed += color_fprintf(fp, color, "%20s", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001492 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001493 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1494 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1495 }
1496
1497 return printed;
1498}
1499
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001500static int trace__set_duration(const struct option *opt, const char *str,
1501 int unset __maybe_unused)
1502{
1503 struct trace *trace = opt->value;
1504
1505 trace->duration_filter = atof(str);
1506 return 0;
1507}
1508
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001509static int trace__open_output(struct trace *trace, const char *filename)
1510{
1511 struct stat st;
1512
1513 if (!stat(filename, &st) && st.st_size) {
1514 char oldname[PATH_MAX];
1515
1516 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1517 unlink(oldname);
1518 rename(filename, oldname);
1519 }
1520
1521 trace->output = fopen(filename, "w");
1522
1523 return trace->output == NULL ? -errno : 0;
1524}
1525
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001526int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1527{
1528 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001529 "perf trace [<options>] [<command>]",
1530 "perf trace [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001531 NULL
1532 };
1533 struct trace trace = {
1534 .audit_machine = audit_detect_machine(),
1535 .syscalls = {
1536 . max = -1,
1537 },
1538 .opts = {
1539 .target = {
1540 .uid = UINT_MAX,
1541 .uses_mmap = true,
1542 },
1543 .user_freq = UINT_MAX,
1544 .user_interval = ULLONG_MAX,
1545 .no_delay = true,
1546 .mmap_pages = 1024,
1547 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001548 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001549 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001550 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001551 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001552 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001553 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001554 OPT_BOOLEAN(0, "comm", &trace.show_comm,
1555 "show the thread COMM next to its id"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001556 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1557 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001558 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001559 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001560 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1561 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001562 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001563 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001564 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001565 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001566 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001567 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001568 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001569 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02001570 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1571 "number of mmap data pages",
1572 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06001573 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001574 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001575 OPT_CALLBACK(0, "duration", &trace, "float",
1576 "show only events with duration > N.M ms",
1577 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001578 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001579 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06001580 OPT_BOOLEAN('T', "time", &trace.full_time,
1581 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001582 OPT_END()
1583 };
1584 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001585 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001586
1587 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001588
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001589 if (output_name != NULL) {
1590 err = trace__open_output(&trace, output_name);
1591 if (err < 0) {
1592 perror("failed to create output file");
1593 goto out;
1594 }
1595 }
1596
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001597 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001598 const char *s = ev_qualifier_str;
1599
1600 trace.not_ev_qualifier = *s == '!';
1601 if (trace.not_ev_qualifier)
1602 ++s;
1603 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001604 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001605 fputs("Not enough memory to parse event qualifier",
1606 trace.output);
1607 err = -ENOMEM;
1608 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001609 }
1610 }
1611
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001612 err = perf_target__validate(&trace.opts.target);
1613 if (err) {
1614 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001615 fprintf(trace.output, "%s", bf);
1616 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001617 }
1618
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001619 err = perf_target__parse_uid(&trace.opts.target);
1620 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001621 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001622 fprintf(trace.output, "%s", bf);
1623 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001624 }
1625
Namhyung Kimf15eb532012-10-05 14:02:16 +09001626 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001627 trace.opts.target.system_wide = true;
1628
David Ahern6810fc92013-08-28 22:29:52 -06001629 if (input_name)
1630 err = trace__replay(&trace);
1631 else
1632 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001633
1634 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001635 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001636
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001637out_close:
1638 if (output_name != NULL)
1639 fclose(trace.output);
1640out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001641 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001642}