blob: 62801663bd464e5dd177508cd5a8e254204b0b03 [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 Meloeb5b1b12013-09-03 16:37:46 -0300255static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
256static DEFINE_STRARRAY(sighow);
257
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300258static const char *socket_families[] = {
259 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
260 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
261 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
262 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
263 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
264 "ALG", "NFC", "VSOCK",
265};
266static DEFINE_STRARRAY(socket_families);
267
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300268static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300269 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300270{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300271 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300272
273 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300274 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300275
276 if (flags == 0)
277 return scnprintf(bf, size, "RDONLY");
278#define P_FLAG(n) \
279 if (flags & O_##n) { \
280 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
281 flags &= ~O_##n; \
282 }
283
284 P_FLAG(APPEND);
285 P_FLAG(ASYNC);
286 P_FLAG(CLOEXEC);
287 P_FLAG(CREAT);
288 P_FLAG(DIRECT);
289 P_FLAG(DIRECTORY);
290 P_FLAG(EXCL);
291 P_FLAG(LARGEFILE);
292 P_FLAG(NOATIME);
293 P_FLAG(NOCTTY);
294#ifdef O_NONBLOCK
295 P_FLAG(NONBLOCK);
296#elif O_NDELAY
297 P_FLAG(NDELAY);
298#endif
299#ifdef O_PATH
300 P_FLAG(PATH);
301#endif
302 P_FLAG(RDWR);
303#ifdef O_DSYNC
304 if ((flags & O_SYNC) == O_SYNC)
305 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
306 else {
307 P_FLAG(DSYNC);
308 }
309#else
310 P_FLAG(SYNC);
311#endif
312 P_FLAG(TRUNC);
313 P_FLAG(WRONLY);
314#undef P_FLAG
315
316 if (flags)
317 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
318
319 return printed;
320}
321
322#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
323
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300324static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
325{
326 int sig = arg->val;
327
328 switch (sig) {
329#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
330 P_SIGNUM(HUP);
331 P_SIGNUM(INT);
332 P_SIGNUM(QUIT);
333 P_SIGNUM(ILL);
334 P_SIGNUM(TRAP);
335 P_SIGNUM(ABRT);
336 P_SIGNUM(BUS);
337 P_SIGNUM(FPE);
338 P_SIGNUM(KILL);
339 P_SIGNUM(USR1);
340 P_SIGNUM(SEGV);
341 P_SIGNUM(USR2);
342 P_SIGNUM(PIPE);
343 P_SIGNUM(ALRM);
344 P_SIGNUM(TERM);
345 P_SIGNUM(STKFLT);
346 P_SIGNUM(CHLD);
347 P_SIGNUM(CONT);
348 P_SIGNUM(STOP);
349 P_SIGNUM(TSTP);
350 P_SIGNUM(TTIN);
351 P_SIGNUM(TTOU);
352 P_SIGNUM(URG);
353 P_SIGNUM(XCPU);
354 P_SIGNUM(XFSZ);
355 P_SIGNUM(VTALRM);
356 P_SIGNUM(PROF);
357 P_SIGNUM(WINCH);
358 P_SIGNUM(IO);
359 P_SIGNUM(PWR);
360 P_SIGNUM(SYS);
361 default: break;
362 }
363
364 return scnprintf(bf, size, "%#x", sig);
365}
366
367#define SCA_SIGNUM syscall_arg__scnprintf_signum
368
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300369static struct syscall_fmt {
370 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300371 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300372 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300373 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300374 bool errmsg;
375 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300376 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300377} syscall_fmts[] = {
Arnaldo Carvalho de Melo8b745262012-10-18 19:06:13 -0300378 { .name = "access", .errmsg = true, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300379 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300380 { .name = "brk", .hexret = true,
381 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300382 { .name = "mmap", .hexret = true, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300383 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300384 { .name = "fcntl", .errmsg = true,
385 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
386 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300387 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
388 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300389 { .name = "futex", .errmsg = true,
390 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300391 { .name = "getitimer", .errmsg = true,
392 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
393 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300394 { .name = "ioctl", .errmsg = true,
395 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300396 { .name = "kill", .errmsg = true,
397 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo579e7862013-09-02 15:37:32 -0300398 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300399 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
400 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300401 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300402 { .name = "madvise", .errmsg = true,
403 .arg_scnprintf = { [0] = SCA_HEX, /* start */
404 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300405 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300406 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300407 [2] = SCA_MMAP_PROT, /* prot */
408 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300409 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300410 .arg_scnprintf = { [0] = SCA_HEX, /* start */
411 [2] = SCA_MMAP_PROT, /* prot */ }, },
412 { .name = "mremap", .hexret = true,
413 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
414 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300415 { .name = "munmap", .errmsg = true,
416 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300417 { .name = "open", .errmsg = true,
418 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300419 { .name = "open_by_handle_at", .errmsg = true,
420 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
421 { .name = "openat", .errmsg = true,
422 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300423 { .name = "poll", .errmsg = true, .timeout = true, },
424 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300425 { .name = "pread", .errmsg = true, .alias = "pread64", },
426 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300427 { .name = "read", .errmsg = true, },
428 { .name = "recvfrom", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300429 { .name = "rt_sigaction", .errmsg = true,
430 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300431 { .name = "rt_sigprocmask", .errmsg = true,
432 .arg_scnprintf = { [0] = SCA_STRARRAY, /* how */ },
433 .arg_parm = { [0] = &strarray__sighow, /* how */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300434 { .name = "rt_sigqueueinfo", .errmsg = true,
435 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
436 { .name = "rt_tgsigqueueinfo", .errmsg = true,
437 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300438 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300439 { .name = "setitimer", .errmsg = true,
440 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
441 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300442 { .name = "socket", .errmsg = true,
443 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */ },
444 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300445 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300446 { .name = "tgkill", .errmsg = true,
447 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
448 { .name = "tkill", .errmsg = true,
449 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300450 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300451};
452
453static int syscall_fmt__cmp(const void *name, const void *fmtp)
454{
455 const struct syscall_fmt *fmt = fmtp;
456 return strcmp(name, fmt->name);
457}
458
459static struct syscall_fmt *syscall_fmt__find(const char *name)
460{
461 const int nmemb = ARRAY_SIZE(syscall_fmts);
462 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
463}
464
465struct syscall {
466 struct event_format *tp_format;
467 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300468 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300469 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300470 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300471 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300472};
473
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200474static size_t fprintf_duration(unsigned long t, FILE *fp)
475{
476 double duration = (double)t / NSEC_PER_MSEC;
477 size_t printed = fprintf(fp, "(");
478
479 if (duration >= 1.0)
480 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
481 else if (duration >= 0.01)
482 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
483 else
484 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300485 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200486}
487
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300488struct thread_trace {
489 u64 entry_time;
490 u64 exit_time;
491 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300492 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300493 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300494 double runtime_ms;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300495};
496
497static struct thread_trace *thread_trace__new(void)
498{
499 return zalloc(sizeof(struct thread_trace));
500}
501
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300502static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300503{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300504 struct thread_trace *ttrace;
505
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300506 if (thread == NULL)
507 goto fail;
508
509 if (thread->priv == NULL)
510 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300511
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300512 if (thread->priv == NULL)
513 goto fail;
514
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300515 ttrace = thread->priv;
516 ++ttrace->nr_events;
517
518 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300519fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300520 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300521 "WARNING: not enough memory, dropping samples!\n");
522 return NULL;
523}
524
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300525struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300526 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300527 int audit_machine;
528 struct {
529 int max;
530 struct syscall *table;
531 } syscalls;
532 struct perf_record_opts opts;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300533 struct machine host;
534 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300535 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300536 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300537 struct strlist *ev_qualifier;
538 bool not_ev_qualifier;
David Ahernbdc89662013-08-28 22:29:53 -0600539 struct intlist *tid_list;
540 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300541 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300542 bool multiple_threads;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300543 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300544 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300545};
546
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300547static bool trace__filter_duration(struct trace *trace, double t)
548{
549 return t < (trace->duration_filter * NSEC_PER_MSEC);
550}
551
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300552static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
553{
554 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
555
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200556 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300557}
558
Namhyung Kimf15eb532012-10-05 14:02:16 +0900559static bool done = false;
560
561static void sig_handler(int sig __maybe_unused)
562{
563 done = true;
564}
565
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300566static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200567 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300568{
569 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200570 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300571
572 if (trace->multiple_threads)
Adrian Hunter38051232013-07-04 16:20:31 +0300573 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300574
575 return printed;
576}
577
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300578static int trace__process_event(struct trace *trace, struct machine *machine,
579 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300580{
581 int ret = 0;
582
583 switch (event->header.type) {
584 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300585 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300586 "LOST %" PRIu64 " events!\n", event->lost.lost);
587 ret = machine__process_lost_event(machine, event);
588 default:
589 ret = machine__process_event(machine, event);
590 break;
591 }
592
593 return ret;
594}
595
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300596static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300597 union perf_event *event,
598 struct perf_sample *sample __maybe_unused,
599 struct machine *machine)
600{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300601 struct trace *trace = container_of(tool, struct trace, tool);
602 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300603}
604
605static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
606{
607 int err = symbol__init();
608
609 if (err)
610 return err;
611
612 machine__init(&trace->host, "", HOST_KERNEL_ID);
613 machine__create_kernel_maps(&trace->host);
614
615 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300616 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300617 trace__tool_process,
618 &trace->host);
619 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300620 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300621 &trace->host);
622 }
623
624 if (err)
625 symbol__exit();
626
627 return err;
628}
629
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300630static int syscall__set_arg_fmts(struct syscall *sc)
631{
632 struct format_field *field;
633 int idx = 0;
634
635 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
636 if (sc->arg_scnprintf == NULL)
637 return -1;
638
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300639 if (sc->fmt)
640 sc->arg_parm = sc->fmt->arg_parm;
641
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300642 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300643 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
644 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
645 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300646 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
647 ++idx;
648 }
649
650 return 0;
651}
652
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300653static int trace__read_syscall_info(struct trace *trace, int id)
654{
655 char tp_name[128];
656 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300657 const char *name = audit_syscall_to_name(id, trace->audit_machine);
658
659 if (name == NULL)
660 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300661
662 if (id > trace->syscalls.max) {
663 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
664
665 if (nsyscalls == NULL)
666 return -1;
667
668 if (trace->syscalls.max != -1) {
669 memset(nsyscalls + trace->syscalls.max + 1, 0,
670 (id - trace->syscalls.max) * sizeof(*sc));
671 } else {
672 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
673 }
674
675 trace->syscalls.table = nsyscalls;
676 trace->syscalls.max = id;
677 }
678
679 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300680 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300681
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300682 if (trace->ev_qualifier) {
683 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
684
685 if (!(in ^ trace->not_ev_qualifier)) {
686 sc->filtered = true;
687 /*
688 * No need to do read tracepoint information since this will be
689 * filtered out.
690 */
691 return 0;
692 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300693 }
694
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300695 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300696
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300697 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
698 sc->tp_format = event_format__new("syscalls", tp_name);
699
700 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
701 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
702 sc->tp_format = event_format__new("syscalls", tp_name);
703 }
704
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300705 if (sc->tp_format == NULL)
706 return -1;
707
708 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300709}
710
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300711static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
712 unsigned long *args)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300713{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300714 size_t printed = 0;
715
716 if (sc->tp_format != NULL) {
717 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300718 u8 bit = 1;
719 struct syscall_arg arg = {
720 .idx = 0,
721 .mask = 0,
722 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300723
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300724 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300725 field = field->next, ++arg.idx, bit <<= 1) {
726 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300727 continue;
728
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300729 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300730 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300731 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
732 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300733 if (sc->arg_parm)
734 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300735 printed += sc->arg_scnprintf[arg.idx](bf + printed,
736 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300737 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300738 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300739 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300740 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300741 }
742 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300743 int i = 0;
744
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300745 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300746 printed += scnprintf(bf + printed, size - printed,
747 "%sarg%d: %ld",
748 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300749 ++i;
750 }
751 }
752
753 return printed;
754}
755
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300756typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
757 struct perf_sample *sample);
758
759static struct syscall *trace__syscall_info(struct trace *trace,
760 struct perf_evsel *evsel,
761 struct perf_sample *sample)
762{
763 int id = perf_evsel__intval(evsel, sample, "id");
764
765 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -0300766
767 /*
768 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
769 * before that, leaving at a higher verbosity level till that is
770 * explained. Reproduced with plain ftrace with:
771 *
772 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
773 * grep "NR -1 " /t/trace_pipe
774 *
775 * After generating some load on the machine.
776 */
777 if (verbose > 1) {
778 static u64 n;
779 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
780 id, perf_evsel__name(evsel), ++n);
781 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300782 return NULL;
783 }
784
785 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
786 trace__read_syscall_info(trace, id))
787 goto out_cant_read;
788
789 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
790 goto out_cant_read;
791
792 return &trace->syscalls.table[id];
793
794out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -0300795 if (verbose) {
796 fprintf(trace->output, "Problems reading syscall %d", id);
797 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
798 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
799 fputs(" information\n", trace->output);
800 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300801 return NULL;
802}
803
804static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
805 struct perf_sample *sample)
806{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300807 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300808 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300809 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300810 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300811 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300812 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300813
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300814 if (sc == NULL)
815 return -1;
816
817 if (sc->filtered)
818 return 0;
819
Adrian Hunter314add62013-08-27 11:23:03 +0300820 thread = machine__findnew_thread(&trace->host, sample->pid,
821 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300822 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300823 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300824 return -1;
825
826 args = perf_evsel__rawptr(evsel, sample, "args");
827 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300828 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300829 return -1;
830 }
831
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300832 ttrace = thread->priv;
833
834 if (ttrace->entry_str == NULL) {
835 ttrace->entry_str = malloc(1024);
836 if (!ttrace->entry_str)
837 return -1;
838 }
839
840 ttrace->entry_time = sample->time;
841 msg = ttrace->entry_str;
842 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
843
844 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
845
846 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300847 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300848 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
849 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300850 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300851 } else
852 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300853
854 return 0;
855}
856
857static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
858 struct perf_sample *sample)
859{
860 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200861 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300862 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300863 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300864 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300865
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300866 if (sc == NULL)
867 return -1;
868
869 if (sc->filtered)
870 return 0;
871
Adrian Hunter314add62013-08-27 11:23:03 +0300872 thread = machine__findnew_thread(&trace->host, sample->pid,
873 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300874 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300875 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300876 return -1;
877
878 ret = perf_evsel__intval(evsel, sample, "ret");
879
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300880 ttrace = thread->priv;
881
882 ttrace->exit_time = sample->time;
883
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300884 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200885 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300886 if (trace__filter_duration(trace, duration))
887 goto out;
888 } else if (trace->duration_filter)
889 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200890
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300891 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300892
893 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300894 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300895 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300896 fprintf(trace->output, " ... [");
897 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
898 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300899 }
900
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -0300901 if (sc->fmt == NULL) {
902signed_print:
903 fprintf(trace->output, ") = %d", ret);
904 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300905 char bf[256];
906 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
907 *e = audit_errno_to_name(-ret);
908
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300909 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -0300910 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300911 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300912 else if (sc->fmt->hexret)
913 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300914 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -0300915 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300916
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300917 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300918out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300919 ttrace->entry_pending = false;
920
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300921 return 0;
922}
923
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300924static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
925 struct perf_sample *sample)
926{
927 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
928 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
Adrian Hunter314add62013-08-27 11:23:03 +0300929 struct thread *thread = machine__findnew_thread(&trace->host,
930 sample->pid,
931 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300932 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300933
934 if (ttrace == NULL)
935 goto out_dump;
936
937 ttrace->runtime_ms += runtime_ms;
938 trace->runtime_ms += runtime_ms;
939 return 0;
940
941out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300942 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300943 evsel->name,
944 perf_evsel__strval(evsel, sample, "comm"),
945 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
946 runtime,
947 perf_evsel__intval(evsel, sample, "vruntime"));
948 return 0;
949}
950
David Ahernbdc89662013-08-28 22:29:53 -0600951static bool skip_sample(struct trace *trace, struct perf_sample *sample)
952{
953 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
954 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
955 return false;
956
957 if (trace->pid_list || trace->tid_list)
958 return true;
959
960 return false;
961}
962
David Ahern6810fc92013-08-28 22:29:52 -0600963static int trace__process_sample(struct perf_tool *tool,
964 union perf_event *event __maybe_unused,
965 struct perf_sample *sample,
966 struct perf_evsel *evsel,
967 struct machine *machine __maybe_unused)
968{
969 struct trace *trace = container_of(tool, struct trace, tool);
970 int err = 0;
971
972 tracepoint_handler handler = evsel->handler.func;
973
David Ahernbdc89662013-08-28 22:29:53 -0600974 if (skip_sample(trace, sample))
975 return 0;
976
David Ahern6810fc92013-08-28 22:29:52 -0600977 if (trace->base_time == 0)
978 trace->base_time = sample->time;
979
980 if (handler)
981 handler(trace, evsel, sample);
982
983 return err;
984}
985
986static bool
987perf_session__has_tp(struct perf_session *session, const char *name)
988{
989 struct perf_evsel *evsel;
990
991 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
992
993 return evsel != NULL;
994}
995
David Ahernbdc89662013-08-28 22:29:53 -0600996static int parse_target_str(struct trace *trace)
997{
998 if (trace->opts.target.pid) {
999 trace->pid_list = intlist__new(trace->opts.target.pid);
1000 if (trace->pid_list == NULL) {
1001 pr_err("Error parsing process id string\n");
1002 return -EINVAL;
1003 }
1004 }
1005
1006 if (trace->opts.target.tid) {
1007 trace->tid_list = intlist__new(trace->opts.target.tid);
1008 if (trace->tid_list == NULL) {
1009 pr_err("Error parsing thread id string\n");
1010 return -EINVAL;
1011 }
1012 }
1013
1014 return 0;
1015}
1016
Namhyung Kimf15eb532012-10-05 14:02:16 +09001017static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001018{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001019 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001020 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001021 int err = -1, i;
1022 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001023 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001024
1025 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001026 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001027 goto out;
1028 }
1029
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001030 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1031 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001032 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001033 goto out_delete_evlist;
1034 }
1035
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001036 if (trace->sched &&
1037 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1038 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001039 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001040 goto out_delete_evlist;
1041 }
1042
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001043 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1044 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001045 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001046 goto out_delete_evlist;
1047 }
1048
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001049 err = trace__symbols_init(trace, evlist);
1050 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001051 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001052 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001053 }
1054
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001055 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001056
Namhyung Kimf15eb532012-10-05 14:02:16 +09001057 signal(SIGCHLD, sig_handler);
1058 signal(SIGINT, sig_handler);
1059
1060 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001061 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001062 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001063 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001064 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001065 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001066 }
1067 }
1068
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001069 err = perf_evlist__open(evlist);
1070 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001071 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001072 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001073 }
1074
1075 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1076 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001077 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001078 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001079 }
1080
1081 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001082
1083 if (forks)
1084 perf_evlist__start_workload(evlist);
1085
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001086 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001087again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001088 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001089
1090 for (i = 0; i < evlist->nr_mmaps; i++) {
1091 union perf_event *event;
1092
1093 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1094 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001095 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001096 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001097
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001098 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001099
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001100 err = perf_evlist__parse_sample(evlist, event, &sample);
1101 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001102 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001103 continue;
1104 }
1105
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001106 if (trace->base_time == 0)
1107 trace->base_time = sample.time;
1108
1109 if (type != PERF_RECORD_SAMPLE) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001110 trace__process_event(trace, &trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001111 continue;
1112 }
1113
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001114 evsel = perf_evlist__id2evsel(evlist, sample.id);
1115 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001116 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001117 continue;
1118 }
1119
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001120 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001121 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 -03001122 perf_evsel__name(evsel), sample.tid,
1123 sample.cpu, sample.raw_size);
1124 continue;
1125 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001126
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001127 handler = evsel->handler.func;
1128 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001129
1130 if (done)
1131 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001132 }
1133 }
1134
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001135 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001136 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001137 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001138
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001139 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001140 }
1141
1142 if (done)
1143 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001144
1145 goto again;
1146
Namhyung Kim3beb0862013-03-15 14:48:50 +09001147out_unmap_evlist:
1148 perf_evlist__munmap(evlist);
1149out_close_evlist:
1150 perf_evlist__close(evlist);
1151out_delete_maps:
1152 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001153out_delete_evlist:
1154 perf_evlist__delete(evlist);
1155out:
1156 return err;
1157}
1158
David Ahern6810fc92013-08-28 22:29:52 -06001159static int trace__replay(struct trace *trace)
1160{
1161 const struct perf_evsel_str_handler handlers[] = {
1162 { "raw_syscalls:sys_enter", trace__sys_enter, },
1163 { "raw_syscalls:sys_exit", trace__sys_exit, },
1164 };
1165
1166 struct perf_session *session;
1167 int err = -1;
1168
1169 trace->tool.sample = trace__process_sample;
1170 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001171 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001172 trace->tool.comm = perf_event__process_comm;
1173 trace->tool.exit = perf_event__process_exit;
1174 trace->tool.fork = perf_event__process_fork;
1175 trace->tool.attr = perf_event__process_attr;
1176 trace->tool.tracing_data = perf_event__process_tracing_data;
1177 trace->tool.build_id = perf_event__process_build_id;
1178
1179 trace->tool.ordered_samples = true;
1180 trace->tool.ordering_requires_timestamps = true;
1181
1182 /* add tid to output */
1183 trace->multiple_threads = true;
1184
1185 if (symbol__init() < 0)
1186 return -1;
1187
1188 session = perf_session__new(input_name, O_RDONLY, 0, false,
1189 &trace->tool);
1190 if (session == NULL)
1191 return -ENOMEM;
1192
1193 err = perf_session__set_tracepoints_handlers(session, handlers);
1194 if (err)
1195 goto out;
1196
1197 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1198 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1199 goto out;
1200 }
1201
1202 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1203 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1204 goto out;
1205 }
1206
David Ahernbdc89662013-08-28 22:29:53 -06001207 err = parse_target_str(trace);
1208 if (err != 0)
1209 goto out;
1210
David Ahern6810fc92013-08-28 22:29:52 -06001211 setup_pager();
1212
1213 err = perf_session__process_events(session, &trace->tool);
1214 if (err)
1215 pr_err("Failed to process events, error %d", err);
1216
1217out:
1218 perf_session__delete(session);
1219
1220 return err;
1221}
1222
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001223static size_t trace__fprintf_threads_header(FILE *fp)
1224{
1225 size_t printed;
1226
1227 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1228 printed += fprintf(fp," __) Summary of events (__\n\n");
1229 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1230 printed += fprintf(fp," _____________________________________________________________________\n\n");
1231
1232 return printed;
1233}
1234
1235static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1236{
1237 size_t printed = trace__fprintf_threads_header(fp);
1238 struct rb_node *nd;
1239
1240 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1241 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1242 struct thread_trace *ttrace = thread->priv;
1243 const char *color;
1244 double ratio;
1245
1246 if (ttrace == NULL)
1247 continue;
1248
1249 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1250
1251 color = PERF_COLOR_NORMAL;
1252 if (ratio > 50.0)
1253 color = PERF_COLOR_RED;
1254 else if (ratio > 25.0)
1255 color = PERF_COLOR_GREEN;
1256 else if (ratio > 5.0)
1257 color = PERF_COLOR_YELLOW;
1258
1259 printed += color_fprintf(fp, color, "%20s", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001260 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001261 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1262 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1263 }
1264
1265 return printed;
1266}
1267
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001268static int trace__set_duration(const struct option *opt, const char *str,
1269 int unset __maybe_unused)
1270{
1271 struct trace *trace = opt->value;
1272
1273 trace->duration_filter = atof(str);
1274 return 0;
1275}
1276
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001277static int trace__open_output(struct trace *trace, const char *filename)
1278{
1279 struct stat st;
1280
1281 if (!stat(filename, &st) && st.st_size) {
1282 char oldname[PATH_MAX];
1283
1284 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1285 unlink(oldname);
1286 rename(filename, oldname);
1287 }
1288
1289 trace->output = fopen(filename, "w");
1290
1291 return trace->output == NULL ? -errno : 0;
1292}
1293
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001294int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1295{
1296 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001297 "perf trace [<options>] [<command>]",
1298 "perf trace [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001299 NULL
1300 };
1301 struct trace trace = {
1302 .audit_machine = audit_detect_machine(),
1303 .syscalls = {
1304 . max = -1,
1305 },
1306 .opts = {
1307 .target = {
1308 .uid = UINT_MAX,
1309 .uses_mmap = true,
1310 },
1311 .user_freq = UINT_MAX,
1312 .user_interval = ULLONG_MAX,
1313 .no_delay = true,
1314 .mmap_pages = 1024,
1315 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001316 .output = stdout,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001317 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001318 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001319 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001320 const struct option trace_options[] = {
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001321 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1322 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001323 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001324 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001325 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1326 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001327 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001328 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001329 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001330 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001331 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001332 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001333 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001334 "child tasks do not inherit counters"),
David Ahernac9be8e2013-08-20 11:15:45 -06001335 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001336 "number of mmap data pages"),
David Ahernac9be8e2013-08-20 11:15:45 -06001337 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001338 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001339 OPT_CALLBACK(0, "duration", &trace, "float",
1340 "show only events with duration > N.M ms",
1341 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001342 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001343 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001344 OPT_END()
1345 };
1346 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001347 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001348
1349 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001350
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001351 if (output_name != NULL) {
1352 err = trace__open_output(&trace, output_name);
1353 if (err < 0) {
1354 perror("failed to create output file");
1355 goto out;
1356 }
1357 }
1358
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001359 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001360 const char *s = ev_qualifier_str;
1361
1362 trace.not_ev_qualifier = *s == '!';
1363 if (trace.not_ev_qualifier)
1364 ++s;
1365 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001366 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001367 fputs("Not enough memory to parse event qualifier",
1368 trace.output);
1369 err = -ENOMEM;
1370 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001371 }
1372 }
1373
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001374 err = perf_target__validate(&trace.opts.target);
1375 if (err) {
1376 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001377 fprintf(trace.output, "%s", bf);
1378 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001379 }
1380
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001381 err = perf_target__parse_uid(&trace.opts.target);
1382 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001383 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001384 fprintf(trace.output, "%s", bf);
1385 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001386 }
1387
Namhyung Kimf15eb532012-10-05 14:02:16 +09001388 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001389 trace.opts.target.system_wide = true;
1390
David Ahern6810fc92013-08-28 22:29:52 -06001391 if (input_name)
1392 err = trace__replay(&trace);
1393 else
1394 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001395
1396 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001397 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001398
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001399out_close:
1400 if (output_name != NULL)
1401 fclose(trace.output);
1402out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001403 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001404}