blob: 8855207deae886a80655929c002fdae648f5e7f9 [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 Meloaec19302012-09-27 13:16:00 -0300655 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300656 { .name = "tgkill", .errmsg = true,
657 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
658 { .name = "tkill", .errmsg = true,
659 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300660 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300661};
662
663static int syscall_fmt__cmp(const void *name, const void *fmtp)
664{
665 const struct syscall_fmt *fmt = fmtp;
666 return strcmp(name, fmt->name);
667}
668
669static struct syscall_fmt *syscall_fmt__find(const char *name)
670{
671 const int nmemb = ARRAY_SIZE(syscall_fmts);
672 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
673}
674
675struct syscall {
676 struct event_format *tp_format;
677 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300678 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300679 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300680 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300681 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300682};
683
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200684static size_t fprintf_duration(unsigned long t, FILE *fp)
685{
686 double duration = (double)t / NSEC_PER_MSEC;
687 size_t printed = fprintf(fp, "(");
688
689 if (duration >= 1.0)
690 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
691 else if (duration >= 0.01)
692 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
693 else
694 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300695 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200696}
697
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300698struct thread_trace {
699 u64 entry_time;
700 u64 exit_time;
701 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300702 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300703 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300704 double runtime_ms;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300705};
706
707static struct thread_trace *thread_trace__new(void)
708{
709 return zalloc(sizeof(struct thread_trace));
710}
711
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300712static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300713{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300714 struct thread_trace *ttrace;
715
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300716 if (thread == NULL)
717 goto fail;
718
719 if (thread->priv == NULL)
720 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300721
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300722 if (thread->priv == NULL)
723 goto fail;
724
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300725 ttrace = thread->priv;
726 ++ttrace->nr_events;
727
728 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300729fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300730 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300731 "WARNING: not enough memory, dropping samples!\n");
732 return NULL;
733}
734
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300735struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300736 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300737 int audit_machine;
738 struct {
739 int max;
740 struct syscall *table;
741 } syscalls;
742 struct perf_record_opts opts;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300743 struct machine host;
744 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600745 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300746 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300747 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300748 struct strlist *ev_qualifier;
749 bool not_ev_qualifier;
David Ahernbdc89662013-08-28 22:29:53 -0600750 struct intlist *tid_list;
751 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300752 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300753 bool multiple_threads;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300754 bool show_comm;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300755 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300756 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300757};
758
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300759static bool trace__filter_duration(struct trace *trace, double t)
760{
761 return t < (trace->duration_filter * NSEC_PER_MSEC);
762}
763
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300764static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
765{
766 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
767
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200768 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300769}
770
Namhyung Kimf15eb532012-10-05 14:02:16 +0900771static bool done = false;
772
773static void sig_handler(int sig __maybe_unused)
774{
775 done = true;
776}
777
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300778static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200779 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300780{
781 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200782 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300783
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300784 if (trace->multiple_threads) {
785 if (trace->show_comm)
786 printed += fprintf(fp, "%.14s/", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +0300787 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300788 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300789
790 return printed;
791}
792
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300793static int trace__process_event(struct trace *trace, struct machine *machine,
794 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300795{
796 int ret = 0;
797
798 switch (event->header.type) {
799 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300800 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300801 "LOST %" PRIu64 " events!\n", event->lost.lost);
802 ret = machine__process_lost_event(machine, event);
803 default:
804 ret = machine__process_event(machine, event);
805 break;
806 }
807
808 return ret;
809}
810
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300811static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300812 union perf_event *event,
813 struct perf_sample *sample __maybe_unused,
814 struct machine *machine)
815{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300816 struct trace *trace = container_of(tool, struct trace, tool);
817 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300818}
819
820static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
821{
822 int err = symbol__init();
823
824 if (err)
825 return err;
826
827 machine__init(&trace->host, "", HOST_KERNEL_ID);
828 machine__create_kernel_maps(&trace->host);
829
830 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300831 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300832 trace__tool_process,
833 &trace->host);
834 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300835 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300836 &trace->host);
837 }
838
839 if (err)
840 symbol__exit();
841
842 return err;
843}
844
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300845static int syscall__set_arg_fmts(struct syscall *sc)
846{
847 struct format_field *field;
848 int idx = 0;
849
850 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
851 if (sc->arg_scnprintf == NULL)
852 return -1;
853
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300854 if (sc->fmt)
855 sc->arg_parm = sc->fmt->arg_parm;
856
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300857 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300858 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
859 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
860 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300861 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
862 ++idx;
863 }
864
865 return 0;
866}
867
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300868static int trace__read_syscall_info(struct trace *trace, int id)
869{
870 char tp_name[128];
871 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300872 const char *name = audit_syscall_to_name(id, trace->audit_machine);
873
874 if (name == NULL)
875 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300876
877 if (id > trace->syscalls.max) {
878 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
879
880 if (nsyscalls == NULL)
881 return -1;
882
883 if (trace->syscalls.max != -1) {
884 memset(nsyscalls + trace->syscalls.max + 1, 0,
885 (id - trace->syscalls.max) * sizeof(*sc));
886 } else {
887 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
888 }
889
890 trace->syscalls.table = nsyscalls;
891 trace->syscalls.max = id;
892 }
893
894 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300895 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300896
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300897 if (trace->ev_qualifier) {
898 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
899
900 if (!(in ^ trace->not_ev_qualifier)) {
901 sc->filtered = true;
902 /*
903 * No need to do read tracepoint information since this will be
904 * filtered out.
905 */
906 return 0;
907 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300908 }
909
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300910 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300911
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300912 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
913 sc->tp_format = event_format__new("syscalls", tp_name);
914
915 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
916 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
917 sc->tp_format = event_format__new("syscalls", tp_name);
918 }
919
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300920 if (sc->tp_format == NULL)
921 return -1;
922
923 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300924}
925
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300926static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
927 unsigned long *args)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300928{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300929 size_t printed = 0;
930
931 if (sc->tp_format != NULL) {
932 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300933 u8 bit = 1;
934 struct syscall_arg arg = {
935 .idx = 0,
936 .mask = 0,
937 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300938
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300939 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300940 field = field->next, ++arg.idx, bit <<= 1) {
941 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300942 continue;
943
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -0300944 if (args[arg.idx] == 0)
945 continue;
946
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300947 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300948 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300949 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
950 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300951 if (sc->arg_parm)
952 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300953 printed += sc->arg_scnprintf[arg.idx](bf + printed,
954 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300955 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300956 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300957 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300958 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300959 }
960 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300961 int i = 0;
962
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300963 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300964 printed += scnprintf(bf + printed, size - printed,
965 "%sarg%d: %ld",
966 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300967 ++i;
968 }
969 }
970
971 return printed;
972}
973
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300974typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
975 struct perf_sample *sample);
976
977static struct syscall *trace__syscall_info(struct trace *trace,
978 struct perf_evsel *evsel,
979 struct perf_sample *sample)
980{
981 int id = perf_evsel__intval(evsel, sample, "id");
982
983 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -0300984
985 /*
986 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
987 * before that, leaving at a higher verbosity level till that is
988 * explained. Reproduced with plain ftrace with:
989 *
990 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
991 * grep "NR -1 " /t/trace_pipe
992 *
993 * After generating some load on the machine.
994 */
995 if (verbose > 1) {
996 static u64 n;
997 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
998 id, perf_evsel__name(evsel), ++n);
999 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001000 return NULL;
1001 }
1002
1003 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1004 trace__read_syscall_info(trace, id))
1005 goto out_cant_read;
1006
1007 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1008 goto out_cant_read;
1009
1010 return &trace->syscalls.table[id];
1011
1012out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001013 if (verbose) {
1014 fprintf(trace->output, "Problems reading syscall %d", id);
1015 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1016 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1017 fputs(" information\n", trace->output);
1018 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001019 return NULL;
1020}
1021
1022static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1023 struct perf_sample *sample)
1024{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001025 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001026 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001027 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001028 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001029 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001030 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001031
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001032 if (sc == NULL)
1033 return -1;
1034
1035 if (sc->filtered)
1036 return 0;
1037
Adrian Hunter314add62013-08-27 11:23:03 +03001038 thread = machine__findnew_thread(&trace->host, sample->pid,
1039 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001040 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001041 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001042 return -1;
1043
1044 args = perf_evsel__rawptr(evsel, sample, "args");
1045 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001046 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001047 return -1;
1048 }
1049
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001050 ttrace = thread->priv;
1051
1052 if (ttrace->entry_str == NULL) {
1053 ttrace->entry_str = malloc(1024);
1054 if (!ttrace->entry_str)
1055 return -1;
1056 }
1057
1058 ttrace->entry_time = sample->time;
1059 msg = ttrace->entry_str;
1060 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1061
1062 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
1063
1064 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001065 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001066 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1067 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001068 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001069 } else
1070 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001071
1072 return 0;
1073}
1074
1075static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1076 struct perf_sample *sample)
1077{
1078 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001079 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001080 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001081 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001082 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001083
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001084 if (sc == NULL)
1085 return -1;
1086
1087 if (sc->filtered)
1088 return 0;
1089
Adrian Hunter314add62013-08-27 11:23:03 +03001090 thread = machine__findnew_thread(&trace->host, sample->pid,
1091 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001092 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001093 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001094 return -1;
1095
1096 ret = perf_evsel__intval(evsel, sample, "ret");
1097
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001098 ttrace = thread->priv;
1099
1100 ttrace->exit_time = sample->time;
1101
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001102 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001103 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001104 if (trace__filter_duration(trace, duration))
1105 goto out;
1106 } else if (trace->duration_filter)
1107 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001108
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001109 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001110
1111 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001112 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001113 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001114 fprintf(trace->output, " ... [");
1115 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1116 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001117 }
1118
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001119 if (sc->fmt == NULL) {
1120signed_print:
1121 fprintf(trace->output, ") = %d", ret);
1122 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001123 char bf[256];
1124 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1125 *e = audit_errno_to_name(-ret);
1126
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001127 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001128 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001129 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001130 else if (sc->fmt->hexret)
1131 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001132 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001133 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001134
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001135 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001136out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001137 ttrace->entry_pending = false;
1138
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001139 return 0;
1140}
1141
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001142static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1143 struct perf_sample *sample)
1144{
1145 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1146 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
Adrian Hunter314add62013-08-27 11:23:03 +03001147 struct thread *thread = machine__findnew_thread(&trace->host,
1148 sample->pid,
1149 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001150 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001151
1152 if (ttrace == NULL)
1153 goto out_dump;
1154
1155 ttrace->runtime_ms += runtime_ms;
1156 trace->runtime_ms += runtime_ms;
1157 return 0;
1158
1159out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001160 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001161 evsel->name,
1162 perf_evsel__strval(evsel, sample, "comm"),
1163 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1164 runtime,
1165 perf_evsel__intval(evsel, sample, "vruntime"));
1166 return 0;
1167}
1168
David Ahernbdc89662013-08-28 22:29:53 -06001169static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1170{
1171 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1172 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1173 return false;
1174
1175 if (trace->pid_list || trace->tid_list)
1176 return true;
1177
1178 return false;
1179}
1180
David Ahern6810fc92013-08-28 22:29:52 -06001181static int trace__process_sample(struct perf_tool *tool,
1182 union perf_event *event __maybe_unused,
1183 struct perf_sample *sample,
1184 struct perf_evsel *evsel,
1185 struct machine *machine __maybe_unused)
1186{
1187 struct trace *trace = container_of(tool, struct trace, tool);
1188 int err = 0;
1189
1190 tracepoint_handler handler = evsel->handler.func;
1191
David Ahernbdc89662013-08-28 22:29:53 -06001192 if (skip_sample(trace, sample))
1193 return 0;
1194
David Ahern4bb09192013-09-04 12:37:43 -06001195 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001196 trace->base_time = sample->time;
1197
1198 if (handler)
1199 handler(trace, evsel, sample);
1200
1201 return err;
1202}
1203
1204static bool
1205perf_session__has_tp(struct perf_session *session, const char *name)
1206{
1207 struct perf_evsel *evsel;
1208
1209 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1210
1211 return evsel != NULL;
1212}
1213
David Ahernbdc89662013-08-28 22:29:53 -06001214static int parse_target_str(struct trace *trace)
1215{
1216 if (trace->opts.target.pid) {
1217 trace->pid_list = intlist__new(trace->opts.target.pid);
1218 if (trace->pid_list == NULL) {
1219 pr_err("Error parsing process id string\n");
1220 return -EINVAL;
1221 }
1222 }
1223
1224 if (trace->opts.target.tid) {
1225 trace->tid_list = intlist__new(trace->opts.target.tid);
1226 if (trace->tid_list == NULL) {
1227 pr_err("Error parsing thread id string\n");
1228 return -EINVAL;
1229 }
1230 }
1231
1232 return 0;
1233}
1234
Namhyung Kimf15eb532012-10-05 14:02:16 +09001235static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001236{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001237 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001238 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001239 int err = -1, i;
1240 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001241 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001242
1243 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001244 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001245 goto out;
1246 }
1247
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001248 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1249 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001250 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001251 goto out_delete_evlist;
1252 }
1253
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001254 if (trace->sched &&
1255 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1256 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001257 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001258 goto out_delete_evlist;
1259 }
1260
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001261 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1262 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001263 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001264 goto out_delete_evlist;
1265 }
1266
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001267 err = trace__symbols_init(trace, evlist);
1268 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001269 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001270 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001271 }
1272
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001273 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001274
Namhyung Kimf15eb532012-10-05 14:02:16 +09001275 signal(SIGCHLD, sig_handler);
1276 signal(SIGINT, sig_handler);
1277
1278 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001279 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001280 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001281 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001282 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001283 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001284 }
1285 }
1286
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001287 err = perf_evlist__open(evlist);
1288 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001289 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001290 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001291 }
1292
1293 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1294 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001295 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001296 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001297 }
1298
1299 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001300
1301 if (forks)
1302 perf_evlist__start_workload(evlist);
1303
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001304 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001305again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001306 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001307
1308 for (i = 0; i < evlist->nr_mmaps; i++) {
1309 union perf_event *event;
1310
1311 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1312 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001313 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001314 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001315
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001316 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001317
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001318 err = perf_evlist__parse_sample(evlist, event, &sample);
1319 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001320 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001321 continue;
1322 }
1323
David Ahern4bb09192013-09-04 12:37:43 -06001324 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001325 trace->base_time = sample.time;
1326
1327 if (type != PERF_RECORD_SAMPLE) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001328 trace__process_event(trace, &trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001329 continue;
1330 }
1331
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001332 evsel = perf_evlist__id2evsel(evlist, sample.id);
1333 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001334 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001335 continue;
1336 }
1337
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001338 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001339 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 -03001340 perf_evsel__name(evsel), sample.tid,
1341 sample.cpu, sample.raw_size);
1342 continue;
1343 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001344
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001345 handler = evsel->handler.func;
1346 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001347
1348 if (done)
1349 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001350 }
1351 }
1352
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001353 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001354 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001355 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001356
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001357 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001358 }
1359
1360 if (done)
1361 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001362
1363 goto again;
1364
Namhyung Kim3beb0862013-03-15 14:48:50 +09001365out_unmap_evlist:
1366 perf_evlist__munmap(evlist);
1367out_close_evlist:
1368 perf_evlist__close(evlist);
1369out_delete_maps:
1370 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001371out_delete_evlist:
1372 perf_evlist__delete(evlist);
1373out:
1374 return err;
1375}
1376
David Ahern6810fc92013-08-28 22:29:52 -06001377static int trace__replay(struct trace *trace)
1378{
1379 const struct perf_evsel_str_handler handlers[] = {
1380 { "raw_syscalls:sys_enter", trace__sys_enter, },
1381 { "raw_syscalls:sys_exit", trace__sys_exit, },
1382 };
1383
1384 struct perf_session *session;
1385 int err = -1;
1386
1387 trace->tool.sample = trace__process_sample;
1388 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001389 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001390 trace->tool.comm = perf_event__process_comm;
1391 trace->tool.exit = perf_event__process_exit;
1392 trace->tool.fork = perf_event__process_fork;
1393 trace->tool.attr = perf_event__process_attr;
1394 trace->tool.tracing_data = perf_event__process_tracing_data;
1395 trace->tool.build_id = perf_event__process_build_id;
1396
1397 trace->tool.ordered_samples = true;
1398 trace->tool.ordering_requires_timestamps = true;
1399
1400 /* add tid to output */
1401 trace->multiple_threads = true;
1402
1403 if (symbol__init() < 0)
1404 return -1;
1405
1406 session = perf_session__new(input_name, O_RDONLY, 0, false,
1407 &trace->tool);
1408 if (session == NULL)
1409 return -ENOMEM;
1410
1411 err = perf_session__set_tracepoints_handlers(session, handlers);
1412 if (err)
1413 goto out;
1414
1415 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1416 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1417 goto out;
1418 }
1419
1420 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1421 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1422 goto out;
1423 }
1424
David Ahernbdc89662013-08-28 22:29:53 -06001425 err = parse_target_str(trace);
1426 if (err != 0)
1427 goto out;
1428
David Ahern6810fc92013-08-28 22:29:52 -06001429 setup_pager();
1430
1431 err = perf_session__process_events(session, &trace->tool);
1432 if (err)
1433 pr_err("Failed to process events, error %d", err);
1434
1435out:
1436 perf_session__delete(session);
1437
1438 return err;
1439}
1440
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001441static size_t trace__fprintf_threads_header(FILE *fp)
1442{
1443 size_t printed;
1444
1445 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1446 printed += fprintf(fp," __) Summary of events (__\n\n");
1447 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1448 printed += fprintf(fp," _____________________________________________________________________\n\n");
1449
1450 return printed;
1451}
1452
1453static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1454{
1455 size_t printed = trace__fprintf_threads_header(fp);
1456 struct rb_node *nd;
1457
1458 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1459 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1460 struct thread_trace *ttrace = thread->priv;
1461 const char *color;
1462 double ratio;
1463
1464 if (ttrace == NULL)
1465 continue;
1466
1467 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1468
1469 color = PERF_COLOR_NORMAL;
1470 if (ratio > 50.0)
1471 color = PERF_COLOR_RED;
1472 else if (ratio > 25.0)
1473 color = PERF_COLOR_GREEN;
1474 else if (ratio > 5.0)
1475 color = PERF_COLOR_YELLOW;
1476
1477 printed += color_fprintf(fp, color, "%20s", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001478 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001479 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1480 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1481 }
1482
1483 return printed;
1484}
1485
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001486static int trace__set_duration(const struct option *opt, const char *str,
1487 int unset __maybe_unused)
1488{
1489 struct trace *trace = opt->value;
1490
1491 trace->duration_filter = atof(str);
1492 return 0;
1493}
1494
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001495static int trace__open_output(struct trace *trace, const char *filename)
1496{
1497 struct stat st;
1498
1499 if (!stat(filename, &st) && st.st_size) {
1500 char oldname[PATH_MAX];
1501
1502 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1503 unlink(oldname);
1504 rename(filename, oldname);
1505 }
1506
1507 trace->output = fopen(filename, "w");
1508
1509 return trace->output == NULL ? -errno : 0;
1510}
1511
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001512int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1513{
1514 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001515 "perf trace [<options>] [<command>]",
1516 "perf trace [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001517 NULL
1518 };
1519 struct trace trace = {
1520 .audit_machine = audit_detect_machine(),
1521 .syscalls = {
1522 . max = -1,
1523 },
1524 .opts = {
1525 .target = {
1526 .uid = UINT_MAX,
1527 .uses_mmap = true,
1528 },
1529 .user_freq = UINT_MAX,
1530 .user_interval = ULLONG_MAX,
1531 .no_delay = true,
1532 .mmap_pages = 1024,
1533 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001534 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001535 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001536 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001537 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001538 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001539 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001540 OPT_BOOLEAN(0, "comm", &trace.show_comm,
1541 "show the thread COMM next to its id"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001542 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1543 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001544 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001545 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001546 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1547 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001548 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001549 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001550 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001551 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001552 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001553 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001554 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001555 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02001556 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1557 "number of mmap data pages",
1558 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06001559 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001560 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001561 OPT_CALLBACK(0, "duration", &trace, "float",
1562 "show only events with duration > N.M ms",
1563 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001564 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001565 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06001566 OPT_BOOLEAN('T', "time", &trace.full_time,
1567 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001568 OPT_END()
1569 };
1570 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001571 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001572
1573 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001574
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001575 if (output_name != NULL) {
1576 err = trace__open_output(&trace, output_name);
1577 if (err < 0) {
1578 perror("failed to create output file");
1579 goto out;
1580 }
1581 }
1582
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001583 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001584 const char *s = ev_qualifier_str;
1585
1586 trace.not_ev_qualifier = *s == '!';
1587 if (trace.not_ev_qualifier)
1588 ++s;
1589 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001590 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001591 fputs("Not enough memory to parse event qualifier",
1592 trace.output);
1593 err = -ENOMEM;
1594 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001595 }
1596 }
1597
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001598 err = perf_target__validate(&trace.opts.target);
1599 if (err) {
1600 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001601 fprintf(trace.output, "%s", bf);
1602 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001603 }
1604
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001605 err = perf_target__parse_uid(&trace.opts.target);
1606 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001607 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001608 fprintf(trace.output, "%s", bf);
1609 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001610 }
1611
Namhyung Kimf15eb532012-10-05 14:02:16 +09001612 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001613 trace.opts.target.system_wide = true;
1614
David Ahern6810fc92013-08-28 22:29:52 -06001615 if (input_name)
1616 err = trace__replay(&trace);
1617 else
1618 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001619
1620 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001621 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001622
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001623out_close:
1624 if (output_name != NULL)
1625 fclose(trace.output);
1626out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001627 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001628}