blob: 7aa6bcacd51f470ec3e42f21afdc2c3a4dcdcf3e [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 Meloa28b24b2013-09-04 11:00:44 -0300268#ifndef SOCK_TYPE_MASK
269#define SOCK_TYPE_MASK 0xf
270#endif
271
272static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
273 struct syscall_arg *arg)
274{
275 size_t printed;
276 int type = arg->val,
277 flags = type & ~SOCK_TYPE_MASK;
278
279 type &= SOCK_TYPE_MASK;
280 /*
281 * Can't use a strarray, MIPS may override for ABI reasons.
282 */
283 switch (type) {
284#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
285 P_SK_TYPE(STREAM);
286 P_SK_TYPE(DGRAM);
287 P_SK_TYPE(RAW);
288 P_SK_TYPE(RDM);
289 P_SK_TYPE(SEQPACKET);
290 P_SK_TYPE(DCCP);
291 P_SK_TYPE(PACKET);
292#undef P_SK_TYPE
293 default:
294 printed = scnprintf(bf, size, "%#x", type);
295 }
296
297#define P_SK_FLAG(n) \
298 if (flags & SOCK_##n) { \
299 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
300 flags &= ~SOCK_##n; \
301 }
302
303 P_SK_FLAG(CLOEXEC);
304 P_SK_FLAG(NONBLOCK);
305#undef P_SK_FLAG
306
307 if (flags)
308 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
309
310 return printed;
311}
312
313#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
314
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300315static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
316 struct syscall_arg *arg)
317{
318 size_t printed = 0;
319 int mode = arg->val;
320
321 if (mode == F_OK) /* 0 */
322 return scnprintf(bf, size, "F");
323#define P_MODE(n) \
324 if (mode & n##_OK) { \
325 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
326 mode &= ~n##_OK; \
327 }
328
329 P_MODE(R);
330 P_MODE(W);
331 P_MODE(X);
332#undef P_MODE
333
334 if (mode)
335 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
336
337 return printed;
338}
339
340#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
341
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300342static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300343 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300344{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300345 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300346
347 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300348 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300349
350 if (flags == 0)
351 return scnprintf(bf, size, "RDONLY");
352#define P_FLAG(n) \
353 if (flags & O_##n) { \
354 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
355 flags &= ~O_##n; \
356 }
357
358 P_FLAG(APPEND);
359 P_FLAG(ASYNC);
360 P_FLAG(CLOEXEC);
361 P_FLAG(CREAT);
362 P_FLAG(DIRECT);
363 P_FLAG(DIRECTORY);
364 P_FLAG(EXCL);
365 P_FLAG(LARGEFILE);
366 P_FLAG(NOATIME);
367 P_FLAG(NOCTTY);
368#ifdef O_NONBLOCK
369 P_FLAG(NONBLOCK);
370#elif O_NDELAY
371 P_FLAG(NDELAY);
372#endif
373#ifdef O_PATH
374 P_FLAG(PATH);
375#endif
376 P_FLAG(RDWR);
377#ifdef O_DSYNC
378 if ((flags & O_SYNC) == O_SYNC)
379 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
380 else {
381 P_FLAG(DSYNC);
382 }
383#else
384 P_FLAG(SYNC);
385#endif
386 P_FLAG(TRUNC);
387 P_FLAG(WRONLY);
388#undef P_FLAG
389
390 if (flags)
391 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
392
393 return printed;
394}
395
396#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
397
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300398static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
399{
400 int sig = arg->val;
401
402 switch (sig) {
403#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
404 P_SIGNUM(HUP);
405 P_SIGNUM(INT);
406 P_SIGNUM(QUIT);
407 P_SIGNUM(ILL);
408 P_SIGNUM(TRAP);
409 P_SIGNUM(ABRT);
410 P_SIGNUM(BUS);
411 P_SIGNUM(FPE);
412 P_SIGNUM(KILL);
413 P_SIGNUM(USR1);
414 P_SIGNUM(SEGV);
415 P_SIGNUM(USR2);
416 P_SIGNUM(PIPE);
417 P_SIGNUM(ALRM);
418 P_SIGNUM(TERM);
419 P_SIGNUM(STKFLT);
420 P_SIGNUM(CHLD);
421 P_SIGNUM(CONT);
422 P_SIGNUM(STOP);
423 P_SIGNUM(TSTP);
424 P_SIGNUM(TTIN);
425 P_SIGNUM(TTOU);
426 P_SIGNUM(URG);
427 P_SIGNUM(XCPU);
428 P_SIGNUM(XFSZ);
429 P_SIGNUM(VTALRM);
430 P_SIGNUM(PROF);
431 P_SIGNUM(WINCH);
432 P_SIGNUM(IO);
433 P_SIGNUM(PWR);
434 P_SIGNUM(SYS);
435 default: break;
436 }
437
438 return scnprintf(bf, size, "%#x", sig);
439}
440
441#define SCA_SIGNUM syscall_arg__scnprintf_signum
442
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300443static struct syscall_fmt {
444 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300445 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300446 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300447 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300448 bool errmsg;
449 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300450 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300451} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300452 { .name = "access", .errmsg = true,
453 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300454 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300455 { .name = "brk", .hexret = true,
456 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300457 { .name = "mmap", .hexret = true, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300458 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300459 { .name = "fcntl", .errmsg = true,
460 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
461 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300462 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
463 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300464 { .name = "futex", .errmsg = true,
465 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300466 { .name = "getitimer", .errmsg = true,
467 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
468 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300469 { .name = "ioctl", .errmsg = true,
470 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300471 { .name = "kill", .errmsg = true,
472 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo579e7862013-09-02 15:37:32 -0300473 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300474 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
475 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300476 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300477 { .name = "madvise", .errmsg = true,
478 .arg_scnprintf = { [0] = SCA_HEX, /* start */
479 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300480 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300481 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300482 [2] = SCA_MMAP_PROT, /* prot */
483 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300484 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300485 .arg_scnprintf = { [0] = SCA_HEX, /* start */
486 [2] = SCA_MMAP_PROT, /* prot */ }, },
487 { .name = "mremap", .hexret = true,
488 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
489 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300490 { .name = "munmap", .errmsg = true,
491 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300492 { .name = "open", .errmsg = true,
493 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300494 { .name = "open_by_handle_at", .errmsg = true,
495 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
496 { .name = "openat", .errmsg = true,
497 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300498 { .name = "poll", .errmsg = true, .timeout = true, },
499 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300500 { .name = "pread", .errmsg = true, .alias = "pread64", },
501 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300502 { .name = "read", .errmsg = true, },
503 { .name = "recvfrom", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300504 { .name = "rt_sigaction", .errmsg = true,
505 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300506 { .name = "rt_sigprocmask", .errmsg = true,
507 .arg_scnprintf = { [0] = SCA_STRARRAY, /* how */ },
508 .arg_parm = { [0] = &strarray__sighow, /* how */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300509 { .name = "rt_sigqueueinfo", .errmsg = true,
510 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
511 { .name = "rt_tgsigqueueinfo", .errmsg = true,
512 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300513 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300514 { .name = "setitimer", .errmsg = true,
515 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
516 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300517 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300518 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
519 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300520 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300521 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300522 { .name = "tgkill", .errmsg = true,
523 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
524 { .name = "tkill", .errmsg = true,
525 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300526 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300527};
528
529static int syscall_fmt__cmp(const void *name, const void *fmtp)
530{
531 const struct syscall_fmt *fmt = fmtp;
532 return strcmp(name, fmt->name);
533}
534
535static struct syscall_fmt *syscall_fmt__find(const char *name)
536{
537 const int nmemb = ARRAY_SIZE(syscall_fmts);
538 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
539}
540
541struct syscall {
542 struct event_format *tp_format;
543 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300544 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300545 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300546 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300547 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300548};
549
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200550static size_t fprintf_duration(unsigned long t, FILE *fp)
551{
552 double duration = (double)t / NSEC_PER_MSEC;
553 size_t printed = fprintf(fp, "(");
554
555 if (duration >= 1.0)
556 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
557 else if (duration >= 0.01)
558 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
559 else
560 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300561 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200562}
563
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300564struct thread_trace {
565 u64 entry_time;
566 u64 exit_time;
567 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300568 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300569 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300570 double runtime_ms;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300571};
572
573static struct thread_trace *thread_trace__new(void)
574{
575 return zalloc(sizeof(struct thread_trace));
576}
577
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300578static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300579{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300580 struct thread_trace *ttrace;
581
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300582 if (thread == NULL)
583 goto fail;
584
585 if (thread->priv == NULL)
586 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300587
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300588 if (thread->priv == NULL)
589 goto fail;
590
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300591 ttrace = thread->priv;
592 ++ttrace->nr_events;
593
594 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300595fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300596 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300597 "WARNING: not enough memory, dropping samples!\n");
598 return NULL;
599}
600
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300601struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300602 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300603 int audit_machine;
604 struct {
605 int max;
606 struct syscall *table;
607 } syscalls;
608 struct perf_record_opts opts;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300609 struct machine host;
610 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300611 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300612 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300613 struct strlist *ev_qualifier;
614 bool not_ev_qualifier;
David Ahernbdc89662013-08-28 22:29:53 -0600615 struct intlist *tid_list;
616 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300617 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300618 bool multiple_threads;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300619 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300620 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300621};
622
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300623static bool trace__filter_duration(struct trace *trace, double t)
624{
625 return t < (trace->duration_filter * NSEC_PER_MSEC);
626}
627
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300628static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
629{
630 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
631
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200632 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300633}
634
Namhyung Kimf15eb532012-10-05 14:02:16 +0900635static bool done = false;
636
637static void sig_handler(int sig __maybe_unused)
638{
639 done = true;
640}
641
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300642static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200643 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300644{
645 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200646 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300647
648 if (trace->multiple_threads)
Adrian Hunter38051232013-07-04 16:20:31 +0300649 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300650
651 return printed;
652}
653
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300654static int trace__process_event(struct trace *trace, struct machine *machine,
655 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300656{
657 int ret = 0;
658
659 switch (event->header.type) {
660 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300661 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300662 "LOST %" PRIu64 " events!\n", event->lost.lost);
663 ret = machine__process_lost_event(machine, event);
664 default:
665 ret = machine__process_event(machine, event);
666 break;
667 }
668
669 return ret;
670}
671
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300672static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300673 union perf_event *event,
674 struct perf_sample *sample __maybe_unused,
675 struct machine *machine)
676{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300677 struct trace *trace = container_of(tool, struct trace, tool);
678 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300679}
680
681static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
682{
683 int err = symbol__init();
684
685 if (err)
686 return err;
687
688 machine__init(&trace->host, "", HOST_KERNEL_ID);
689 machine__create_kernel_maps(&trace->host);
690
691 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300692 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300693 trace__tool_process,
694 &trace->host);
695 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300696 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300697 &trace->host);
698 }
699
700 if (err)
701 symbol__exit();
702
703 return err;
704}
705
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300706static int syscall__set_arg_fmts(struct syscall *sc)
707{
708 struct format_field *field;
709 int idx = 0;
710
711 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
712 if (sc->arg_scnprintf == NULL)
713 return -1;
714
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300715 if (sc->fmt)
716 sc->arg_parm = sc->fmt->arg_parm;
717
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300718 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300719 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
720 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
721 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300722 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
723 ++idx;
724 }
725
726 return 0;
727}
728
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300729static int trace__read_syscall_info(struct trace *trace, int id)
730{
731 char tp_name[128];
732 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300733 const char *name = audit_syscall_to_name(id, trace->audit_machine);
734
735 if (name == NULL)
736 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300737
738 if (id > trace->syscalls.max) {
739 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
740
741 if (nsyscalls == NULL)
742 return -1;
743
744 if (trace->syscalls.max != -1) {
745 memset(nsyscalls + trace->syscalls.max + 1, 0,
746 (id - trace->syscalls.max) * sizeof(*sc));
747 } else {
748 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
749 }
750
751 trace->syscalls.table = nsyscalls;
752 trace->syscalls.max = id;
753 }
754
755 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300756 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300757
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300758 if (trace->ev_qualifier) {
759 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
760
761 if (!(in ^ trace->not_ev_qualifier)) {
762 sc->filtered = true;
763 /*
764 * No need to do read tracepoint information since this will be
765 * filtered out.
766 */
767 return 0;
768 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300769 }
770
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300771 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300772
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300773 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
774 sc->tp_format = event_format__new("syscalls", tp_name);
775
776 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
777 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
778 sc->tp_format = event_format__new("syscalls", tp_name);
779 }
780
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300781 if (sc->tp_format == NULL)
782 return -1;
783
784 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300785}
786
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300787static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
788 unsigned long *args)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300789{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300790 size_t printed = 0;
791
792 if (sc->tp_format != NULL) {
793 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300794 u8 bit = 1;
795 struct syscall_arg arg = {
796 .idx = 0,
797 .mask = 0,
798 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300799
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300800 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300801 field = field->next, ++arg.idx, bit <<= 1) {
802 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300803 continue;
804
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300805 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300806 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300807 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
808 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300809 if (sc->arg_parm)
810 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300811 printed += sc->arg_scnprintf[arg.idx](bf + printed,
812 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300813 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300814 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300815 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300816 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300817 }
818 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300819 int i = 0;
820
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300821 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300822 printed += scnprintf(bf + printed, size - printed,
823 "%sarg%d: %ld",
824 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300825 ++i;
826 }
827 }
828
829 return printed;
830}
831
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300832typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
833 struct perf_sample *sample);
834
835static struct syscall *trace__syscall_info(struct trace *trace,
836 struct perf_evsel *evsel,
837 struct perf_sample *sample)
838{
839 int id = perf_evsel__intval(evsel, sample, "id");
840
841 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -0300842
843 /*
844 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
845 * before that, leaving at a higher verbosity level till that is
846 * explained. Reproduced with plain ftrace with:
847 *
848 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
849 * grep "NR -1 " /t/trace_pipe
850 *
851 * After generating some load on the machine.
852 */
853 if (verbose > 1) {
854 static u64 n;
855 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
856 id, perf_evsel__name(evsel), ++n);
857 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300858 return NULL;
859 }
860
861 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
862 trace__read_syscall_info(trace, id))
863 goto out_cant_read;
864
865 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
866 goto out_cant_read;
867
868 return &trace->syscalls.table[id];
869
870out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -0300871 if (verbose) {
872 fprintf(trace->output, "Problems reading syscall %d", id);
873 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
874 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
875 fputs(" information\n", trace->output);
876 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300877 return NULL;
878}
879
880static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
881 struct perf_sample *sample)
882{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300883 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300884 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300885 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300886 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300887 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300888 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300889
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300890 if (sc == NULL)
891 return -1;
892
893 if (sc->filtered)
894 return 0;
895
Adrian Hunter314add62013-08-27 11:23:03 +0300896 thread = machine__findnew_thread(&trace->host, sample->pid,
897 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300898 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300899 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300900 return -1;
901
902 args = perf_evsel__rawptr(evsel, sample, "args");
903 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300904 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300905 return -1;
906 }
907
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300908 ttrace = thread->priv;
909
910 if (ttrace->entry_str == NULL) {
911 ttrace->entry_str = malloc(1024);
912 if (!ttrace->entry_str)
913 return -1;
914 }
915
916 ttrace->entry_time = sample->time;
917 msg = ttrace->entry_str;
918 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
919
920 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
921
922 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300923 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300924 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
925 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300926 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300927 } else
928 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300929
930 return 0;
931}
932
933static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
934 struct perf_sample *sample)
935{
936 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200937 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300938 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300939 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300940 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300941
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300942 if (sc == NULL)
943 return -1;
944
945 if (sc->filtered)
946 return 0;
947
Adrian Hunter314add62013-08-27 11:23:03 +0300948 thread = machine__findnew_thread(&trace->host, sample->pid,
949 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300950 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300951 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300952 return -1;
953
954 ret = perf_evsel__intval(evsel, sample, "ret");
955
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300956 ttrace = thread->priv;
957
958 ttrace->exit_time = sample->time;
959
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300960 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200961 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300962 if (trace__filter_duration(trace, duration))
963 goto out;
964 } else if (trace->duration_filter)
965 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200966
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300967 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300968
969 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300970 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300971 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300972 fprintf(trace->output, " ... [");
973 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
974 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300975 }
976
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -0300977 if (sc->fmt == NULL) {
978signed_print:
979 fprintf(trace->output, ") = %d", ret);
980 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300981 char bf[256];
982 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
983 *e = audit_errno_to_name(-ret);
984
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300985 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -0300986 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300987 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300988 else if (sc->fmt->hexret)
989 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300990 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -0300991 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300992
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300993 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300994out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300995 ttrace->entry_pending = false;
996
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300997 return 0;
998}
999
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001000static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1001 struct perf_sample *sample)
1002{
1003 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1004 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
Adrian Hunter314add62013-08-27 11:23:03 +03001005 struct thread *thread = machine__findnew_thread(&trace->host,
1006 sample->pid,
1007 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001008 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001009
1010 if (ttrace == NULL)
1011 goto out_dump;
1012
1013 ttrace->runtime_ms += runtime_ms;
1014 trace->runtime_ms += runtime_ms;
1015 return 0;
1016
1017out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001018 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001019 evsel->name,
1020 perf_evsel__strval(evsel, sample, "comm"),
1021 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1022 runtime,
1023 perf_evsel__intval(evsel, sample, "vruntime"));
1024 return 0;
1025}
1026
David Ahernbdc89662013-08-28 22:29:53 -06001027static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1028{
1029 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1030 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1031 return false;
1032
1033 if (trace->pid_list || trace->tid_list)
1034 return true;
1035
1036 return false;
1037}
1038
David Ahern6810fc92013-08-28 22:29:52 -06001039static int trace__process_sample(struct perf_tool *tool,
1040 union perf_event *event __maybe_unused,
1041 struct perf_sample *sample,
1042 struct perf_evsel *evsel,
1043 struct machine *machine __maybe_unused)
1044{
1045 struct trace *trace = container_of(tool, struct trace, tool);
1046 int err = 0;
1047
1048 tracepoint_handler handler = evsel->handler.func;
1049
David Ahernbdc89662013-08-28 22:29:53 -06001050 if (skip_sample(trace, sample))
1051 return 0;
1052
David Ahern6810fc92013-08-28 22:29:52 -06001053 if (trace->base_time == 0)
1054 trace->base_time = sample->time;
1055
1056 if (handler)
1057 handler(trace, evsel, sample);
1058
1059 return err;
1060}
1061
1062static bool
1063perf_session__has_tp(struct perf_session *session, const char *name)
1064{
1065 struct perf_evsel *evsel;
1066
1067 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1068
1069 return evsel != NULL;
1070}
1071
David Ahernbdc89662013-08-28 22:29:53 -06001072static int parse_target_str(struct trace *trace)
1073{
1074 if (trace->opts.target.pid) {
1075 trace->pid_list = intlist__new(trace->opts.target.pid);
1076 if (trace->pid_list == NULL) {
1077 pr_err("Error parsing process id string\n");
1078 return -EINVAL;
1079 }
1080 }
1081
1082 if (trace->opts.target.tid) {
1083 trace->tid_list = intlist__new(trace->opts.target.tid);
1084 if (trace->tid_list == NULL) {
1085 pr_err("Error parsing thread id string\n");
1086 return -EINVAL;
1087 }
1088 }
1089
1090 return 0;
1091}
1092
Namhyung Kimf15eb532012-10-05 14:02:16 +09001093static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001094{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001095 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001096 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001097 int err = -1, i;
1098 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001099 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001100
1101 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001102 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001103 goto out;
1104 }
1105
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001106 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1107 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001108 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001109 goto out_delete_evlist;
1110 }
1111
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001112 if (trace->sched &&
1113 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1114 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001115 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001116 goto out_delete_evlist;
1117 }
1118
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001119 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1120 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001121 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001122 goto out_delete_evlist;
1123 }
1124
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001125 err = trace__symbols_init(trace, evlist);
1126 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001127 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001128 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001129 }
1130
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001131 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001132
Namhyung Kimf15eb532012-10-05 14:02:16 +09001133 signal(SIGCHLD, sig_handler);
1134 signal(SIGINT, sig_handler);
1135
1136 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001137 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001138 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001139 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001140 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001141 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001142 }
1143 }
1144
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001145 err = perf_evlist__open(evlist);
1146 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001147 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001148 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001149 }
1150
1151 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1152 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001153 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001154 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001155 }
1156
1157 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001158
1159 if (forks)
1160 perf_evlist__start_workload(evlist);
1161
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001162 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001163again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001164 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001165
1166 for (i = 0; i < evlist->nr_mmaps; i++) {
1167 union perf_event *event;
1168
1169 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1170 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001171 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001172 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001173
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001174 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001175
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001176 err = perf_evlist__parse_sample(evlist, event, &sample);
1177 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001178 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001179 continue;
1180 }
1181
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001182 if (trace->base_time == 0)
1183 trace->base_time = sample.time;
1184
1185 if (type != PERF_RECORD_SAMPLE) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001186 trace__process_event(trace, &trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001187 continue;
1188 }
1189
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001190 evsel = perf_evlist__id2evsel(evlist, sample.id);
1191 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001192 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001193 continue;
1194 }
1195
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001196 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001197 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 -03001198 perf_evsel__name(evsel), sample.tid,
1199 sample.cpu, sample.raw_size);
1200 continue;
1201 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001202
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001203 handler = evsel->handler.func;
1204 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001205
1206 if (done)
1207 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001208 }
1209 }
1210
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001211 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001212 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001213 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001214
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001215 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001216 }
1217
1218 if (done)
1219 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001220
1221 goto again;
1222
Namhyung Kim3beb0862013-03-15 14:48:50 +09001223out_unmap_evlist:
1224 perf_evlist__munmap(evlist);
1225out_close_evlist:
1226 perf_evlist__close(evlist);
1227out_delete_maps:
1228 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001229out_delete_evlist:
1230 perf_evlist__delete(evlist);
1231out:
1232 return err;
1233}
1234
David Ahern6810fc92013-08-28 22:29:52 -06001235static int trace__replay(struct trace *trace)
1236{
1237 const struct perf_evsel_str_handler handlers[] = {
1238 { "raw_syscalls:sys_enter", trace__sys_enter, },
1239 { "raw_syscalls:sys_exit", trace__sys_exit, },
1240 };
1241
1242 struct perf_session *session;
1243 int err = -1;
1244
1245 trace->tool.sample = trace__process_sample;
1246 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001247 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001248 trace->tool.comm = perf_event__process_comm;
1249 trace->tool.exit = perf_event__process_exit;
1250 trace->tool.fork = perf_event__process_fork;
1251 trace->tool.attr = perf_event__process_attr;
1252 trace->tool.tracing_data = perf_event__process_tracing_data;
1253 trace->tool.build_id = perf_event__process_build_id;
1254
1255 trace->tool.ordered_samples = true;
1256 trace->tool.ordering_requires_timestamps = true;
1257
1258 /* add tid to output */
1259 trace->multiple_threads = true;
1260
1261 if (symbol__init() < 0)
1262 return -1;
1263
1264 session = perf_session__new(input_name, O_RDONLY, 0, false,
1265 &trace->tool);
1266 if (session == NULL)
1267 return -ENOMEM;
1268
1269 err = perf_session__set_tracepoints_handlers(session, handlers);
1270 if (err)
1271 goto out;
1272
1273 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1274 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1275 goto out;
1276 }
1277
1278 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1279 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1280 goto out;
1281 }
1282
David Ahernbdc89662013-08-28 22:29:53 -06001283 err = parse_target_str(trace);
1284 if (err != 0)
1285 goto out;
1286
David Ahern6810fc92013-08-28 22:29:52 -06001287 setup_pager();
1288
1289 err = perf_session__process_events(session, &trace->tool);
1290 if (err)
1291 pr_err("Failed to process events, error %d", err);
1292
1293out:
1294 perf_session__delete(session);
1295
1296 return err;
1297}
1298
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001299static size_t trace__fprintf_threads_header(FILE *fp)
1300{
1301 size_t printed;
1302
1303 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1304 printed += fprintf(fp," __) Summary of events (__\n\n");
1305 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1306 printed += fprintf(fp," _____________________________________________________________________\n\n");
1307
1308 return printed;
1309}
1310
1311static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1312{
1313 size_t printed = trace__fprintf_threads_header(fp);
1314 struct rb_node *nd;
1315
1316 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1317 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1318 struct thread_trace *ttrace = thread->priv;
1319 const char *color;
1320 double ratio;
1321
1322 if (ttrace == NULL)
1323 continue;
1324
1325 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1326
1327 color = PERF_COLOR_NORMAL;
1328 if (ratio > 50.0)
1329 color = PERF_COLOR_RED;
1330 else if (ratio > 25.0)
1331 color = PERF_COLOR_GREEN;
1332 else if (ratio > 5.0)
1333 color = PERF_COLOR_YELLOW;
1334
1335 printed += color_fprintf(fp, color, "%20s", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001336 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001337 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1338 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1339 }
1340
1341 return printed;
1342}
1343
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001344static int trace__set_duration(const struct option *opt, const char *str,
1345 int unset __maybe_unused)
1346{
1347 struct trace *trace = opt->value;
1348
1349 trace->duration_filter = atof(str);
1350 return 0;
1351}
1352
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001353static int trace__open_output(struct trace *trace, const char *filename)
1354{
1355 struct stat st;
1356
1357 if (!stat(filename, &st) && st.st_size) {
1358 char oldname[PATH_MAX];
1359
1360 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1361 unlink(oldname);
1362 rename(filename, oldname);
1363 }
1364
1365 trace->output = fopen(filename, "w");
1366
1367 return trace->output == NULL ? -errno : 0;
1368}
1369
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001370int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1371{
1372 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001373 "perf trace [<options>] [<command>]",
1374 "perf trace [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001375 NULL
1376 };
1377 struct trace trace = {
1378 .audit_machine = audit_detect_machine(),
1379 .syscalls = {
1380 . max = -1,
1381 },
1382 .opts = {
1383 .target = {
1384 .uid = UINT_MAX,
1385 .uses_mmap = true,
1386 },
1387 .user_freq = UINT_MAX,
1388 .user_interval = ULLONG_MAX,
1389 .no_delay = true,
1390 .mmap_pages = 1024,
1391 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001392 .output = stdout,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001393 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001394 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001395 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001396 const struct option trace_options[] = {
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001397 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1398 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001399 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001400 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001401 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1402 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001403 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001404 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001405 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001406 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001407 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001408 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001409 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001410 "child tasks do not inherit counters"),
David Ahernac9be8e2013-08-20 11:15:45 -06001411 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001412 "number of mmap data pages"),
David Ahernac9be8e2013-08-20 11:15:45 -06001413 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001414 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001415 OPT_CALLBACK(0, "duration", &trace, "float",
1416 "show only events with duration > N.M ms",
1417 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001418 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001419 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001420 OPT_END()
1421 };
1422 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001423 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001424
1425 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001426
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001427 if (output_name != NULL) {
1428 err = trace__open_output(&trace, output_name);
1429 if (err < 0) {
1430 perror("failed to create output file");
1431 goto out;
1432 }
1433 }
1434
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001435 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001436 const char *s = ev_qualifier_str;
1437
1438 trace.not_ev_qualifier = *s == '!';
1439 if (trace.not_ev_qualifier)
1440 ++s;
1441 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001442 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001443 fputs("Not enough memory to parse event qualifier",
1444 trace.output);
1445 err = -ENOMEM;
1446 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001447 }
1448 }
1449
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001450 err = perf_target__validate(&trace.opts.target);
1451 if (err) {
1452 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001453 fprintf(trace.output, "%s", bf);
1454 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001455 }
1456
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001457 err = perf_target__parse_uid(&trace.opts.target);
1458 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001459 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001460 fprintf(trace.output, "%s", bf);
1461 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001462 }
1463
Namhyung Kimf15eb532012-10-05 14:02:16 +09001464 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001465 trace.opts.target.system_wide = true;
1466
David Ahern6810fc92013-08-28 22:29:52 -06001467 if (input_name)
1468 err = trace__replay(&trace);
1469 else
1470 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001471
1472 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001473 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001474
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001475out_close:
1476 if (output_name != NULL)
1477 fclose(trace.output);
1478out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001479 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001480}