blob: 8a09ba3dcd97dd5c6619e5ac31166e1335811fd4 [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 Melo1f115cb2013-09-03 15:50:28 -0300235static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
236static DEFINE_STRARRAY(itimers);
237
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300238static const char *whences[] = { "SET", "CUR", "END",
239#ifdef SEEK_DATA
240"DATA",
241#endif
242#ifdef SEEK_HOLE
243"HOLE",
244#endif
245};
246static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300247
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300248static const char *fcntl_cmds[] = {
249 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
250 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
251 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
252 "F_GETOWNER_UIDS",
253};
254static DEFINE_STRARRAY(fcntl_cmds);
255
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300256static const char *rlimit_resources[] = {
257 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
258 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
259 "RTTIME",
260};
261static DEFINE_STRARRAY(rlimit_resources);
262
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300263static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
264static DEFINE_STRARRAY(sighow);
265
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300266static const char *socket_families[] = {
267 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
268 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
269 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
270 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
271 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
272 "ALG", "NFC", "VSOCK",
273};
274static DEFINE_STRARRAY(socket_families);
275
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300276#ifndef SOCK_TYPE_MASK
277#define SOCK_TYPE_MASK 0xf
278#endif
279
280static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
281 struct syscall_arg *arg)
282{
283 size_t printed;
284 int type = arg->val,
285 flags = type & ~SOCK_TYPE_MASK;
286
287 type &= SOCK_TYPE_MASK;
288 /*
289 * Can't use a strarray, MIPS may override for ABI reasons.
290 */
291 switch (type) {
292#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
293 P_SK_TYPE(STREAM);
294 P_SK_TYPE(DGRAM);
295 P_SK_TYPE(RAW);
296 P_SK_TYPE(RDM);
297 P_SK_TYPE(SEQPACKET);
298 P_SK_TYPE(DCCP);
299 P_SK_TYPE(PACKET);
300#undef P_SK_TYPE
301 default:
302 printed = scnprintf(bf, size, "%#x", type);
303 }
304
305#define P_SK_FLAG(n) \
306 if (flags & SOCK_##n) { \
307 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
308 flags &= ~SOCK_##n; \
309 }
310
311 P_SK_FLAG(CLOEXEC);
312 P_SK_FLAG(NONBLOCK);
313#undef P_SK_FLAG
314
315 if (flags)
316 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
317
318 return printed;
319}
320
321#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
322
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300323#ifndef MSG_PROBE
324#define MSG_PROBE 0x10
325#endif
326#ifndef MSG_SENDPAGE_NOTLAST
327#define MSG_SENDPAGE_NOTLAST 0x20000
328#endif
329#ifndef MSG_FASTOPEN
330#define MSG_FASTOPEN 0x20000000
331#endif
332
333static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
334 struct syscall_arg *arg)
335{
336 int printed = 0, flags = arg->val;
337
338 if (flags == 0)
339 return scnprintf(bf, size, "NONE");
340#define P_MSG_FLAG(n) \
341 if (flags & MSG_##n) { \
342 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
343 flags &= ~MSG_##n; \
344 }
345
346 P_MSG_FLAG(OOB);
347 P_MSG_FLAG(PEEK);
348 P_MSG_FLAG(DONTROUTE);
349 P_MSG_FLAG(TRYHARD);
350 P_MSG_FLAG(CTRUNC);
351 P_MSG_FLAG(PROBE);
352 P_MSG_FLAG(TRUNC);
353 P_MSG_FLAG(DONTWAIT);
354 P_MSG_FLAG(EOR);
355 P_MSG_FLAG(WAITALL);
356 P_MSG_FLAG(FIN);
357 P_MSG_FLAG(SYN);
358 P_MSG_FLAG(CONFIRM);
359 P_MSG_FLAG(RST);
360 P_MSG_FLAG(ERRQUEUE);
361 P_MSG_FLAG(NOSIGNAL);
362 P_MSG_FLAG(MORE);
363 P_MSG_FLAG(WAITFORONE);
364 P_MSG_FLAG(SENDPAGE_NOTLAST);
365 P_MSG_FLAG(FASTOPEN);
366 P_MSG_FLAG(CMSG_CLOEXEC);
367#undef P_MSG_FLAG
368
369 if (flags)
370 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
371
372 return printed;
373}
374
375#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
376
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300377static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
378 struct syscall_arg *arg)
379{
380 size_t printed = 0;
381 int mode = arg->val;
382
383 if (mode == F_OK) /* 0 */
384 return scnprintf(bf, size, "F");
385#define P_MODE(n) \
386 if (mode & n##_OK) { \
387 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
388 mode &= ~n##_OK; \
389 }
390
391 P_MODE(R);
392 P_MODE(W);
393 P_MODE(X);
394#undef P_MODE
395
396 if (mode)
397 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
398
399 return printed;
400}
401
402#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
403
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300404static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300405 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300406{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300407 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300408
409 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300410 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300411
412 if (flags == 0)
413 return scnprintf(bf, size, "RDONLY");
414#define P_FLAG(n) \
415 if (flags & O_##n) { \
416 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
417 flags &= ~O_##n; \
418 }
419
420 P_FLAG(APPEND);
421 P_FLAG(ASYNC);
422 P_FLAG(CLOEXEC);
423 P_FLAG(CREAT);
424 P_FLAG(DIRECT);
425 P_FLAG(DIRECTORY);
426 P_FLAG(EXCL);
427 P_FLAG(LARGEFILE);
428 P_FLAG(NOATIME);
429 P_FLAG(NOCTTY);
430#ifdef O_NONBLOCK
431 P_FLAG(NONBLOCK);
432#elif O_NDELAY
433 P_FLAG(NDELAY);
434#endif
435#ifdef O_PATH
436 P_FLAG(PATH);
437#endif
438 P_FLAG(RDWR);
439#ifdef O_DSYNC
440 if ((flags & O_SYNC) == O_SYNC)
441 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
442 else {
443 P_FLAG(DSYNC);
444 }
445#else
446 P_FLAG(SYNC);
447#endif
448 P_FLAG(TRUNC);
449 P_FLAG(WRONLY);
450#undef P_FLAG
451
452 if (flags)
453 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
454
455 return printed;
456}
457
458#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
459
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300460static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
461 struct syscall_arg *arg)
462{
463 int printed = 0, flags = arg->val;
464
465 if (flags == 0)
466 return scnprintf(bf, size, "NONE");
467#define P_FLAG(n) \
468 if (flags & EFD_##n) { \
469 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
470 flags &= ~EFD_##n; \
471 }
472
473 P_FLAG(SEMAPHORE);
474 P_FLAG(CLOEXEC);
475 P_FLAG(NONBLOCK);
476#undef P_FLAG
477
478 if (flags)
479 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
480
481 return printed;
482}
483
484#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
485
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300486static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
487{
488 int sig = arg->val;
489
490 switch (sig) {
491#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
492 P_SIGNUM(HUP);
493 P_SIGNUM(INT);
494 P_SIGNUM(QUIT);
495 P_SIGNUM(ILL);
496 P_SIGNUM(TRAP);
497 P_SIGNUM(ABRT);
498 P_SIGNUM(BUS);
499 P_SIGNUM(FPE);
500 P_SIGNUM(KILL);
501 P_SIGNUM(USR1);
502 P_SIGNUM(SEGV);
503 P_SIGNUM(USR2);
504 P_SIGNUM(PIPE);
505 P_SIGNUM(ALRM);
506 P_SIGNUM(TERM);
507 P_SIGNUM(STKFLT);
508 P_SIGNUM(CHLD);
509 P_SIGNUM(CONT);
510 P_SIGNUM(STOP);
511 P_SIGNUM(TSTP);
512 P_SIGNUM(TTIN);
513 P_SIGNUM(TTOU);
514 P_SIGNUM(URG);
515 P_SIGNUM(XCPU);
516 P_SIGNUM(XFSZ);
517 P_SIGNUM(VTALRM);
518 P_SIGNUM(PROF);
519 P_SIGNUM(WINCH);
520 P_SIGNUM(IO);
521 P_SIGNUM(PWR);
522 P_SIGNUM(SYS);
523 default: break;
524 }
525
526 return scnprintf(bf, size, "%#x", sig);
527}
528
529#define SCA_SIGNUM syscall_arg__scnprintf_signum
530
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300531static struct syscall_fmt {
532 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300533 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300534 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300535 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300536 bool errmsg;
537 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300538 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300539} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300540 { .name = "access", .errmsg = true,
541 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300542 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300543 { .name = "brk", .hexret = true,
544 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300545 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300546 { .name = "eventfd2", .errmsg = true,
547 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300548 { .name = "fcntl", .errmsg = true,
549 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
550 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300551 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
552 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300553 { .name = "futex", .errmsg = true,
554 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300555 { .name = "getitimer", .errmsg = true,
556 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
557 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300558 { .name = "getrlimit", .errmsg = true,
559 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
560 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300561 { .name = "ioctl", .errmsg = true,
562 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300563 { .name = "kill", .errmsg = true,
564 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo579e7862013-09-02 15:37:32 -0300565 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300566 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
567 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300568 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300569 { .name = "madvise", .errmsg = true,
570 .arg_scnprintf = { [0] = SCA_HEX, /* start */
571 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300572 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300573 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300574 [2] = SCA_MMAP_PROT, /* prot */
575 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300576 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300577 .arg_scnprintf = { [0] = SCA_HEX, /* start */
578 [2] = SCA_MMAP_PROT, /* prot */ }, },
579 { .name = "mremap", .hexret = true,
580 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
581 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300582 { .name = "munmap", .errmsg = true,
583 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300584 { .name = "open", .errmsg = true,
585 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300586 { .name = "open_by_handle_at", .errmsg = true,
587 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
588 { .name = "openat", .errmsg = true,
589 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300590 { .name = "poll", .errmsg = true, .timeout = true, },
591 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300592 { .name = "pread", .errmsg = true, .alias = "pread64", },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300593 { .name = "prlimit64", .errmsg = true,
594 .arg_scnprintf = { [1] = SCA_STRARRAY, /* resource */ },
595 .arg_parm = { [1] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300596 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300597 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300598 { .name = "recvfrom", .errmsg = true,
599 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
600 { .name = "recvmmsg", .errmsg = true,
601 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
602 { .name = "recvmsg", .errmsg = true,
603 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300604 { .name = "rt_sigaction", .errmsg = true,
605 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300606 { .name = "rt_sigprocmask", .errmsg = true,
607 .arg_scnprintf = { [0] = SCA_STRARRAY, /* how */ },
608 .arg_parm = { [0] = &strarray__sighow, /* how */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300609 { .name = "rt_sigqueueinfo", .errmsg = true,
610 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
611 { .name = "rt_tgsigqueueinfo", .errmsg = true,
612 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300613 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300614 { .name = "sendmmsg", .errmsg = true,
615 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
616 { .name = "sendmsg", .errmsg = true,
617 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
618 { .name = "sendto", .errmsg = true,
619 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300620 { .name = "setitimer", .errmsg = true,
621 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
622 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300623 { .name = "setrlimit", .errmsg = true,
624 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
625 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300626 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300627 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
628 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300629 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300630 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300631 { .name = "tgkill", .errmsg = true,
632 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
633 { .name = "tkill", .errmsg = true,
634 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300635 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300636};
637
638static int syscall_fmt__cmp(const void *name, const void *fmtp)
639{
640 const struct syscall_fmt *fmt = fmtp;
641 return strcmp(name, fmt->name);
642}
643
644static struct syscall_fmt *syscall_fmt__find(const char *name)
645{
646 const int nmemb = ARRAY_SIZE(syscall_fmts);
647 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
648}
649
650struct syscall {
651 struct event_format *tp_format;
652 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300653 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300654 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300655 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300656 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300657};
658
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200659static size_t fprintf_duration(unsigned long t, FILE *fp)
660{
661 double duration = (double)t / NSEC_PER_MSEC;
662 size_t printed = fprintf(fp, "(");
663
664 if (duration >= 1.0)
665 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
666 else if (duration >= 0.01)
667 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
668 else
669 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300670 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200671}
672
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300673struct thread_trace {
674 u64 entry_time;
675 u64 exit_time;
676 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300677 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300678 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300679 double runtime_ms;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300680};
681
682static struct thread_trace *thread_trace__new(void)
683{
684 return zalloc(sizeof(struct thread_trace));
685}
686
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300687static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300688{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300689 struct thread_trace *ttrace;
690
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300691 if (thread == NULL)
692 goto fail;
693
694 if (thread->priv == NULL)
695 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300696
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300697 if (thread->priv == NULL)
698 goto fail;
699
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300700 ttrace = thread->priv;
701 ++ttrace->nr_events;
702
703 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300704fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300705 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300706 "WARNING: not enough memory, dropping samples!\n");
707 return NULL;
708}
709
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300710struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300711 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300712 int audit_machine;
713 struct {
714 int max;
715 struct syscall *table;
716 } syscalls;
717 struct perf_record_opts opts;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300718 struct machine host;
719 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600720 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300721 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300722 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300723 struct strlist *ev_qualifier;
724 bool not_ev_qualifier;
David Ahernbdc89662013-08-28 22:29:53 -0600725 struct intlist *tid_list;
726 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300727 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300728 bool multiple_threads;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300729 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300730 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300731};
732
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300733static bool trace__filter_duration(struct trace *trace, double t)
734{
735 return t < (trace->duration_filter * NSEC_PER_MSEC);
736}
737
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300738static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
739{
740 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
741
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200742 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300743}
744
Namhyung Kimf15eb532012-10-05 14:02:16 +0900745static bool done = false;
746
747static void sig_handler(int sig __maybe_unused)
748{
749 done = true;
750}
751
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300752static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200753 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300754{
755 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200756 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300757
758 if (trace->multiple_threads)
Adrian Hunter38051232013-07-04 16:20:31 +0300759 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300760
761 return printed;
762}
763
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300764static int trace__process_event(struct trace *trace, struct machine *machine,
765 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300766{
767 int ret = 0;
768
769 switch (event->header.type) {
770 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300771 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300772 "LOST %" PRIu64 " events!\n", event->lost.lost);
773 ret = machine__process_lost_event(machine, event);
774 default:
775 ret = machine__process_event(machine, event);
776 break;
777 }
778
779 return ret;
780}
781
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300782static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300783 union perf_event *event,
784 struct perf_sample *sample __maybe_unused,
785 struct machine *machine)
786{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300787 struct trace *trace = container_of(tool, struct trace, tool);
788 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300789}
790
791static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
792{
793 int err = symbol__init();
794
795 if (err)
796 return err;
797
798 machine__init(&trace->host, "", HOST_KERNEL_ID);
799 machine__create_kernel_maps(&trace->host);
800
801 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300802 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300803 trace__tool_process,
804 &trace->host);
805 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300806 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300807 &trace->host);
808 }
809
810 if (err)
811 symbol__exit();
812
813 return err;
814}
815
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300816static int syscall__set_arg_fmts(struct syscall *sc)
817{
818 struct format_field *field;
819 int idx = 0;
820
821 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
822 if (sc->arg_scnprintf == NULL)
823 return -1;
824
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300825 if (sc->fmt)
826 sc->arg_parm = sc->fmt->arg_parm;
827
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300828 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300829 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
830 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
831 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300832 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
833 ++idx;
834 }
835
836 return 0;
837}
838
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300839static int trace__read_syscall_info(struct trace *trace, int id)
840{
841 char tp_name[128];
842 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300843 const char *name = audit_syscall_to_name(id, trace->audit_machine);
844
845 if (name == NULL)
846 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300847
848 if (id > trace->syscalls.max) {
849 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
850
851 if (nsyscalls == NULL)
852 return -1;
853
854 if (trace->syscalls.max != -1) {
855 memset(nsyscalls + trace->syscalls.max + 1, 0,
856 (id - trace->syscalls.max) * sizeof(*sc));
857 } else {
858 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
859 }
860
861 trace->syscalls.table = nsyscalls;
862 trace->syscalls.max = id;
863 }
864
865 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300866 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300867
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300868 if (trace->ev_qualifier) {
869 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
870
871 if (!(in ^ trace->not_ev_qualifier)) {
872 sc->filtered = true;
873 /*
874 * No need to do read tracepoint information since this will be
875 * filtered out.
876 */
877 return 0;
878 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300879 }
880
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300881 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300882
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300883 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
884 sc->tp_format = event_format__new("syscalls", tp_name);
885
886 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
887 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
888 sc->tp_format = event_format__new("syscalls", tp_name);
889 }
890
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300891 if (sc->tp_format == NULL)
892 return -1;
893
894 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300895}
896
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300897static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
898 unsigned long *args)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300899{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300900 size_t printed = 0;
901
902 if (sc->tp_format != NULL) {
903 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300904 u8 bit = 1;
905 struct syscall_arg arg = {
906 .idx = 0,
907 .mask = 0,
908 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300909
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300910 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300911 field = field->next, ++arg.idx, bit <<= 1) {
912 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300913 continue;
914
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -0300915 if (args[arg.idx] == 0)
916 continue;
917
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300918 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300919 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300920 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
921 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300922 if (sc->arg_parm)
923 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300924 printed += sc->arg_scnprintf[arg.idx](bf + printed,
925 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300926 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300927 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300928 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300929 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300930 }
931 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300932 int i = 0;
933
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300934 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300935 printed += scnprintf(bf + printed, size - printed,
936 "%sarg%d: %ld",
937 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300938 ++i;
939 }
940 }
941
942 return printed;
943}
944
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300945typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
946 struct perf_sample *sample);
947
948static struct syscall *trace__syscall_info(struct trace *trace,
949 struct perf_evsel *evsel,
950 struct perf_sample *sample)
951{
952 int id = perf_evsel__intval(evsel, sample, "id");
953
954 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -0300955
956 /*
957 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
958 * before that, leaving at a higher verbosity level till that is
959 * explained. Reproduced with plain ftrace with:
960 *
961 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
962 * grep "NR -1 " /t/trace_pipe
963 *
964 * After generating some load on the machine.
965 */
966 if (verbose > 1) {
967 static u64 n;
968 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
969 id, perf_evsel__name(evsel), ++n);
970 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300971 return NULL;
972 }
973
974 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
975 trace__read_syscall_info(trace, id))
976 goto out_cant_read;
977
978 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
979 goto out_cant_read;
980
981 return &trace->syscalls.table[id];
982
983out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -0300984 if (verbose) {
985 fprintf(trace->output, "Problems reading syscall %d", id);
986 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
987 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
988 fputs(" information\n", trace->output);
989 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300990 return NULL;
991}
992
993static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
994 struct perf_sample *sample)
995{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300996 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300997 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300998 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300999 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001000 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001001 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001002
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001003 if (sc == NULL)
1004 return -1;
1005
1006 if (sc->filtered)
1007 return 0;
1008
Adrian Hunter314add62013-08-27 11:23:03 +03001009 thread = machine__findnew_thread(&trace->host, sample->pid,
1010 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001011 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001012 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001013 return -1;
1014
1015 args = perf_evsel__rawptr(evsel, sample, "args");
1016 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001017 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001018 return -1;
1019 }
1020
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001021 ttrace = thread->priv;
1022
1023 if (ttrace->entry_str == NULL) {
1024 ttrace->entry_str = malloc(1024);
1025 if (!ttrace->entry_str)
1026 return -1;
1027 }
1028
1029 ttrace->entry_time = sample->time;
1030 msg = ttrace->entry_str;
1031 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1032
1033 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
1034
1035 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001036 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001037 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1038 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001039 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001040 } else
1041 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001042
1043 return 0;
1044}
1045
1046static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1047 struct perf_sample *sample)
1048{
1049 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001050 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001051 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001052 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001053 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001054
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001055 if (sc == NULL)
1056 return -1;
1057
1058 if (sc->filtered)
1059 return 0;
1060
Adrian Hunter314add62013-08-27 11:23:03 +03001061 thread = machine__findnew_thread(&trace->host, sample->pid,
1062 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001063 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001064 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001065 return -1;
1066
1067 ret = perf_evsel__intval(evsel, sample, "ret");
1068
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001069 ttrace = thread->priv;
1070
1071 ttrace->exit_time = sample->time;
1072
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001073 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001074 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001075 if (trace__filter_duration(trace, duration))
1076 goto out;
1077 } else if (trace->duration_filter)
1078 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001079
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001080 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001081
1082 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001083 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001084 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001085 fprintf(trace->output, " ... [");
1086 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1087 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001088 }
1089
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001090 if (sc->fmt == NULL) {
1091signed_print:
1092 fprintf(trace->output, ") = %d", ret);
1093 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001094 char bf[256];
1095 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1096 *e = audit_errno_to_name(-ret);
1097
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001098 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001099 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001100 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001101 else if (sc->fmt->hexret)
1102 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001103 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001104 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001105
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001106 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001107out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001108 ttrace->entry_pending = false;
1109
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001110 return 0;
1111}
1112
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001113static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1114 struct perf_sample *sample)
1115{
1116 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1117 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
Adrian Hunter314add62013-08-27 11:23:03 +03001118 struct thread *thread = machine__findnew_thread(&trace->host,
1119 sample->pid,
1120 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001121 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001122
1123 if (ttrace == NULL)
1124 goto out_dump;
1125
1126 ttrace->runtime_ms += runtime_ms;
1127 trace->runtime_ms += runtime_ms;
1128 return 0;
1129
1130out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001131 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001132 evsel->name,
1133 perf_evsel__strval(evsel, sample, "comm"),
1134 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1135 runtime,
1136 perf_evsel__intval(evsel, sample, "vruntime"));
1137 return 0;
1138}
1139
David Ahernbdc89662013-08-28 22:29:53 -06001140static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1141{
1142 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1143 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1144 return false;
1145
1146 if (trace->pid_list || trace->tid_list)
1147 return true;
1148
1149 return false;
1150}
1151
David Ahern6810fc92013-08-28 22:29:52 -06001152static int trace__process_sample(struct perf_tool *tool,
1153 union perf_event *event __maybe_unused,
1154 struct perf_sample *sample,
1155 struct perf_evsel *evsel,
1156 struct machine *machine __maybe_unused)
1157{
1158 struct trace *trace = container_of(tool, struct trace, tool);
1159 int err = 0;
1160
1161 tracepoint_handler handler = evsel->handler.func;
1162
David Ahernbdc89662013-08-28 22:29:53 -06001163 if (skip_sample(trace, sample))
1164 return 0;
1165
David Ahern4bb09192013-09-04 12:37:43 -06001166 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001167 trace->base_time = sample->time;
1168
1169 if (handler)
1170 handler(trace, evsel, sample);
1171
1172 return err;
1173}
1174
1175static bool
1176perf_session__has_tp(struct perf_session *session, const char *name)
1177{
1178 struct perf_evsel *evsel;
1179
1180 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1181
1182 return evsel != NULL;
1183}
1184
David Ahernbdc89662013-08-28 22:29:53 -06001185static int parse_target_str(struct trace *trace)
1186{
1187 if (trace->opts.target.pid) {
1188 trace->pid_list = intlist__new(trace->opts.target.pid);
1189 if (trace->pid_list == NULL) {
1190 pr_err("Error parsing process id string\n");
1191 return -EINVAL;
1192 }
1193 }
1194
1195 if (trace->opts.target.tid) {
1196 trace->tid_list = intlist__new(trace->opts.target.tid);
1197 if (trace->tid_list == NULL) {
1198 pr_err("Error parsing thread id string\n");
1199 return -EINVAL;
1200 }
1201 }
1202
1203 return 0;
1204}
1205
Namhyung Kimf15eb532012-10-05 14:02:16 +09001206static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001207{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001208 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001209 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001210 int err = -1, i;
1211 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001212 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001213
1214 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001215 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001216 goto out;
1217 }
1218
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001219 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1220 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001221 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001222 goto out_delete_evlist;
1223 }
1224
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001225 if (trace->sched &&
1226 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1227 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001228 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001229 goto out_delete_evlist;
1230 }
1231
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001232 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1233 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001234 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001235 goto out_delete_evlist;
1236 }
1237
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001238 err = trace__symbols_init(trace, evlist);
1239 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001240 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001241 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001242 }
1243
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001244 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001245
Namhyung Kimf15eb532012-10-05 14:02:16 +09001246 signal(SIGCHLD, sig_handler);
1247 signal(SIGINT, sig_handler);
1248
1249 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001250 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001251 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001252 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001253 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001254 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001255 }
1256 }
1257
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001258 err = perf_evlist__open(evlist);
1259 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001260 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001261 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001262 }
1263
1264 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1265 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001266 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001267 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001268 }
1269
1270 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001271
1272 if (forks)
1273 perf_evlist__start_workload(evlist);
1274
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001275 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001276again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001277 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001278
1279 for (i = 0; i < evlist->nr_mmaps; i++) {
1280 union perf_event *event;
1281
1282 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1283 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001284 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001285 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001286
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001287 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001288
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001289 err = perf_evlist__parse_sample(evlist, event, &sample);
1290 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001291 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001292 continue;
1293 }
1294
David Ahern4bb09192013-09-04 12:37:43 -06001295 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001296 trace->base_time = sample.time;
1297
1298 if (type != PERF_RECORD_SAMPLE) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001299 trace__process_event(trace, &trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001300 continue;
1301 }
1302
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001303 evsel = perf_evlist__id2evsel(evlist, sample.id);
1304 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001305 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001306 continue;
1307 }
1308
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001309 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001310 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 -03001311 perf_evsel__name(evsel), sample.tid,
1312 sample.cpu, sample.raw_size);
1313 continue;
1314 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001315
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001316 handler = evsel->handler.func;
1317 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001318
1319 if (done)
1320 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001321 }
1322 }
1323
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001324 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001325 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001326 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001327
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001328 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001329 }
1330
1331 if (done)
1332 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001333
1334 goto again;
1335
Namhyung Kim3beb0862013-03-15 14:48:50 +09001336out_unmap_evlist:
1337 perf_evlist__munmap(evlist);
1338out_close_evlist:
1339 perf_evlist__close(evlist);
1340out_delete_maps:
1341 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001342out_delete_evlist:
1343 perf_evlist__delete(evlist);
1344out:
1345 return err;
1346}
1347
David Ahern6810fc92013-08-28 22:29:52 -06001348static int trace__replay(struct trace *trace)
1349{
1350 const struct perf_evsel_str_handler handlers[] = {
1351 { "raw_syscalls:sys_enter", trace__sys_enter, },
1352 { "raw_syscalls:sys_exit", trace__sys_exit, },
1353 };
1354
1355 struct perf_session *session;
1356 int err = -1;
1357
1358 trace->tool.sample = trace__process_sample;
1359 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001360 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001361 trace->tool.comm = perf_event__process_comm;
1362 trace->tool.exit = perf_event__process_exit;
1363 trace->tool.fork = perf_event__process_fork;
1364 trace->tool.attr = perf_event__process_attr;
1365 trace->tool.tracing_data = perf_event__process_tracing_data;
1366 trace->tool.build_id = perf_event__process_build_id;
1367
1368 trace->tool.ordered_samples = true;
1369 trace->tool.ordering_requires_timestamps = true;
1370
1371 /* add tid to output */
1372 trace->multiple_threads = true;
1373
1374 if (symbol__init() < 0)
1375 return -1;
1376
1377 session = perf_session__new(input_name, O_RDONLY, 0, false,
1378 &trace->tool);
1379 if (session == NULL)
1380 return -ENOMEM;
1381
1382 err = perf_session__set_tracepoints_handlers(session, handlers);
1383 if (err)
1384 goto out;
1385
1386 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1387 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1388 goto out;
1389 }
1390
1391 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1392 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1393 goto out;
1394 }
1395
David Ahernbdc89662013-08-28 22:29:53 -06001396 err = parse_target_str(trace);
1397 if (err != 0)
1398 goto out;
1399
David Ahern6810fc92013-08-28 22:29:52 -06001400 setup_pager();
1401
1402 err = perf_session__process_events(session, &trace->tool);
1403 if (err)
1404 pr_err("Failed to process events, error %d", err);
1405
1406out:
1407 perf_session__delete(session);
1408
1409 return err;
1410}
1411
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001412static size_t trace__fprintf_threads_header(FILE *fp)
1413{
1414 size_t printed;
1415
1416 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1417 printed += fprintf(fp," __) Summary of events (__\n\n");
1418 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1419 printed += fprintf(fp," _____________________________________________________________________\n\n");
1420
1421 return printed;
1422}
1423
1424static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1425{
1426 size_t printed = trace__fprintf_threads_header(fp);
1427 struct rb_node *nd;
1428
1429 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1430 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1431 struct thread_trace *ttrace = thread->priv;
1432 const char *color;
1433 double ratio;
1434
1435 if (ttrace == NULL)
1436 continue;
1437
1438 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1439
1440 color = PERF_COLOR_NORMAL;
1441 if (ratio > 50.0)
1442 color = PERF_COLOR_RED;
1443 else if (ratio > 25.0)
1444 color = PERF_COLOR_GREEN;
1445 else if (ratio > 5.0)
1446 color = PERF_COLOR_YELLOW;
1447
1448 printed += color_fprintf(fp, color, "%20s", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001449 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001450 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1451 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1452 }
1453
1454 return printed;
1455}
1456
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001457static int trace__set_duration(const struct option *opt, const char *str,
1458 int unset __maybe_unused)
1459{
1460 struct trace *trace = opt->value;
1461
1462 trace->duration_filter = atof(str);
1463 return 0;
1464}
1465
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001466static int trace__open_output(struct trace *trace, const char *filename)
1467{
1468 struct stat st;
1469
1470 if (!stat(filename, &st) && st.st_size) {
1471 char oldname[PATH_MAX];
1472
1473 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1474 unlink(oldname);
1475 rename(filename, oldname);
1476 }
1477
1478 trace->output = fopen(filename, "w");
1479
1480 return trace->output == NULL ? -errno : 0;
1481}
1482
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001483int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1484{
1485 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001486 "perf trace [<options>] [<command>]",
1487 "perf trace [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001488 NULL
1489 };
1490 struct trace trace = {
1491 .audit_machine = audit_detect_machine(),
1492 .syscalls = {
1493 . max = -1,
1494 },
1495 .opts = {
1496 .target = {
1497 .uid = UINT_MAX,
1498 .uses_mmap = true,
1499 },
1500 .user_freq = UINT_MAX,
1501 .user_interval = ULLONG_MAX,
1502 .no_delay = true,
1503 .mmap_pages = 1024,
1504 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001505 .output = stdout,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001506 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001507 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001508 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001509 const struct option trace_options[] = {
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001510 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1511 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001512 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001513 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001514 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1515 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001516 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001517 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001518 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001519 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001520 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001521 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001522 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001523 "child tasks do not inherit counters"),
David Ahernac9be8e2013-08-20 11:15:45 -06001524 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001525 "number of mmap data pages"),
David Ahernac9be8e2013-08-20 11:15:45 -06001526 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001527 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001528 OPT_CALLBACK(0, "duration", &trace, "float",
1529 "show only events with duration > N.M ms",
1530 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001531 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001532 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06001533 OPT_BOOLEAN('T', "time", &trace.full_time,
1534 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001535 OPT_END()
1536 };
1537 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001538 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001539
1540 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001541
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001542 if (output_name != NULL) {
1543 err = trace__open_output(&trace, output_name);
1544 if (err < 0) {
1545 perror("failed to create output file");
1546 goto out;
1547 }
1548 }
1549
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001550 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001551 const char *s = ev_qualifier_str;
1552
1553 trace.not_ev_qualifier = *s == '!';
1554 if (trace.not_ev_qualifier)
1555 ++s;
1556 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001557 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001558 fputs("Not enough memory to parse event qualifier",
1559 trace.output);
1560 err = -ENOMEM;
1561 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001562 }
1563 }
1564
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001565 err = perf_target__validate(&trace.opts.target);
1566 if (err) {
1567 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001568 fprintf(trace.output, "%s", bf);
1569 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001570 }
1571
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001572 err = perf_target__parse_uid(&trace.opts.target);
1573 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001574 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001575 fprintf(trace.output, "%s", bf);
1576 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001577 }
1578
Namhyung Kimf15eb532012-10-05 14:02:16 +09001579 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001580 trace.opts.target.system_wide = true;
1581
David Ahern6810fc92013-08-28 22:29:52 -06001582 if (input_name)
1583 err = trace__replay(&trace);
1584 else
1585 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001586
1587 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001588 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001589
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001590out_close:
1591 if (output_name != NULL)
1592 fclose(trace.output);
1593out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001594 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001595}