blob: 807e542da6237aff64122b8a371b50f2b010192b [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 Melo01533e92013-09-03 12:20:12 -0300192static 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 -0300193{
194 enum syscall_futex_args {
195 SCF_UADDR = (1 << 0),
196 SCF_OP = (1 << 1),
197 SCF_VAL = (1 << 2),
198 SCF_TIMEOUT = (1 << 3),
199 SCF_UADDR2 = (1 << 4),
200 SCF_VAL3 = (1 << 5),
201 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300202 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300203 int cmd = op & FUTEX_CMD_MASK;
204 size_t printed = 0;
205
206 switch (cmd) {
207#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300208 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
209 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
210 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
211 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
212 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
213 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300214 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300215 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
216 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
217 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
218 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
219 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300220 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
221 default: printed = scnprintf(bf, size, "%#x", cmd); break;
222 }
223
224 if (op & FUTEX_PRIVATE_FLAG)
225 printed += scnprintf(bf + printed, size - printed, "|PRIV");
226
227 if (op & FUTEX_CLOCK_REALTIME)
228 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
229
230 return printed;
231}
232
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300233#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
234
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300235static const char *epoll_ctl_ops[] = { [1] = "ADD", "DEL", "MOD", };
236static DEFINE_STRARRAY(epoll_ctl_ops);
237
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300238static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
239static DEFINE_STRARRAY(itimers);
240
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300241static const char *whences[] = { "SET", "CUR", "END",
242#ifdef SEEK_DATA
243"DATA",
244#endif
245#ifdef SEEK_HOLE
246"HOLE",
247#endif
248};
249static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300250
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300251static const char *fcntl_cmds[] = {
252 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
253 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
254 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
255 "F_GETOWNER_UIDS",
256};
257static DEFINE_STRARRAY(fcntl_cmds);
258
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300259static const char *rlimit_resources[] = {
260 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
261 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
262 "RTTIME",
263};
264static DEFINE_STRARRAY(rlimit_resources);
265
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300266static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
267static DEFINE_STRARRAY(sighow);
268
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300269static const char *socket_families[] = {
270 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
271 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
272 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
273 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
274 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
275 "ALG", "NFC", "VSOCK",
276};
277static DEFINE_STRARRAY(socket_families);
278
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300279#ifndef SOCK_TYPE_MASK
280#define SOCK_TYPE_MASK 0xf
281#endif
282
283static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
284 struct syscall_arg *arg)
285{
286 size_t printed;
287 int type = arg->val,
288 flags = type & ~SOCK_TYPE_MASK;
289
290 type &= SOCK_TYPE_MASK;
291 /*
292 * Can't use a strarray, MIPS may override for ABI reasons.
293 */
294 switch (type) {
295#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
296 P_SK_TYPE(STREAM);
297 P_SK_TYPE(DGRAM);
298 P_SK_TYPE(RAW);
299 P_SK_TYPE(RDM);
300 P_SK_TYPE(SEQPACKET);
301 P_SK_TYPE(DCCP);
302 P_SK_TYPE(PACKET);
303#undef P_SK_TYPE
304 default:
305 printed = scnprintf(bf, size, "%#x", type);
306 }
307
308#define P_SK_FLAG(n) \
309 if (flags & SOCK_##n) { \
310 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
311 flags &= ~SOCK_##n; \
312 }
313
314 P_SK_FLAG(CLOEXEC);
315 P_SK_FLAG(NONBLOCK);
316#undef P_SK_FLAG
317
318 if (flags)
319 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
320
321 return printed;
322}
323
324#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
325
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300326#ifndef MSG_PROBE
327#define MSG_PROBE 0x10
328#endif
329#ifndef MSG_SENDPAGE_NOTLAST
330#define MSG_SENDPAGE_NOTLAST 0x20000
331#endif
332#ifndef MSG_FASTOPEN
333#define MSG_FASTOPEN 0x20000000
334#endif
335
336static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
337 struct syscall_arg *arg)
338{
339 int printed = 0, flags = arg->val;
340
341 if (flags == 0)
342 return scnprintf(bf, size, "NONE");
343#define P_MSG_FLAG(n) \
344 if (flags & MSG_##n) { \
345 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
346 flags &= ~MSG_##n; \
347 }
348
349 P_MSG_FLAG(OOB);
350 P_MSG_FLAG(PEEK);
351 P_MSG_FLAG(DONTROUTE);
352 P_MSG_FLAG(TRYHARD);
353 P_MSG_FLAG(CTRUNC);
354 P_MSG_FLAG(PROBE);
355 P_MSG_FLAG(TRUNC);
356 P_MSG_FLAG(DONTWAIT);
357 P_MSG_FLAG(EOR);
358 P_MSG_FLAG(WAITALL);
359 P_MSG_FLAG(FIN);
360 P_MSG_FLAG(SYN);
361 P_MSG_FLAG(CONFIRM);
362 P_MSG_FLAG(RST);
363 P_MSG_FLAG(ERRQUEUE);
364 P_MSG_FLAG(NOSIGNAL);
365 P_MSG_FLAG(MORE);
366 P_MSG_FLAG(WAITFORONE);
367 P_MSG_FLAG(SENDPAGE_NOTLAST);
368 P_MSG_FLAG(FASTOPEN);
369 P_MSG_FLAG(CMSG_CLOEXEC);
370#undef P_MSG_FLAG
371
372 if (flags)
373 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
374
375 return printed;
376}
377
378#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
379
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300380static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
381 struct syscall_arg *arg)
382{
383 size_t printed = 0;
384 int mode = arg->val;
385
386 if (mode == F_OK) /* 0 */
387 return scnprintf(bf, size, "F");
388#define P_MODE(n) \
389 if (mode & n##_OK) { \
390 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
391 mode &= ~n##_OK; \
392 }
393
394 P_MODE(R);
395 P_MODE(W);
396 P_MODE(X);
397#undef P_MODE
398
399 if (mode)
400 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
401
402 return printed;
403}
404
405#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
406
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300407static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300408 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300409{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300410 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300411
412 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300413 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300414
415 if (flags == 0)
416 return scnprintf(bf, size, "RDONLY");
417#define P_FLAG(n) \
418 if (flags & O_##n) { \
419 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
420 flags &= ~O_##n; \
421 }
422
423 P_FLAG(APPEND);
424 P_FLAG(ASYNC);
425 P_FLAG(CLOEXEC);
426 P_FLAG(CREAT);
427 P_FLAG(DIRECT);
428 P_FLAG(DIRECTORY);
429 P_FLAG(EXCL);
430 P_FLAG(LARGEFILE);
431 P_FLAG(NOATIME);
432 P_FLAG(NOCTTY);
433#ifdef O_NONBLOCK
434 P_FLAG(NONBLOCK);
435#elif O_NDELAY
436 P_FLAG(NDELAY);
437#endif
438#ifdef O_PATH
439 P_FLAG(PATH);
440#endif
441 P_FLAG(RDWR);
442#ifdef O_DSYNC
443 if ((flags & O_SYNC) == O_SYNC)
444 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
445 else {
446 P_FLAG(DSYNC);
447 }
448#else
449 P_FLAG(SYNC);
450#endif
451 P_FLAG(TRUNC);
452 P_FLAG(WRONLY);
453#undef P_FLAG
454
455 if (flags)
456 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
457
458 return printed;
459}
460
461#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
462
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300463static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
464 struct syscall_arg *arg)
465{
466 int printed = 0, flags = arg->val;
467
468 if (flags == 0)
469 return scnprintf(bf, size, "NONE");
470#define P_FLAG(n) \
471 if (flags & EFD_##n) { \
472 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
473 flags &= ~EFD_##n; \
474 }
475
476 P_FLAG(SEMAPHORE);
477 P_FLAG(CLOEXEC);
478 P_FLAG(NONBLOCK);
479#undef P_FLAG
480
481 if (flags)
482 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
483
484 return printed;
485}
486
487#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
488
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300489static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
490{
491 int sig = arg->val;
492
493 switch (sig) {
494#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
495 P_SIGNUM(HUP);
496 P_SIGNUM(INT);
497 P_SIGNUM(QUIT);
498 P_SIGNUM(ILL);
499 P_SIGNUM(TRAP);
500 P_SIGNUM(ABRT);
501 P_SIGNUM(BUS);
502 P_SIGNUM(FPE);
503 P_SIGNUM(KILL);
504 P_SIGNUM(USR1);
505 P_SIGNUM(SEGV);
506 P_SIGNUM(USR2);
507 P_SIGNUM(PIPE);
508 P_SIGNUM(ALRM);
509 P_SIGNUM(TERM);
510 P_SIGNUM(STKFLT);
511 P_SIGNUM(CHLD);
512 P_SIGNUM(CONT);
513 P_SIGNUM(STOP);
514 P_SIGNUM(TSTP);
515 P_SIGNUM(TTIN);
516 P_SIGNUM(TTOU);
517 P_SIGNUM(URG);
518 P_SIGNUM(XCPU);
519 P_SIGNUM(XFSZ);
520 P_SIGNUM(VTALRM);
521 P_SIGNUM(PROF);
522 P_SIGNUM(WINCH);
523 P_SIGNUM(IO);
524 P_SIGNUM(PWR);
525 P_SIGNUM(SYS);
526 default: break;
527 }
528
529 return scnprintf(bf, size, "%#x", sig);
530}
531
532#define SCA_SIGNUM syscall_arg__scnprintf_signum
533
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300534static struct syscall_fmt {
535 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300536 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300537 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300538 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300539 bool errmsg;
540 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300541 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300542} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300543 { .name = "access", .errmsg = true,
544 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300545 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300546 { .name = "brk", .hexret = true,
547 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300548 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300549 { .name = "epoll_ctl", .errmsg = true,
550 .arg_scnprintf = { [1] = SCA_STRARRAY, /* op */ },
551 .arg_parm = { [1] = &strarray__epoll_ctl_ops, /* op */ }, },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300552 { .name = "eventfd2", .errmsg = true,
553 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300554 { .name = "fcntl", .errmsg = true,
555 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
556 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300557 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
558 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300559 { .name = "futex", .errmsg = true,
560 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300561 { .name = "getitimer", .errmsg = true,
562 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
563 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300564 { .name = "getrlimit", .errmsg = true,
565 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
566 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300567 { .name = "ioctl", .errmsg = true,
568 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300569 { .name = "kill", .errmsg = true,
570 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo579e7862013-09-02 15:37:32 -0300571 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300572 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
573 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300574 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300575 { .name = "madvise", .errmsg = true,
576 .arg_scnprintf = { [0] = SCA_HEX, /* start */
577 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300578 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300579 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300580 [2] = SCA_MMAP_PROT, /* prot */
581 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300582 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300583 .arg_scnprintf = { [0] = SCA_HEX, /* start */
584 [2] = SCA_MMAP_PROT, /* prot */ }, },
585 { .name = "mremap", .hexret = true,
586 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
587 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300588 { .name = "munmap", .errmsg = true,
589 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300590 { .name = "open", .errmsg = true,
591 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300592 { .name = "open_by_handle_at", .errmsg = true,
593 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
594 { .name = "openat", .errmsg = true,
595 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300596 { .name = "poll", .errmsg = true, .timeout = true, },
597 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300598 { .name = "pread", .errmsg = true, .alias = "pread64", },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300599 { .name = "prlimit64", .errmsg = true,
600 .arg_scnprintf = { [1] = SCA_STRARRAY, /* resource */ },
601 .arg_parm = { [1] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300602 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300603 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300604 { .name = "recvfrom", .errmsg = true,
605 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
606 { .name = "recvmmsg", .errmsg = true,
607 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
608 { .name = "recvmsg", .errmsg = true,
609 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300610 { .name = "rt_sigaction", .errmsg = true,
611 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300612 { .name = "rt_sigprocmask", .errmsg = true,
613 .arg_scnprintf = { [0] = SCA_STRARRAY, /* how */ },
614 .arg_parm = { [0] = &strarray__sighow, /* how */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300615 { .name = "rt_sigqueueinfo", .errmsg = true,
616 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
617 { .name = "rt_tgsigqueueinfo", .errmsg = true,
618 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300619 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300620 { .name = "sendmmsg", .errmsg = true,
621 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
622 { .name = "sendmsg", .errmsg = true,
623 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
624 { .name = "sendto", .errmsg = true,
625 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300626 { .name = "setitimer", .errmsg = true,
627 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
628 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300629 { .name = "setrlimit", .errmsg = true,
630 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
631 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300632 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300633 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
634 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300635 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300636 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300637 { .name = "tgkill", .errmsg = true,
638 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
639 { .name = "tkill", .errmsg = true,
640 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300641 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300642};
643
644static int syscall_fmt__cmp(const void *name, const void *fmtp)
645{
646 const struct syscall_fmt *fmt = fmtp;
647 return strcmp(name, fmt->name);
648}
649
650static struct syscall_fmt *syscall_fmt__find(const char *name)
651{
652 const int nmemb = ARRAY_SIZE(syscall_fmts);
653 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
654}
655
656struct syscall {
657 struct event_format *tp_format;
658 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300659 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300660 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300661 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300662 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300663};
664
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200665static size_t fprintf_duration(unsigned long t, FILE *fp)
666{
667 double duration = (double)t / NSEC_PER_MSEC;
668 size_t printed = fprintf(fp, "(");
669
670 if (duration >= 1.0)
671 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
672 else if (duration >= 0.01)
673 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
674 else
675 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300676 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200677}
678
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300679struct thread_trace {
680 u64 entry_time;
681 u64 exit_time;
682 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300683 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300684 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300685 double runtime_ms;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300686};
687
688static struct thread_trace *thread_trace__new(void)
689{
690 return zalloc(sizeof(struct thread_trace));
691}
692
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300693static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300694{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300695 struct thread_trace *ttrace;
696
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300697 if (thread == NULL)
698 goto fail;
699
700 if (thread->priv == NULL)
701 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300702
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300703 if (thread->priv == NULL)
704 goto fail;
705
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300706 ttrace = thread->priv;
707 ++ttrace->nr_events;
708
709 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300710fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300711 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300712 "WARNING: not enough memory, dropping samples!\n");
713 return NULL;
714}
715
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300716struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300717 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300718 int audit_machine;
719 struct {
720 int max;
721 struct syscall *table;
722 } syscalls;
723 struct perf_record_opts opts;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300724 struct machine host;
725 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600726 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300727 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300728 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300729 struct strlist *ev_qualifier;
730 bool not_ev_qualifier;
David Ahernbdc89662013-08-28 22:29:53 -0600731 struct intlist *tid_list;
732 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300733 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300734 bool multiple_threads;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300735 bool show_comm;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300736 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300737 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300738};
739
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300740static bool trace__filter_duration(struct trace *trace, double t)
741{
742 return t < (trace->duration_filter * NSEC_PER_MSEC);
743}
744
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300745static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
746{
747 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
748
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200749 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300750}
751
Namhyung Kimf15eb532012-10-05 14:02:16 +0900752static bool done = false;
753
754static void sig_handler(int sig __maybe_unused)
755{
756 done = true;
757}
758
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300759static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200760 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300761{
762 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200763 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300764
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300765 if (trace->multiple_threads) {
766 if (trace->show_comm)
767 printed += fprintf(fp, "%.14s/", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +0300768 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300769 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300770
771 return printed;
772}
773
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300774static int trace__process_event(struct trace *trace, struct machine *machine,
775 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300776{
777 int ret = 0;
778
779 switch (event->header.type) {
780 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300781 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300782 "LOST %" PRIu64 " events!\n", event->lost.lost);
783 ret = machine__process_lost_event(machine, event);
784 default:
785 ret = machine__process_event(machine, event);
786 break;
787 }
788
789 return ret;
790}
791
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300792static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300793 union perf_event *event,
794 struct perf_sample *sample __maybe_unused,
795 struct machine *machine)
796{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300797 struct trace *trace = container_of(tool, struct trace, tool);
798 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300799}
800
801static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
802{
803 int err = symbol__init();
804
805 if (err)
806 return err;
807
808 machine__init(&trace->host, "", HOST_KERNEL_ID);
809 machine__create_kernel_maps(&trace->host);
810
811 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300812 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300813 trace__tool_process,
814 &trace->host);
815 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300816 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300817 &trace->host);
818 }
819
820 if (err)
821 symbol__exit();
822
823 return err;
824}
825
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300826static int syscall__set_arg_fmts(struct syscall *sc)
827{
828 struct format_field *field;
829 int idx = 0;
830
831 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
832 if (sc->arg_scnprintf == NULL)
833 return -1;
834
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300835 if (sc->fmt)
836 sc->arg_parm = sc->fmt->arg_parm;
837
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300838 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300839 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
840 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
841 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300842 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
843 ++idx;
844 }
845
846 return 0;
847}
848
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300849static int trace__read_syscall_info(struct trace *trace, int id)
850{
851 char tp_name[128];
852 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300853 const char *name = audit_syscall_to_name(id, trace->audit_machine);
854
855 if (name == NULL)
856 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300857
858 if (id > trace->syscalls.max) {
859 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
860
861 if (nsyscalls == NULL)
862 return -1;
863
864 if (trace->syscalls.max != -1) {
865 memset(nsyscalls + trace->syscalls.max + 1, 0,
866 (id - trace->syscalls.max) * sizeof(*sc));
867 } else {
868 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
869 }
870
871 trace->syscalls.table = nsyscalls;
872 trace->syscalls.max = id;
873 }
874
875 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300876 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300877
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300878 if (trace->ev_qualifier) {
879 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
880
881 if (!(in ^ trace->not_ev_qualifier)) {
882 sc->filtered = true;
883 /*
884 * No need to do read tracepoint information since this will be
885 * filtered out.
886 */
887 return 0;
888 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300889 }
890
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300891 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300892
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300893 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
894 sc->tp_format = event_format__new("syscalls", tp_name);
895
896 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
897 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
898 sc->tp_format = event_format__new("syscalls", tp_name);
899 }
900
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300901 if (sc->tp_format == NULL)
902 return -1;
903
904 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300905}
906
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300907static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
908 unsigned long *args)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300909{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300910 size_t printed = 0;
911
912 if (sc->tp_format != NULL) {
913 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300914 u8 bit = 1;
915 struct syscall_arg arg = {
916 .idx = 0,
917 .mask = 0,
918 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300919
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300920 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300921 field = field->next, ++arg.idx, bit <<= 1) {
922 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300923 continue;
924
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -0300925 if (args[arg.idx] == 0)
926 continue;
927
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300928 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300929 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300930 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
931 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300932 if (sc->arg_parm)
933 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300934 printed += sc->arg_scnprintf[arg.idx](bf + printed,
935 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300936 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300937 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300938 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300939 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300940 }
941 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300942 int i = 0;
943
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300944 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300945 printed += scnprintf(bf + printed, size - printed,
946 "%sarg%d: %ld",
947 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300948 ++i;
949 }
950 }
951
952 return printed;
953}
954
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300955typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
956 struct perf_sample *sample);
957
958static struct syscall *trace__syscall_info(struct trace *trace,
959 struct perf_evsel *evsel,
960 struct perf_sample *sample)
961{
962 int id = perf_evsel__intval(evsel, sample, "id");
963
964 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -0300965
966 /*
967 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
968 * before that, leaving at a higher verbosity level till that is
969 * explained. Reproduced with plain ftrace with:
970 *
971 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
972 * grep "NR -1 " /t/trace_pipe
973 *
974 * After generating some load on the machine.
975 */
976 if (verbose > 1) {
977 static u64 n;
978 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
979 id, perf_evsel__name(evsel), ++n);
980 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300981 return NULL;
982 }
983
984 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
985 trace__read_syscall_info(trace, id))
986 goto out_cant_read;
987
988 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
989 goto out_cant_read;
990
991 return &trace->syscalls.table[id];
992
993out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -0300994 if (verbose) {
995 fprintf(trace->output, "Problems reading syscall %d", id);
996 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
997 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
998 fputs(" information\n", trace->output);
999 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001000 return NULL;
1001}
1002
1003static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1004 struct perf_sample *sample)
1005{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001006 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001007 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001008 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001009 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001010 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001011 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001012
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001013 if (sc == NULL)
1014 return -1;
1015
1016 if (sc->filtered)
1017 return 0;
1018
Adrian Hunter314add62013-08-27 11:23:03 +03001019 thread = machine__findnew_thread(&trace->host, sample->pid,
1020 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001021 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001022 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001023 return -1;
1024
1025 args = perf_evsel__rawptr(evsel, sample, "args");
1026 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001027 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001028 return -1;
1029 }
1030
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001031 ttrace = thread->priv;
1032
1033 if (ttrace->entry_str == NULL) {
1034 ttrace->entry_str = malloc(1024);
1035 if (!ttrace->entry_str)
1036 return -1;
1037 }
1038
1039 ttrace->entry_time = sample->time;
1040 msg = ttrace->entry_str;
1041 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1042
1043 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
1044
1045 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001046 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001047 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1048 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001049 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001050 } else
1051 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001052
1053 return 0;
1054}
1055
1056static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1057 struct perf_sample *sample)
1058{
1059 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001060 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001061 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001062 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001063 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001064
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001065 if (sc == NULL)
1066 return -1;
1067
1068 if (sc->filtered)
1069 return 0;
1070
Adrian Hunter314add62013-08-27 11:23:03 +03001071 thread = machine__findnew_thread(&trace->host, sample->pid,
1072 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001073 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001074 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001075 return -1;
1076
1077 ret = perf_evsel__intval(evsel, sample, "ret");
1078
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001079 ttrace = thread->priv;
1080
1081 ttrace->exit_time = sample->time;
1082
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001083 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001084 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001085 if (trace__filter_duration(trace, duration))
1086 goto out;
1087 } else if (trace->duration_filter)
1088 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001089
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001090 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001091
1092 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001093 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001094 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001095 fprintf(trace->output, " ... [");
1096 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1097 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001098 }
1099
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001100 if (sc->fmt == NULL) {
1101signed_print:
1102 fprintf(trace->output, ") = %d", ret);
1103 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001104 char bf[256];
1105 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1106 *e = audit_errno_to_name(-ret);
1107
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001108 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001109 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001110 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001111 else if (sc->fmt->hexret)
1112 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001113 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001114 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001115
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001116 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001117out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001118 ttrace->entry_pending = false;
1119
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001120 return 0;
1121}
1122
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001123static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1124 struct perf_sample *sample)
1125{
1126 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1127 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
Adrian Hunter314add62013-08-27 11:23:03 +03001128 struct thread *thread = machine__findnew_thread(&trace->host,
1129 sample->pid,
1130 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001131 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001132
1133 if (ttrace == NULL)
1134 goto out_dump;
1135
1136 ttrace->runtime_ms += runtime_ms;
1137 trace->runtime_ms += runtime_ms;
1138 return 0;
1139
1140out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001141 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001142 evsel->name,
1143 perf_evsel__strval(evsel, sample, "comm"),
1144 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1145 runtime,
1146 perf_evsel__intval(evsel, sample, "vruntime"));
1147 return 0;
1148}
1149
David Ahernbdc89662013-08-28 22:29:53 -06001150static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1151{
1152 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1153 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1154 return false;
1155
1156 if (trace->pid_list || trace->tid_list)
1157 return true;
1158
1159 return false;
1160}
1161
David Ahern6810fc92013-08-28 22:29:52 -06001162static int trace__process_sample(struct perf_tool *tool,
1163 union perf_event *event __maybe_unused,
1164 struct perf_sample *sample,
1165 struct perf_evsel *evsel,
1166 struct machine *machine __maybe_unused)
1167{
1168 struct trace *trace = container_of(tool, struct trace, tool);
1169 int err = 0;
1170
1171 tracepoint_handler handler = evsel->handler.func;
1172
David Ahernbdc89662013-08-28 22:29:53 -06001173 if (skip_sample(trace, sample))
1174 return 0;
1175
David Ahern4bb09192013-09-04 12:37:43 -06001176 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001177 trace->base_time = sample->time;
1178
1179 if (handler)
1180 handler(trace, evsel, sample);
1181
1182 return err;
1183}
1184
1185static bool
1186perf_session__has_tp(struct perf_session *session, const char *name)
1187{
1188 struct perf_evsel *evsel;
1189
1190 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1191
1192 return evsel != NULL;
1193}
1194
David Ahernbdc89662013-08-28 22:29:53 -06001195static int parse_target_str(struct trace *trace)
1196{
1197 if (trace->opts.target.pid) {
1198 trace->pid_list = intlist__new(trace->opts.target.pid);
1199 if (trace->pid_list == NULL) {
1200 pr_err("Error parsing process id string\n");
1201 return -EINVAL;
1202 }
1203 }
1204
1205 if (trace->opts.target.tid) {
1206 trace->tid_list = intlist__new(trace->opts.target.tid);
1207 if (trace->tid_list == NULL) {
1208 pr_err("Error parsing thread id string\n");
1209 return -EINVAL;
1210 }
1211 }
1212
1213 return 0;
1214}
1215
Namhyung Kimf15eb532012-10-05 14:02:16 +09001216static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001217{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001218 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001219 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001220 int err = -1, i;
1221 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001222 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001223
1224 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001225 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001226 goto out;
1227 }
1228
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001229 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1230 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001231 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001232 goto out_delete_evlist;
1233 }
1234
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001235 if (trace->sched &&
1236 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1237 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001238 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001239 goto out_delete_evlist;
1240 }
1241
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001242 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1243 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001244 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001245 goto out_delete_evlist;
1246 }
1247
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001248 err = trace__symbols_init(trace, evlist);
1249 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001250 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001251 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001252 }
1253
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001254 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001255
Namhyung Kimf15eb532012-10-05 14:02:16 +09001256 signal(SIGCHLD, sig_handler);
1257 signal(SIGINT, sig_handler);
1258
1259 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001260 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001261 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001262 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001263 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001264 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001265 }
1266 }
1267
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001268 err = perf_evlist__open(evlist);
1269 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001270 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001271 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001272 }
1273
1274 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1275 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001276 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001277 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001278 }
1279
1280 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001281
1282 if (forks)
1283 perf_evlist__start_workload(evlist);
1284
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001285 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001286again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001287 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001288
1289 for (i = 0; i < evlist->nr_mmaps; i++) {
1290 union perf_event *event;
1291
1292 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1293 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001294 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001295 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001296
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001297 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001298
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001299 err = perf_evlist__parse_sample(evlist, event, &sample);
1300 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001301 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001302 continue;
1303 }
1304
David Ahern4bb09192013-09-04 12:37:43 -06001305 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001306 trace->base_time = sample.time;
1307
1308 if (type != PERF_RECORD_SAMPLE) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001309 trace__process_event(trace, &trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001310 continue;
1311 }
1312
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001313 evsel = perf_evlist__id2evsel(evlist, sample.id);
1314 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001315 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001316 continue;
1317 }
1318
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001319 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001320 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 -03001321 perf_evsel__name(evsel), sample.tid,
1322 sample.cpu, sample.raw_size);
1323 continue;
1324 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001325
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001326 handler = evsel->handler.func;
1327 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001328
1329 if (done)
1330 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001331 }
1332 }
1333
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001334 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001335 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001336 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001337
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001338 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001339 }
1340
1341 if (done)
1342 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001343
1344 goto again;
1345
Namhyung Kim3beb0862013-03-15 14:48:50 +09001346out_unmap_evlist:
1347 perf_evlist__munmap(evlist);
1348out_close_evlist:
1349 perf_evlist__close(evlist);
1350out_delete_maps:
1351 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001352out_delete_evlist:
1353 perf_evlist__delete(evlist);
1354out:
1355 return err;
1356}
1357
David Ahern6810fc92013-08-28 22:29:52 -06001358static int trace__replay(struct trace *trace)
1359{
1360 const struct perf_evsel_str_handler handlers[] = {
1361 { "raw_syscalls:sys_enter", trace__sys_enter, },
1362 { "raw_syscalls:sys_exit", trace__sys_exit, },
1363 };
1364
1365 struct perf_session *session;
1366 int err = -1;
1367
1368 trace->tool.sample = trace__process_sample;
1369 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001370 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001371 trace->tool.comm = perf_event__process_comm;
1372 trace->tool.exit = perf_event__process_exit;
1373 trace->tool.fork = perf_event__process_fork;
1374 trace->tool.attr = perf_event__process_attr;
1375 trace->tool.tracing_data = perf_event__process_tracing_data;
1376 trace->tool.build_id = perf_event__process_build_id;
1377
1378 trace->tool.ordered_samples = true;
1379 trace->tool.ordering_requires_timestamps = true;
1380
1381 /* add tid to output */
1382 trace->multiple_threads = true;
1383
1384 if (symbol__init() < 0)
1385 return -1;
1386
1387 session = perf_session__new(input_name, O_RDONLY, 0, false,
1388 &trace->tool);
1389 if (session == NULL)
1390 return -ENOMEM;
1391
1392 err = perf_session__set_tracepoints_handlers(session, handlers);
1393 if (err)
1394 goto out;
1395
1396 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1397 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1398 goto out;
1399 }
1400
1401 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1402 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1403 goto out;
1404 }
1405
David Ahernbdc89662013-08-28 22:29:53 -06001406 err = parse_target_str(trace);
1407 if (err != 0)
1408 goto out;
1409
David Ahern6810fc92013-08-28 22:29:52 -06001410 setup_pager();
1411
1412 err = perf_session__process_events(session, &trace->tool);
1413 if (err)
1414 pr_err("Failed to process events, error %d", err);
1415
1416out:
1417 perf_session__delete(session);
1418
1419 return err;
1420}
1421
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001422static size_t trace__fprintf_threads_header(FILE *fp)
1423{
1424 size_t printed;
1425
1426 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1427 printed += fprintf(fp," __) Summary of events (__\n\n");
1428 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1429 printed += fprintf(fp," _____________________________________________________________________\n\n");
1430
1431 return printed;
1432}
1433
1434static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1435{
1436 size_t printed = trace__fprintf_threads_header(fp);
1437 struct rb_node *nd;
1438
1439 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1440 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1441 struct thread_trace *ttrace = thread->priv;
1442 const char *color;
1443 double ratio;
1444
1445 if (ttrace == NULL)
1446 continue;
1447
1448 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1449
1450 color = PERF_COLOR_NORMAL;
1451 if (ratio > 50.0)
1452 color = PERF_COLOR_RED;
1453 else if (ratio > 25.0)
1454 color = PERF_COLOR_GREEN;
1455 else if (ratio > 5.0)
1456 color = PERF_COLOR_YELLOW;
1457
1458 printed += color_fprintf(fp, color, "%20s", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001459 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001460 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1461 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1462 }
1463
1464 return printed;
1465}
1466
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001467static int trace__set_duration(const struct option *opt, const char *str,
1468 int unset __maybe_unused)
1469{
1470 struct trace *trace = opt->value;
1471
1472 trace->duration_filter = atof(str);
1473 return 0;
1474}
1475
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001476static int trace__open_output(struct trace *trace, const char *filename)
1477{
1478 struct stat st;
1479
1480 if (!stat(filename, &st) && st.st_size) {
1481 char oldname[PATH_MAX];
1482
1483 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1484 unlink(oldname);
1485 rename(filename, oldname);
1486 }
1487
1488 trace->output = fopen(filename, "w");
1489
1490 return trace->output == NULL ? -errno : 0;
1491}
1492
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001493int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1494{
1495 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001496 "perf trace [<options>] [<command>]",
1497 "perf trace [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001498 NULL
1499 };
1500 struct trace trace = {
1501 .audit_machine = audit_detect_machine(),
1502 .syscalls = {
1503 . max = -1,
1504 },
1505 .opts = {
1506 .target = {
1507 .uid = UINT_MAX,
1508 .uses_mmap = true,
1509 },
1510 .user_freq = UINT_MAX,
1511 .user_interval = ULLONG_MAX,
1512 .no_delay = true,
1513 .mmap_pages = 1024,
1514 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001515 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001516 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001517 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001518 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001519 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001520 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001521 OPT_BOOLEAN(0, "comm", &trace.show_comm,
1522 "show the thread COMM next to its id"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001523 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1524 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001525 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001526 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001527 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1528 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001529 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001530 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001531 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001532 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001533 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001534 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001535 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001536 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02001537 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1538 "number of mmap data pages",
1539 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06001540 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001541 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001542 OPT_CALLBACK(0, "duration", &trace, "float",
1543 "show only events with duration > N.M ms",
1544 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001545 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001546 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06001547 OPT_BOOLEAN('T', "time", &trace.full_time,
1548 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001549 OPT_END()
1550 };
1551 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001552 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001553
1554 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001555
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001556 if (output_name != NULL) {
1557 err = trace__open_output(&trace, output_name);
1558 if (err < 0) {
1559 perror("failed to create output file");
1560 goto out;
1561 }
1562 }
1563
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001564 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001565 const char *s = ev_qualifier_str;
1566
1567 trace.not_ev_qualifier = *s == '!';
1568 if (trace.not_ev_qualifier)
1569 ++s;
1570 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001571 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001572 fputs("Not enough memory to parse event qualifier",
1573 trace.output);
1574 err = -ENOMEM;
1575 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001576 }
1577 }
1578
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001579 err = perf_target__validate(&trace.opts.target);
1580 if (err) {
1581 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001582 fprintf(trace.output, "%s", bf);
1583 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001584 }
1585
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001586 err = perf_target__parse_uid(&trace.opts.target);
1587 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001588 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001589 fprintf(trace.output, "%s", bf);
1590 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001591 }
1592
Namhyung Kimf15eb532012-10-05 14:02:16 +09001593 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001594 trace.opts.target.system_wide = true;
1595
David Ahern6810fc92013-08-28 22:29:52 -06001596 if (input_name)
1597 err = trace__replay(&trace);
1598 else
1599 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001600
1601 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001602 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001603
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001604out_close:
1605 if (output_name != NULL)
1606 fclose(trace.output);
1607out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001608 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001609}