blob: bc21140ac782875deabd6a2246c152980c10fc15 [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 Meloae685382013-08-20 17:44:42 -030016#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030017#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030018
Ingo Molnar456857b2013-09-12 15:29:00 +020019/* For older distros: */
20#ifndef MAP_STACK
21# define MAP_STACK 0x20000
22#endif
23
24#ifndef MADV_HWPOISON
25# define MADV_HWPOISON 100
26#endif
27
28#ifndef MADV_MERGEABLE
29# define MADV_MERGEABLE 12
30#endif
31
32#ifndef MADV_UNMERGEABLE
33# define MADV_UNMERGEABLE 13
34#endif
35
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030036struct syscall_arg {
37 unsigned long val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030038 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030039 u8 idx;
40 u8 mask;
41};
42
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030043struct strarray {
44 int nr_entries;
45 const char **entries;
46};
47
48#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
49 .nr_entries = ARRAY_SIZE(array), \
50 .entries = array, \
51}
52
53static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
54 struct syscall_arg *arg)
55{
56 int idx = arg->val;
57 struct strarray *sa = arg->parm;
58
59 if (idx < 0 || idx >= sa->nr_entries)
60 return scnprintf(bf, size, "%d", idx);
61
62 return scnprintf(bf, size, "%s", sa->entries[idx]);
63}
64
65#define SCA_STRARRAY syscall_arg__scnprintf_strarray
66
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -030067static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030068 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030069{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030070 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030071}
72
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -030073#define SCA_HEX syscall_arg__scnprintf_hex
74
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -030075static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030076 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030077{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030078 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030079
80 if (prot == PROT_NONE)
81 return scnprintf(bf, size, "NONE");
82#define P_MMAP_PROT(n) \
83 if (prot & PROT_##n) { \
84 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
85 prot &= ~PROT_##n; \
86 }
87
88 P_MMAP_PROT(EXEC);
89 P_MMAP_PROT(READ);
90 P_MMAP_PROT(WRITE);
91#ifdef PROT_SEM
92 P_MMAP_PROT(SEM);
93#endif
94 P_MMAP_PROT(GROWSDOWN);
95 P_MMAP_PROT(GROWSUP);
96#undef P_MMAP_PROT
97
98 if (prot)
99 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
100
101 return printed;
102}
103
104#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
105
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300106static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300107 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300108{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300109 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300110
111#define P_MMAP_FLAG(n) \
112 if (flags & MAP_##n) { \
113 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
114 flags &= ~MAP_##n; \
115 }
116
117 P_MMAP_FLAG(SHARED);
118 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400119#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300120 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400121#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300122 P_MMAP_FLAG(ANONYMOUS);
123 P_MMAP_FLAG(DENYWRITE);
124 P_MMAP_FLAG(EXECUTABLE);
125 P_MMAP_FLAG(FILE);
126 P_MMAP_FLAG(FIXED);
127 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600128#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300129 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600130#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300131 P_MMAP_FLAG(LOCKED);
132 P_MMAP_FLAG(NONBLOCK);
133 P_MMAP_FLAG(NORESERVE);
134 P_MMAP_FLAG(POPULATE);
135 P_MMAP_FLAG(STACK);
136#ifdef MAP_UNINITIALIZED
137 P_MMAP_FLAG(UNINITIALIZED);
138#endif
139#undef P_MMAP_FLAG
140
141 if (flags)
142 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
143
144 return printed;
145}
146
147#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
148
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300149static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300150 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300151{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300152 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300153
154 switch (behavior) {
155#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
156 P_MADV_BHV(NORMAL);
157 P_MADV_BHV(RANDOM);
158 P_MADV_BHV(SEQUENTIAL);
159 P_MADV_BHV(WILLNEED);
160 P_MADV_BHV(DONTNEED);
161 P_MADV_BHV(REMOVE);
162 P_MADV_BHV(DONTFORK);
163 P_MADV_BHV(DOFORK);
164 P_MADV_BHV(HWPOISON);
165#ifdef MADV_SOFT_OFFLINE
166 P_MADV_BHV(SOFT_OFFLINE);
167#endif
168 P_MADV_BHV(MERGEABLE);
169 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600170#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300171 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600172#endif
173#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300174 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600175#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300176#ifdef MADV_DONTDUMP
177 P_MADV_BHV(DONTDUMP);
178#endif
179#ifdef MADV_DODUMP
180 P_MADV_BHV(DODUMP);
181#endif
182#undef P_MADV_PHV
183 default: break;
184 }
185
186 return scnprintf(bf, size, "%#x", behavior);
187}
188
189#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
190
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300191static 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 -0300192{
193 enum syscall_futex_args {
194 SCF_UADDR = (1 << 0),
195 SCF_OP = (1 << 1),
196 SCF_VAL = (1 << 2),
197 SCF_TIMEOUT = (1 << 3),
198 SCF_UADDR2 = (1 << 4),
199 SCF_VAL3 = (1 << 5),
200 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300201 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300202 int cmd = op & FUTEX_CMD_MASK;
203 size_t printed = 0;
204
205 switch (cmd) {
206#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300207 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
208 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
209 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
210 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
211 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
212 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300213 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300214 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
215 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
216 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
217 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
218 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300219 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
220 default: printed = scnprintf(bf, size, "%#x", cmd); break;
221 }
222
223 if (op & FUTEX_PRIVATE_FLAG)
224 printed += scnprintf(bf + printed, size - printed, "|PRIV");
225
226 if (op & FUTEX_CLOCK_REALTIME)
227 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
228
229 return printed;
230}
231
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300232#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
233
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300234static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
235static DEFINE_STRARRAY(itimers);
236
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300237static const char *whences[] = { "SET", "CUR", "END",
238#ifdef SEEK_DATA
239"DATA",
240#endif
241#ifdef SEEK_HOLE
242"HOLE",
243#endif
244};
245static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300246
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300247static const char *fcntl_cmds[] = {
248 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
249 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
250 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
251 "F_GETOWNER_UIDS",
252};
253static DEFINE_STRARRAY(fcntl_cmds);
254
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300255static const char *rlimit_resources[] = {
256 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
257 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
258 "RTTIME",
259};
260static DEFINE_STRARRAY(rlimit_resources);
261
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300262static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
263static DEFINE_STRARRAY(sighow);
264
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300265static const char *socket_families[] = {
266 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
267 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
268 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
269 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
270 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
271 "ALG", "NFC", "VSOCK",
272};
273static DEFINE_STRARRAY(socket_families);
274
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300275#ifndef SOCK_TYPE_MASK
276#define SOCK_TYPE_MASK 0xf
277#endif
278
279static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
280 struct syscall_arg *arg)
281{
282 size_t printed;
283 int type = arg->val,
284 flags = type & ~SOCK_TYPE_MASK;
285
286 type &= SOCK_TYPE_MASK;
287 /*
288 * Can't use a strarray, MIPS may override for ABI reasons.
289 */
290 switch (type) {
291#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
292 P_SK_TYPE(STREAM);
293 P_SK_TYPE(DGRAM);
294 P_SK_TYPE(RAW);
295 P_SK_TYPE(RDM);
296 P_SK_TYPE(SEQPACKET);
297 P_SK_TYPE(DCCP);
298 P_SK_TYPE(PACKET);
299#undef P_SK_TYPE
300 default:
301 printed = scnprintf(bf, size, "%#x", type);
302 }
303
304#define P_SK_FLAG(n) \
305 if (flags & SOCK_##n) { \
306 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
307 flags &= ~SOCK_##n; \
308 }
309
310 P_SK_FLAG(CLOEXEC);
311 P_SK_FLAG(NONBLOCK);
312#undef P_SK_FLAG
313
314 if (flags)
315 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
316
317 return printed;
318}
319
320#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
321
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300322static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
323 struct syscall_arg *arg)
324{
325 size_t printed = 0;
326 int mode = arg->val;
327
328 if (mode == F_OK) /* 0 */
329 return scnprintf(bf, size, "F");
330#define P_MODE(n) \
331 if (mode & n##_OK) { \
332 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
333 mode &= ~n##_OK; \
334 }
335
336 P_MODE(R);
337 P_MODE(W);
338 P_MODE(X);
339#undef P_MODE
340
341 if (mode)
342 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
343
344 return printed;
345}
346
347#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
348
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300349static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300350 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300351{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300352 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300353
354 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300355 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300356
357 if (flags == 0)
358 return scnprintf(bf, size, "RDONLY");
359#define P_FLAG(n) \
360 if (flags & O_##n) { \
361 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
362 flags &= ~O_##n; \
363 }
364
365 P_FLAG(APPEND);
366 P_FLAG(ASYNC);
367 P_FLAG(CLOEXEC);
368 P_FLAG(CREAT);
369 P_FLAG(DIRECT);
370 P_FLAG(DIRECTORY);
371 P_FLAG(EXCL);
372 P_FLAG(LARGEFILE);
373 P_FLAG(NOATIME);
374 P_FLAG(NOCTTY);
375#ifdef O_NONBLOCK
376 P_FLAG(NONBLOCK);
377#elif O_NDELAY
378 P_FLAG(NDELAY);
379#endif
380#ifdef O_PATH
381 P_FLAG(PATH);
382#endif
383 P_FLAG(RDWR);
384#ifdef O_DSYNC
385 if ((flags & O_SYNC) == O_SYNC)
386 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
387 else {
388 P_FLAG(DSYNC);
389 }
390#else
391 P_FLAG(SYNC);
392#endif
393 P_FLAG(TRUNC);
394 P_FLAG(WRONLY);
395#undef P_FLAG
396
397 if (flags)
398 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
399
400 return printed;
401}
402
403#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
404
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300405static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
406{
407 int sig = arg->val;
408
409 switch (sig) {
410#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
411 P_SIGNUM(HUP);
412 P_SIGNUM(INT);
413 P_SIGNUM(QUIT);
414 P_SIGNUM(ILL);
415 P_SIGNUM(TRAP);
416 P_SIGNUM(ABRT);
417 P_SIGNUM(BUS);
418 P_SIGNUM(FPE);
419 P_SIGNUM(KILL);
420 P_SIGNUM(USR1);
421 P_SIGNUM(SEGV);
422 P_SIGNUM(USR2);
423 P_SIGNUM(PIPE);
424 P_SIGNUM(ALRM);
425 P_SIGNUM(TERM);
426 P_SIGNUM(STKFLT);
427 P_SIGNUM(CHLD);
428 P_SIGNUM(CONT);
429 P_SIGNUM(STOP);
430 P_SIGNUM(TSTP);
431 P_SIGNUM(TTIN);
432 P_SIGNUM(TTOU);
433 P_SIGNUM(URG);
434 P_SIGNUM(XCPU);
435 P_SIGNUM(XFSZ);
436 P_SIGNUM(VTALRM);
437 P_SIGNUM(PROF);
438 P_SIGNUM(WINCH);
439 P_SIGNUM(IO);
440 P_SIGNUM(PWR);
441 P_SIGNUM(SYS);
442 default: break;
443 }
444
445 return scnprintf(bf, size, "%#x", sig);
446}
447
448#define SCA_SIGNUM syscall_arg__scnprintf_signum
449
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300450static struct syscall_fmt {
451 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300452 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300453 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300454 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300455 bool errmsg;
456 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300457 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300458} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300459 { .name = "access", .errmsg = true,
460 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300461 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300462 { .name = "brk", .hexret = true,
463 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300464 { .name = "mmap", .hexret = true, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300465 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300466 { .name = "fcntl", .errmsg = true,
467 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
468 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300469 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
470 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300471 { .name = "futex", .errmsg = true,
472 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300473 { .name = "getitimer", .errmsg = true,
474 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
475 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300476 { .name = "getrlimit", .errmsg = true,
477 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
478 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300479 { .name = "ioctl", .errmsg = true,
480 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300481 { .name = "kill", .errmsg = true,
482 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo579e7862013-09-02 15:37:32 -0300483 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300484 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
485 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300486 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300487 { .name = "madvise", .errmsg = true,
488 .arg_scnprintf = { [0] = SCA_HEX, /* start */
489 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300490 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300491 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300492 [2] = SCA_MMAP_PROT, /* prot */
493 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300494 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300495 .arg_scnprintf = { [0] = SCA_HEX, /* start */
496 [2] = SCA_MMAP_PROT, /* prot */ }, },
497 { .name = "mremap", .hexret = true,
498 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
499 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300500 { .name = "munmap", .errmsg = true,
501 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300502 { .name = "open", .errmsg = true,
503 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300504 { .name = "open_by_handle_at", .errmsg = true,
505 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
506 { .name = "openat", .errmsg = true,
507 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300508 { .name = "poll", .errmsg = true, .timeout = true, },
509 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300510 { .name = "pread", .errmsg = true, .alias = "pread64", },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300511 { .name = "prlimit64", .errmsg = true,
512 .arg_scnprintf = { [1] = SCA_STRARRAY, /* resource */ },
513 .arg_parm = { [1] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300514 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300515 { .name = "read", .errmsg = true, },
516 { .name = "recvfrom", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300517 { .name = "rt_sigaction", .errmsg = true,
518 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300519 { .name = "rt_sigprocmask", .errmsg = true,
520 .arg_scnprintf = { [0] = SCA_STRARRAY, /* how */ },
521 .arg_parm = { [0] = &strarray__sighow, /* how */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300522 { .name = "rt_sigqueueinfo", .errmsg = true,
523 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
524 { .name = "rt_tgsigqueueinfo", .errmsg = true,
525 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300526 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300527 { .name = "setitimer", .errmsg = true,
528 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
529 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300530 { .name = "setrlimit", .errmsg = true,
531 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
532 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300533 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300534 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
535 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300536 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300537 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300538 { .name = "tgkill", .errmsg = true,
539 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
540 { .name = "tkill", .errmsg = true,
541 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300542 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300543};
544
545static int syscall_fmt__cmp(const void *name, const void *fmtp)
546{
547 const struct syscall_fmt *fmt = fmtp;
548 return strcmp(name, fmt->name);
549}
550
551static struct syscall_fmt *syscall_fmt__find(const char *name)
552{
553 const int nmemb = ARRAY_SIZE(syscall_fmts);
554 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
555}
556
557struct syscall {
558 struct event_format *tp_format;
559 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300560 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300561 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300562 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300563 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300564};
565
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200566static size_t fprintf_duration(unsigned long t, FILE *fp)
567{
568 double duration = (double)t / NSEC_PER_MSEC;
569 size_t printed = fprintf(fp, "(");
570
571 if (duration >= 1.0)
572 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
573 else if (duration >= 0.01)
574 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
575 else
576 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300577 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200578}
579
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300580struct thread_trace {
581 u64 entry_time;
582 u64 exit_time;
583 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300584 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300585 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300586 double runtime_ms;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300587};
588
589static struct thread_trace *thread_trace__new(void)
590{
591 return zalloc(sizeof(struct thread_trace));
592}
593
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300594static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300595{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300596 struct thread_trace *ttrace;
597
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300598 if (thread == NULL)
599 goto fail;
600
601 if (thread->priv == NULL)
602 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300603
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300604 if (thread->priv == NULL)
605 goto fail;
606
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300607 ttrace = thread->priv;
608 ++ttrace->nr_events;
609
610 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300611fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300612 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300613 "WARNING: not enough memory, dropping samples!\n");
614 return NULL;
615}
616
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300617struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300618 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300619 int audit_machine;
620 struct {
621 int max;
622 struct syscall *table;
623 } syscalls;
624 struct perf_record_opts opts;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300625 struct machine host;
626 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600627 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300628 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300629 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300630 struct strlist *ev_qualifier;
631 bool not_ev_qualifier;
David Ahernbdc89662013-08-28 22:29:53 -0600632 struct intlist *tid_list;
633 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300634 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300635 bool multiple_threads;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300636 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300637 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300638};
639
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300640static bool trace__filter_duration(struct trace *trace, double t)
641{
642 return t < (trace->duration_filter * NSEC_PER_MSEC);
643}
644
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300645static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
646{
647 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
648
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200649 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300650}
651
Namhyung Kimf15eb532012-10-05 14:02:16 +0900652static bool done = false;
653
654static void sig_handler(int sig __maybe_unused)
655{
656 done = true;
657}
658
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300659static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200660 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300661{
662 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200663 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300664
665 if (trace->multiple_threads)
Adrian Hunter38051232013-07-04 16:20:31 +0300666 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300667
668 return printed;
669}
670
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300671static int trace__process_event(struct trace *trace, struct machine *machine,
672 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300673{
674 int ret = 0;
675
676 switch (event->header.type) {
677 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300678 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300679 "LOST %" PRIu64 " events!\n", event->lost.lost);
680 ret = machine__process_lost_event(machine, event);
681 default:
682 ret = machine__process_event(machine, event);
683 break;
684 }
685
686 return ret;
687}
688
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300689static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300690 union perf_event *event,
691 struct perf_sample *sample __maybe_unused,
692 struct machine *machine)
693{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300694 struct trace *trace = container_of(tool, struct trace, tool);
695 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300696}
697
698static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
699{
700 int err = symbol__init();
701
702 if (err)
703 return err;
704
705 machine__init(&trace->host, "", HOST_KERNEL_ID);
706 machine__create_kernel_maps(&trace->host);
707
708 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300709 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300710 trace__tool_process,
711 &trace->host);
712 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300713 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300714 &trace->host);
715 }
716
717 if (err)
718 symbol__exit();
719
720 return err;
721}
722
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300723static int syscall__set_arg_fmts(struct syscall *sc)
724{
725 struct format_field *field;
726 int idx = 0;
727
728 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
729 if (sc->arg_scnprintf == NULL)
730 return -1;
731
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300732 if (sc->fmt)
733 sc->arg_parm = sc->fmt->arg_parm;
734
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300735 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300736 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
737 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
738 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300739 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
740 ++idx;
741 }
742
743 return 0;
744}
745
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300746static int trace__read_syscall_info(struct trace *trace, int id)
747{
748 char tp_name[128];
749 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300750 const char *name = audit_syscall_to_name(id, trace->audit_machine);
751
752 if (name == NULL)
753 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300754
755 if (id > trace->syscalls.max) {
756 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
757
758 if (nsyscalls == NULL)
759 return -1;
760
761 if (trace->syscalls.max != -1) {
762 memset(nsyscalls + trace->syscalls.max + 1, 0,
763 (id - trace->syscalls.max) * sizeof(*sc));
764 } else {
765 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
766 }
767
768 trace->syscalls.table = nsyscalls;
769 trace->syscalls.max = id;
770 }
771
772 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300773 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300774
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300775 if (trace->ev_qualifier) {
776 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
777
778 if (!(in ^ trace->not_ev_qualifier)) {
779 sc->filtered = true;
780 /*
781 * No need to do read tracepoint information since this will be
782 * filtered out.
783 */
784 return 0;
785 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300786 }
787
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300788 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300789
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300790 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
791 sc->tp_format = event_format__new("syscalls", tp_name);
792
793 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
794 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
795 sc->tp_format = event_format__new("syscalls", tp_name);
796 }
797
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300798 if (sc->tp_format == NULL)
799 return -1;
800
801 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300802}
803
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300804static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
805 unsigned long *args)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300806{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300807 size_t printed = 0;
808
809 if (sc->tp_format != NULL) {
810 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300811 u8 bit = 1;
812 struct syscall_arg arg = {
813 .idx = 0,
814 .mask = 0,
815 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300816
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300817 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300818 field = field->next, ++arg.idx, bit <<= 1) {
819 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300820 continue;
821
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300822 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300823 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300824 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
825 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300826 if (sc->arg_parm)
827 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300828 printed += sc->arg_scnprintf[arg.idx](bf + printed,
829 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300830 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300831 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300832 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300833 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300834 }
835 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300836 int i = 0;
837
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300838 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300839 printed += scnprintf(bf + printed, size - printed,
840 "%sarg%d: %ld",
841 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300842 ++i;
843 }
844 }
845
846 return printed;
847}
848
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300849typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
850 struct perf_sample *sample);
851
852static struct syscall *trace__syscall_info(struct trace *trace,
853 struct perf_evsel *evsel,
854 struct perf_sample *sample)
855{
856 int id = perf_evsel__intval(evsel, sample, "id");
857
858 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -0300859
860 /*
861 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
862 * before that, leaving at a higher verbosity level till that is
863 * explained. Reproduced with plain ftrace with:
864 *
865 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
866 * grep "NR -1 " /t/trace_pipe
867 *
868 * After generating some load on the machine.
869 */
870 if (verbose > 1) {
871 static u64 n;
872 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
873 id, perf_evsel__name(evsel), ++n);
874 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300875 return NULL;
876 }
877
878 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
879 trace__read_syscall_info(trace, id))
880 goto out_cant_read;
881
882 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
883 goto out_cant_read;
884
885 return &trace->syscalls.table[id];
886
887out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -0300888 if (verbose) {
889 fprintf(trace->output, "Problems reading syscall %d", id);
890 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
891 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
892 fputs(" information\n", trace->output);
893 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300894 return NULL;
895}
896
897static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
898 struct perf_sample *sample)
899{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300900 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300901 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300902 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300903 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300904 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300905 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300906
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300907 if (sc == NULL)
908 return -1;
909
910 if (sc->filtered)
911 return 0;
912
Adrian Hunter314add62013-08-27 11:23:03 +0300913 thread = machine__findnew_thread(&trace->host, sample->pid,
914 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300915 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300916 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300917 return -1;
918
919 args = perf_evsel__rawptr(evsel, sample, "args");
920 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300921 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300922 return -1;
923 }
924
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300925 ttrace = thread->priv;
926
927 if (ttrace->entry_str == NULL) {
928 ttrace->entry_str = malloc(1024);
929 if (!ttrace->entry_str)
930 return -1;
931 }
932
933 ttrace->entry_time = sample->time;
934 msg = ttrace->entry_str;
935 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
936
937 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
938
939 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300940 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300941 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
942 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300943 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300944 } else
945 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300946
947 return 0;
948}
949
950static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
951 struct perf_sample *sample)
952{
953 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200954 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300955 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300956 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300957 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300958
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300959 if (sc == NULL)
960 return -1;
961
962 if (sc->filtered)
963 return 0;
964
Adrian Hunter314add62013-08-27 11:23:03 +0300965 thread = machine__findnew_thread(&trace->host, sample->pid,
966 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300967 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300968 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300969 return -1;
970
971 ret = perf_evsel__intval(evsel, sample, "ret");
972
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300973 ttrace = thread->priv;
974
975 ttrace->exit_time = sample->time;
976
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300977 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200978 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300979 if (trace__filter_duration(trace, duration))
980 goto out;
981 } else if (trace->duration_filter)
982 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200983
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300984 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300985
986 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300987 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300988 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300989 fprintf(trace->output, " ... [");
990 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
991 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300992 }
993
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -0300994 if (sc->fmt == NULL) {
995signed_print:
996 fprintf(trace->output, ") = %d", ret);
997 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300998 char bf[256];
999 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1000 *e = audit_errno_to_name(-ret);
1001
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001002 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001003 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001004 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001005 else if (sc->fmt->hexret)
1006 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001007 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001008 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001009
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001010 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001011out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001012 ttrace->entry_pending = false;
1013
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001014 return 0;
1015}
1016
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001017static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1018 struct perf_sample *sample)
1019{
1020 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1021 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
Adrian Hunter314add62013-08-27 11:23:03 +03001022 struct thread *thread = machine__findnew_thread(&trace->host,
1023 sample->pid,
1024 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001025 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001026
1027 if (ttrace == NULL)
1028 goto out_dump;
1029
1030 ttrace->runtime_ms += runtime_ms;
1031 trace->runtime_ms += runtime_ms;
1032 return 0;
1033
1034out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001035 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001036 evsel->name,
1037 perf_evsel__strval(evsel, sample, "comm"),
1038 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1039 runtime,
1040 perf_evsel__intval(evsel, sample, "vruntime"));
1041 return 0;
1042}
1043
David Ahernbdc89662013-08-28 22:29:53 -06001044static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1045{
1046 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1047 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1048 return false;
1049
1050 if (trace->pid_list || trace->tid_list)
1051 return true;
1052
1053 return false;
1054}
1055
David Ahern6810fc92013-08-28 22:29:52 -06001056static int trace__process_sample(struct perf_tool *tool,
1057 union perf_event *event __maybe_unused,
1058 struct perf_sample *sample,
1059 struct perf_evsel *evsel,
1060 struct machine *machine __maybe_unused)
1061{
1062 struct trace *trace = container_of(tool, struct trace, tool);
1063 int err = 0;
1064
1065 tracepoint_handler handler = evsel->handler.func;
1066
David Ahernbdc89662013-08-28 22:29:53 -06001067 if (skip_sample(trace, sample))
1068 return 0;
1069
David Ahern4bb09192013-09-04 12:37:43 -06001070 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001071 trace->base_time = sample->time;
1072
1073 if (handler)
1074 handler(trace, evsel, sample);
1075
1076 return err;
1077}
1078
1079static bool
1080perf_session__has_tp(struct perf_session *session, const char *name)
1081{
1082 struct perf_evsel *evsel;
1083
1084 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1085
1086 return evsel != NULL;
1087}
1088
David Ahernbdc89662013-08-28 22:29:53 -06001089static int parse_target_str(struct trace *trace)
1090{
1091 if (trace->opts.target.pid) {
1092 trace->pid_list = intlist__new(trace->opts.target.pid);
1093 if (trace->pid_list == NULL) {
1094 pr_err("Error parsing process id string\n");
1095 return -EINVAL;
1096 }
1097 }
1098
1099 if (trace->opts.target.tid) {
1100 trace->tid_list = intlist__new(trace->opts.target.tid);
1101 if (trace->tid_list == NULL) {
1102 pr_err("Error parsing thread id string\n");
1103 return -EINVAL;
1104 }
1105 }
1106
1107 return 0;
1108}
1109
Namhyung Kimf15eb532012-10-05 14:02:16 +09001110static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001111{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001112 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001113 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001114 int err = -1, i;
1115 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001116 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001117
1118 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001119 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001120 goto out;
1121 }
1122
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001123 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1124 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001125 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001126 goto out_delete_evlist;
1127 }
1128
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001129 if (trace->sched &&
1130 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1131 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001132 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001133 goto out_delete_evlist;
1134 }
1135
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001136 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1137 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001138 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001139 goto out_delete_evlist;
1140 }
1141
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001142 err = trace__symbols_init(trace, evlist);
1143 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001144 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001145 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001146 }
1147
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001148 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001149
Namhyung Kimf15eb532012-10-05 14:02:16 +09001150 signal(SIGCHLD, sig_handler);
1151 signal(SIGINT, sig_handler);
1152
1153 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001154 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001155 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001156 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001157 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001158 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001159 }
1160 }
1161
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001162 err = perf_evlist__open(evlist);
1163 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001164 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001165 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001166 }
1167
1168 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1169 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001170 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001171 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001172 }
1173
1174 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001175
1176 if (forks)
1177 perf_evlist__start_workload(evlist);
1178
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001179 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001180again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001181 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001182
1183 for (i = 0; i < evlist->nr_mmaps; i++) {
1184 union perf_event *event;
1185
1186 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1187 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001188 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001189 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001190
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001191 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001192
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001193 err = perf_evlist__parse_sample(evlist, event, &sample);
1194 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001195 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001196 continue;
1197 }
1198
David Ahern4bb09192013-09-04 12:37:43 -06001199 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001200 trace->base_time = sample.time;
1201
1202 if (type != PERF_RECORD_SAMPLE) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001203 trace__process_event(trace, &trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001204 continue;
1205 }
1206
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001207 evsel = perf_evlist__id2evsel(evlist, sample.id);
1208 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001209 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001210 continue;
1211 }
1212
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001213 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001214 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 -03001215 perf_evsel__name(evsel), sample.tid,
1216 sample.cpu, sample.raw_size);
1217 continue;
1218 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001219
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001220 handler = evsel->handler.func;
1221 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001222
1223 if (done)
1224 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001225 }
1226 }
1227
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001228 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001229 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001230 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001231
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001232 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001233 }
1234
1235 if (done)
1236 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001237
1238 goto again;
1239
Namhyung Kim3beb0862013-03-15 14:48:50 +09001240out_unmap_evlist:
1241 perf_evlist__munmap(evlist);
1242out_close_evlist:
1243 perf_evlist__close(evlist);
1244out_delete_maps:
1245 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001246out_delete_evlist:
1247 perf_evlist__delete(evlist);
1248out:
1249 return err;
1250}
1251
David Ahern6810fc92013-08-28 22:29:52 -06001252static int trace__replay(struct trace *trace)
1253{
1254 const struct perf_evsel_str_handler handlers[] = {
1255 { "raw_syscalls:sys_enter", trace__sys_enter, },
1256 { "raw_syscalls:sys_exit", trace__sys_exit, },
1257 };
1258
1259 struct perf_session *session;
1260 int err = -1;
1261
1262 trace->tool.sample = trace__process_sample;
1263 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001264 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001265 trace->tool.comm = perf_event__process_comm;
1266 trace->tool.exit = perf_event__process_exit;
1267 trace->tool.fork = perf_event__process_fork;
1268 trace->tool.attr = perf_event__process_attr;
1269 trace->tool.tracing_data = perf_event__process_tracing_data;
1270 trace->tool.build_id = perf_event__process_build_id;
1271
1272 trace->tool.ordered_samples = true;
1273 trace->tool.ordering_requires_timestamps = true;
1274
1275 /* add tid to output */
1276 trace->multiple_threads = true;
1277
1278 if (symbol__init() < 0)
1279 return -1;
1280
1281 session = perf_session__new(input_name, O_RDONLY, 0, false,
1282 &trace->tool);
1283 if (session == NULL)
1284 return -ENOMEM;
1285
1286 err = perf_session__set_tracepoints_handlers(session, handlers);
1287 if (err)
1288 goto out;
1289
1290 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1291 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1292 goto out;
1293 }
1294
1295 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1296 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1297 goto out;
1298 }
1299
David Ahernbdc89662013-08-28 22:29:53 -06001300 err = parse_target_str(trace);
1301 if (err != 0)
1302 goto out;
1303
David Ahern6810fc92013-08-28 22:29:52 -06001304 setup_pager();
1305
1306 err = perf_session__process_events(session, &trace->tool);
1307 if (err)
1308 pr_err("Failed to process events, error %d", err);
1309
1310out:
1311 perf_session__delete(session);
1312
1313 return err;
1314}
1315
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001316static size_t trace__fprintf_threads_header(FILE *fp)
1317{
1318 size_t printed;
1319
1320 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1321 printed += fprintf(fp," __) Summary of events (__\n\n");
1322 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1323 printed += fprintf(fp," _____________________________________________________________________\n\n");
1324
1325 return printed;
1326}
1327
1328static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1329{
1330 size_t printed = trace__fprintf_threads_header(fp);
1331 struct rb_node *nd;
1332
1333 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1334 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1335 struct thread_trace *ttrace = thread->priv;
1336 const char *color;
1337 double ratio;
1338
1339 if (ttrace == NULL)
1340 continue;
1341
1342 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1343
1344 color = PERF_COLOR_NORMAL;
1345 if (ratio > 50.0)
1346 color = PERF_COLOR_RED;
1347 else if (ratio > 25.0)
1348 color = PERF_COLOR_GREEN;
1349 else if (ratio > 5.0)
1350 color = PERF_COLOR_YELLOW;
1351
1352 printed += color_fprintf(fp, color, "%20s", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001353 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001354 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1355 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1356 }
1357
1358 return printed;
1359}
1360
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001361static int trace__set_duration(const struct option *opt, const char *str,
1362 int unset __maybe_unused)
1363{
1364 struct trace *trace = opt->value;
1365
1366 trace->duration_filter = atof(str);
1367 return 0;
1368}
1369
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001370static int trace__open_output(struct trace *trace, const char *filename)
1371{
1372 struct stat st;
1373
1374 if (!stat(filename, &st) && st.st_size) {
1375 char oldname[PATH_MAX];
1376
1377 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1378 unlink(oldname);
1379 rename(filename, oldname);
1380 }
1381
1382 trace->output = fopen(filename, "w");
1383
1384 return trace->output == NULL ? -errno : 0;
1385}
1386
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001387int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1388{
1389 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001390 "perf trace [<options>] [<command>]",
1391 "perf trace [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001392 NULL
1393 };
1394 struct trace trace = {
1395 .audit_machine = audit_detect_machine(),
1396 .syscalls = {
1397 . max = -1,
1398 },
1399 .opts = {
1400 .target = {
1401 .uid = UINT_MAX,
1402 .uses_mmap = true,
1403 },
1404 .user_freq = UINT_MAX,
1405 .user_interval = ULLONG_MAX,
1406 .no_delay = true,
1407 .mmap_pages = 1024,
1408 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001409 .output = stdout,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001410 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001411 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001412 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001413 const struct option trace_options[] = {
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001414 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1415 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001416 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001417 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001418 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1419 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001420 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001421 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001422 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001423 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001424 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001425 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001426 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001427 "child tasks do not inherit counters"),
David Ahernac9be8e2013-08-20 11:15:45 -06001428 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001429 "number of mmap data pages"),
David Ahernac9be8e2013-08-20 11:15:45 -06001430 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001431 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001432 OPT_CALLBACK(0, "duration", &trace, "float",
1433 "show only events with duration > N.M ms",
1434 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001435 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001436 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06001437 OPT_BOOLEAN('T', "time", &trace.full_time,
1438 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001439 OPT_END()
1440 };
1441 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001442 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001443
1444 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001445
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001446 if (output_name != NULL) {
1447 err = trace__open_output(&trace, output_name);
1448 if (err < 0) {
1449 perror("failed to create output file");
1450 goto out;
1451 }
1452 }
1453
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001454 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001455 const char *s = ev_qualifier_str;
1456
1457 trace.not_ev_qualifier = *s == '!';
1458 if (trace.not_ev_qualifier)
1459 ++s;
1460 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001461 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001462 fputs("Not enough memory to parse event qualifier",
1463 trace.output);
1464 err = -ENOMEM;
1465 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001466 }
1467 }
1468
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001469 err = perf_target__validate(&trace.opts.target);
1470 if (err) {
1471 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001472 fprintf(trace.output, "%s", bf);
1473 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001474 }
1475
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001476 err = perf_target__parse_uid(&trace.opts.target);
1477 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001478 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001479 fprintf(trace.output, "%s", bf);
1480 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001481 }
1482
Namhyung Kimf15eb532012-10-05 14:02:16 +09001483 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001484 trace.opts.target.system_wide = true;
1485
David Ahern6810fc92013-08-28 22:29:52 -06001486 if (input_name)
1487 err = trace__replay(&trace);
1488 else
1489 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001490
1491 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001492 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001493
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001494out_close:
1495 if (output_name != NULL)
1496 fclose(trace.output);
1497out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001498 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001499}