blob: 516f6b39b4b667fd15ad6dcd110e170b5b0c0a92 [file] [log] [blame]
Robert Richter4e319022013-06-11 17:29:18 +02001#include <traceevent/event-parse.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03003#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03004#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03005#include "util/evlist.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03006#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -06007#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03008#include "util/thread.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03009#include "util/parse-options.h"
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030010#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060011#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030012#include "util/thread_map.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030013
14#include <libaudit.h>
15#include <stdlib.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030016#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030017#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030018
Ingo Molnar456857b2013-09-12 15:29:00 +020019/* For older distros: */
20#ifndef MAP_STACK
21# define MAP_STACK 0x20000
22#endif
23
24#ifndef MADV_HWPOISON
25# define MADV_HWPOISON 100
26#endif
27
28#ifndef MADV_MERGEABLE
29# define MADV_MERGEABLE 12
30#endif
31
32#ifndef MADV_UNMERGEABLE
33# define MADV_UNMERGEABLE 13
34#endif
35
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030036struct syscall_arg {
37 unsigned long val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030038 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030039 u8 idx;
40 u8 mask;
41};
42
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030043struct strarray {
44 int nr_entries;
45 const char **entries;
46};
47
48#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
49 .nr_entries = ARRAY_SIZE(array), \
50 .entries = array, \
51}
52
53static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
54 struct syscall_arg *arg)
55{
56 int idx = arg->val;
57 struct strarray *sa = arg->parm;
58
59 if (idx < 0 || idx >= sa->nr_entries)
60 return scnprintf(bf, size, "%d", idx);
61
62 return scnprintf(bf, size, "%s", sa->entries[idx]);
63}
64
65#define SCA_STRARRAY syscall_arg__scnprintf_strarray
66
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -030067static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030068 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030069{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030070 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030071}
72
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -030073#define SCA_HEX syscall_arg__scnprintf_hex
74
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -030075static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030076 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030077{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030078 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030079
80 if (prot == PROT_NONE)
81 return scnprintf(bf, size, "NONE");
82#define P_MMAP_PROT(n) \
83 if (prot & PROT_##n) { \
84 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
85 prot &= ~PROT_##n; \
86 }
87
88 P_MMAP_PROT(EXEC);
89 P_MMAP_PROT(READ);
90 P_MMAP_PROT(WRITE);
91#ifdef PROT_SEM
92 P_MMAP_PROT(SEM);
93#endif
94 P_MMAP_PROT(GROWSDOWN);
95 P_MMAP_PROT(GROWSUP);
96#undef P_MMAP_PROT
97
98 if (prot)
99 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
100
101 return printed;
102}
103
104#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
105
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300106static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300107 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300108{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300109 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300110
111#define P_MMAP_FLAG(n) \
112 if (flags & MAP_##n) { \
113 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
114 flags &= ~MAP_##n; \
115 }
116
117 P_MMAP_FLAG(SHARED);
118 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400119#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300120 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400121#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300122 P_MMAP_FLAG(ANONYMOUS);
123 P_MMAP_FLAG(DENYWRITE);
124 P_MMAP_FLAG(EXECUTABLE);
125 P_MMAP_FLAG(FILE);
126 P_MMAP_FLAG(FIXED);
127 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600128#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300129 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600130#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300131 P_MMAP_FLAG(LOCKED);
132 P_MMAP_FLAG(NONBLOCK);
133 P_MMAP_FLAG(NORESERVE);
134 P_MMAP_FLAG(POPULATE);
135 P_MMAP_FLAG(STACK);
136#ifdef MAP_UNINITIALIZED
137 P_MMAP_FLAG(UNINITIALIZED);
138#endif
139#undef P_MMAP_FLAG
140
141 if (flags)
142 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
143
144 return printed;
145}
146
147#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
148
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300149static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300150 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300151{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300152 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300153
154 switch (behavior) {
155#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
156 P_MADV_BHV(NORMAL);
157 P_MADV_BHV(RANDOM);
158 P_MADV_BHV(SEQUENTIAL);
159 P_MADV_BHV(WILLNEED);
160 P_MADV_BHV(DONTNEED);
161 P_MADV_BHV(REMOVE);
162 P_MADV_BHV(DONTFORK);
163 P_MADV_BHV(DOFORK);
164 P_MADV_BHV(HWPOISON);
165#ifdef MADV_SOFT_OFFLINE
166 P_MADV_BHV(SOFT_OFFLINE);
167#endif
168 P_MADV_BHV(MERGEABLE);
169 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600170#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300171 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600172#endif
173#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300174 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600175#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300176#ifdef MADV_DONTDUMP
177 P_MADV_BHV(DONTDUMP);
178#endif
179#ifdef MADV_DODUMP
180 P_MADV_BHV(DODUMP);
181#endif
182#undef P_MADV_PHV
183 default: break;
184 }
185
186 return scnprintf(bf, size, "%#x", behavior);
187}
188
189#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
190
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300191static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300192{
193 enum syscall_futex_args {
194 SCF_UADDR = (1 << 0),
195 SCF_OP = (1 << 1),
196 SCF_VAL = (1 << 2),
197 SCF_TIMEOUT = (1 << 3),
198 SCF_UADDR2 = (1 << 4),
199 SCF_VAL3 = (1 << 5),
200 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300201 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300202 int cmd = op & FUTEX_CMD_MASK;
203 size_t printed = 0;
204
205 switch (cmd) {
206#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300207 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
208 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
209 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
210 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
211 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
212 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300213 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300214 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
215 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
216 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
217 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
218 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300219 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
220 default: printed = scnprintf(bf, size, "%#x", cmd); break;
221 }
222
223 if (op & FUTEX_PRIVATE_FLAG)
224 printed += scnprintf(bf + printed, size - printed, "|PRIV");
225
226 if (op & FUTEX_CLOCK_REALTIME)
227 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
228
229 return printed;
230}
231
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300232#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
233
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300234static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
235static DEFINE_STRARRAY(itimers);
236
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300237static const char *whences[] = { "SET", "CUR", "END",
238#ifdef SEEK_DATA
239"DATA",
240#endif
241#ifdef SEEK_HOLE
242"HOLE",
243#endif
244};
245static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300246
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300247static const char *fcntl_cmds[] = {
248 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
249 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
250 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
251 "F_GETOWNER_UIDS",
252};
253static DEFINE_STRARRAY(fcntl_cmds);
254
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300255static const char *rlimit_resources[] = {
256 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
257 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
258 "RTTIME",
259};
260static DEFINE_STRARRAY(rlimit_resources);
261
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300262static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
263static DEFINE_STRARRAY(sighow);
264
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300265static const char *socket_families[] = {
266 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
267 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
268 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
269 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
270 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
271 "ALG", "NFC", "VSOCK",
272};
273static DEFINE_STRARRAY(socket_families);
274
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300275#ifndef SOCK_TYPE_MASK
276#define SOCK_TYPE_MASK 0xf
277#endif
278
279static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
280 struct syscall_arg *arg)
281{
282 size_t printed;
283 int type = arg->val,
284 flags = type & ~SOCK_TYPE_MASK;
285
286 type &= SOCK_TYPE_MASK;
287 /*
288 * Can't use a strarray, MIPS may override for ABI reasons.
289 */
290 switch (type) {
291#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
292 P_SK_TYPE(STREAM);
293 P_SK_TYPE(DGRAM);
294 P_SK_TYPE(RAW);
295 P_SK_TYPE(RDM);
296 P_SK_TYPE(SEQPACKET);
297 P_SK_TYPE(DCCP);
298 P_SK_TYPE(PACKET);
299#undef P_SK_TYPE
300 default:
301 printed = scnprintf(bf, size, "%#x", type);
302 }
303
304#define P_SK_FLAG(n) \
305 if (flags & SOCK_##n) { \
306 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
307 flags &= ~SOCK_##n; \
308 }
309
310 P_SK_FLAG(CLOEXEC);
311 P_SK_FLAG(NONBLOCK);
312#undef P_SK_FLAG
313
314 if (flags)
315 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
316
317 return printed;
318}
319
320#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
321
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300322static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
323 struct syscall_arg *arg)
324{
325 size_t printed = 0;
326 int mode = arg->val;
327
328 if (mode == F_OK) /* 0 */
329 return scnprintf(bf, size, "F");
330#define P_MODE(n) \
331 if (mode & n##_OK) { \
332 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
333 mode &= ~n##_OK; \
334 }
335
336 P_MODE(R);
337 P_MODE(W);
338 P_MODE(X);
339#undef P_MODE
340
341 if (mode)
342 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
343
344 return printed;
345}
346
347#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
348
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300349static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300350 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300351{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300352 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300353
354 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300355 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300356
357 if (flags == 0)
358 return scnprintf(bf, size, "RDONLY");
359#define P_FLAG(n) \
360 if (flags & O_##n) { \
361 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
362 flags &= ~O_##n; \
363 }
364
365 P_FLAG(APPEND);
366 P_FLAG(ASYNC);
367 P_FLAG(CLOEXEC);
368 P_FLAG(CREAT);
369 P_FLAG(DIRECT);
370 P_FLAG(DIRECTORY);
371 P_FLAG(EXCL);
372 P_FLAG(LARGEFILE);
373 P_FLAG(NOATIME);
374 P_FLAG(NOCTTY);
375#ifdef O_NONBLOCK
376 P_FLAG(NONBLOCK);
377#elif O_NDELAY
378 P_FLAG(NDELAY);
379#endif
380#ifdef O_PATH
381 P_FLAG(PATH);
382#endif
383 P_FLAG(RDWR);
384#ifdef O_DSYNC
385 if ((flags & O_SYNC) == O_SYNC)
386 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
387 else {
388 P_FLAG(DSYNC);
389 }
390#else
391 P_FLAG(SYNC);
392#endif
393 P_FLAG(TRUNC);
394 P_FLAG(WRONLY);
395#undef P_FLAG
396
397 if (flags)
398 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
399
400 return printed;
401}
402
403#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
404
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300405static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
406{
407 int sig = arg->val;
408
409 switch (sig) {
410#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
411 P_SIGNUM(HUP);
412 P_SIGNUM(INT);
413 P_SIGNUM(QUIT);
414 P_SIGNUM(ILL);
415 P_SIGNUM(TRAP);
416 P_SIGNUM(ABRT);
417 P_SIGNUM(BUS);
418 P_SIGNUM(FPE);
419 P_SIGNUM(KILL);
420 P_SIGNUM(USR1);
421 P_SIGNUM(SEGV);
422 P_SIGNUM(USR2);
423 P_SIGNUM(PIPE);
424 P_SIGNUM(ALRM);
425 P_SIGNUM(TERM);
426 P_SIGNUM(STKFLT);
427 P_SIGNUM(CHLD);
428 P_SIGNUM(CONT);
429 P_SIGNUM(STOP);
430 P_SIGNUM(TSTP);
431 P_SIGNUM(TTIN);
432 P_SIGNUM(TTOU);
433 P_SIGNUM(URG);
434 P_SIGNUM(XCPU);
435 P_SIGNUM(XFSZ);
436 P_SIGNUM(VTALRM);
437 P_SIGNUM(PROF);
438 P_SIGNUM(WINCH);
439 P_SIGNUM(IO);
440 P_SIGNUM(PWR);
441 P_SIGNUM(SYS);
442 default: break;
443 }
444
445 return scnprintf(bf, size, "%#x", sig);
446}
447
448#define SCA_SIGNUM syscall_arg__scnprintf_signum
449
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300450static struct syscall_fmt {
451 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300452 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300453 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300454 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300455 bool errmsg;
456 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300457 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300458} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300459 { .name = "access", .errmsg = true,
460 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300461 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300462 { .name = "brk", .hexret = true,
463 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300464 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300465 { .name = "fcntl", .errmsg = true,
466 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
467 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300468 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
469 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300470 { .name = "futex", .errmsg = true,
471 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300472 { .name = "getitimer", .errmsg = true,
473 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
474 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300475 { .name = "getrlimit", .errmsg = true,
476 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
477 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300478 { .name = "ioctl", .errmsg = true,
479 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300480 { .name = "kill", .errmsg = true,
481 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo579e7862013-09-02 15:37:32 -0300482 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300483 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
484 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300485 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300486 { .name = "madvise", .errmsg = true,
487 .arg_scnprintf = { [0] = SCA_HEX, /* start */
488 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300489 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300490 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300491 [2] = SCA_MMAP_PROT, /* prot */
492 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300493 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300494 .arg_scnprintf = { [0] = SCA_HEX, /* start */
495 [2] = SCA_MMAP_PROT, /* prot */ }, },
496 { .name = "mremap", .hexret = true,
497 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
498 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300499 { .name = "munmap", .errmsg = true,
500 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300501 { .name = "open", .errmsg = true,
502 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300503 { .name = "open_by_handle_at", .errmsg = true,
504 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
505 { .name = "openat", .errmsg = true,
506 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300507 { .name = "poll", .errmsg = true, .timeout = true, },
508 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300509 { .name = "pread", .errmsg = true, .alias = "pread64", },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300510 { .name = "prlimit64", .errmsg = true,
511 .arg_scnprintf = { [1] = SCA_STRARRAY, /* resource */ },
512 .arg_parm = { [1] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300513 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300514 { .name = "read", .errmsg = true, },
515 { .name = "recvfrom", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300516 { .name = "rt_sigaction", .errmsg = true,
517 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300518 { .name = "rt_sigprocmask", .errmsg = true,
519 .arg_scnprintf = { [0] = SCA_STRARRAY, /* how */ },
520 .arg_parm = { [0] = &strarray__sighow, /* how */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300521 { .name = "rt_sigqueueinfo", .errmsg = true,
522 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
523 { .name = "rt_tgsigqueueinfo", .errmsg = true,
524 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300525 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300526 { .name = "setitimer", .errmsg = true,
527 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
528 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300529 { .name = "setrlimit", .errmsg = true,
530 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
531 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300532 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300533 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
534 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300535 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300536 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300537 { .name = "tgkill", .errmsg = true,
538 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
539 { .name = "tkill", .errmsg = true,
540 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300541 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300542};
543
544static int syscall_fmt__cmp(const void *name, const void *fmtp)
545{
546 const struct syscall_fmt *fmt = fmtp;
547 return strcmp(name, fmt->name);
548}
549
550static struct syscall_fmt *syscall_fmt__find(const char *name)
551{
552 const int nmemb = ARRAY_SIZE(syscall_fmts);
553 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
554}
555
556struct syscall {
557 struct event_format *tp_format;
558 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300559 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300560 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300561 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300562 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300563};
564
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200565static size_t fprintf_duration(unsigned long t, FILE *fp)
566{
567 double duration = (double)t / NSEC_PER_MSEC;
568 size_t printed = fprintf(fp, "(");
569
570 if (duration >= 1.0)
571 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
572 else if (duration >= 0.01)
573 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
574 else
575 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300576 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200577}
578
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300579struct thread_trace {
580 u64 entry_time;
581 u64 exit_time;
582 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300583 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300584 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300585 double runtime_ms;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300586};
587
588static struct thread_trace *thread_trace__new(void)
589{
590 return zalloc(sizeof(struct thread_trace));
591}
592
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300593static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300594{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300595 struct thread_trace *ttrace;
596
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300597 if (thread == NULL)
598 goto fail;
599
600 if (thread->priv == NULL)
601 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300602
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300603 if (thread->priv == NULL)
604 goto fail;
605
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300606 ttrace = thread->priv;
607 ++ttrace->nr_events;
608
609 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300610fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300611 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300612 "WARNING: not enough memory, dropping samples!\n");
613 return NULL;
614}
615
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300616struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300617 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300618 int audit_machine;
619 struct {
620 int max;
621 struct syscall *table;
622 } syscalls;
623 struct perf_record_opts opts;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300624 struct machine host;
625 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600626 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300627 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300628 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300629 struct strlist *ev_qualifier;
630 bool not_ev_qualifier;
David Ahernbdc89662013-08-28 22:29:53 -0600631 struct intlist *tid_list;
632 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300633 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300634 bool multiple_threads;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300635 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300636 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300637};
638
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300639static bool trace__filter_duration(struct trace *trace, double t)
640{
641 return t < (trace->duration_filter * NSEC_PER_MSEC);
642}
643
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300644static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
645{
646 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
647
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200648 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300649}
650
Namhyung Kimf15eb532012-10-05 14:02:16 +0900651static bool done = false;
652
653static void sig_handler(int sig __maybe_unused)
654{
655 done = true;
656}
657
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300658static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200659 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300660{
661 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200662 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300663
664 if (trace->multiple_threads)
Adrian Hunter38051232013-07-04 16:20:31 +0300665 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300666
667 return printed;
668}
669
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300670static int trace__process_event(struct trace *trace, struct machine *machine,
671 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300672{
673 int ret = 0;
674
675 switch (event->header.type) {
676 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300677 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300678 "LOST %" PRIu64 " events!\n", event->lost.lost);
679 ret = machine__process_lost_event(machine, event);
680 default:
681 ret = machine__process_event(machine, event);
682 break;
683 }
684
685 return ret;
686}
687
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300688static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300689 union perf_event *event,
690 struct perf_sample *sample __maybe_unused,
691 struct machine *machine)
692{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300693 struct trace *trace = container_of(tool, struct trace, tool);
694 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300695}
696
697static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
698{
699 int err = symbol__init();
700
701 if (err)
702 return err;
703
704 machine__init(&trace->host, "", HOST_KERNEL_ID);
705 machine__create_kernel_maps(&trace->host);
706
707 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300708 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300709 trace__tool_process,
710 &trace->host);
711 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300712 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300713 &trace->host);
714 }
715
716 if (err)
717 symbol__exit();
718
719 return err;
720}
721
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300722static int syscall__set_arg_fmts(struct syscall *sc)
723{
724 struct format_field *field;
725 int idx = 0;
726
727 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
728 if (sc->arg_scnprintf == NULL)
729 return -1;
730
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300731 if (sc->fmt)
732 sc->arg_parm = sc->fmt->arg_parm;
733
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300734 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300735 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
736 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
737 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300738 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
739 ++idx;
740 }
741
742 return 0;
743}
744
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300745static int trace__read_syscall_info(struct trace *trace, int id)
746{
747 char tp_name[128];
748 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300749 const char *name = audit_syscall_to_name(id, trace->audit_machine);
750
751 if (name == NULL)
752 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300753
754 if (id > trace->syscalls.max) {
755 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
756
757 if (nsyscalls == NULL)
758 return -1;
759
760 if (trace->syscalls.max != -1) {
761 memset(nsyscalls + trace->syscalls.max + 1, 0,
762 (id - trace->syscalls.max) * sizeof(*sc));
763 } else {
764 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
765 }
766
767 trace->syscalls.table = nsyscalls;
768 trace->syscalls.max = id;
769 }
770
771 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300772 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300773
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300774 if (trace->ev_qualifier) {
775 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
776
777 if (!(in ^ trace->not_ev_qualifier)) {
778 sc->filtered = true;
779 /*
780 * No need to do read tracepoint information since this will be
781 * filtered out.
782 */
783 return 0;
784 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300785 }
786
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300787 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300788
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300789 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
790 sc->tp_format = event_format__new("syscalls", tp_name);
791
792 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
793 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
794 sc->tp_format = event_format__new("syscalls", tp_name);
795 }
796
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300797 if (sc->tp_format == NULL)
798 return -1;
799
800 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300801}
802
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300803static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
804 unsigned long *args)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300805{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300806 size_t printed = 0;
807
808 if (sc->tp_format != NULL) {
809 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300810 u8 bit = 1;
811 struct syscall_arg arg = {
812 .idx = 0,
813 .mask = 0,
814 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300815
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300816 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300817 field = field->next, ++arg.idx, bit <<= 1) {
818 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300819 continue;
820
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -0300821 if (args[arg.idx] == 0)
822 continue;
823
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300824 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300825 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300826 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
827 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300828 if (sc->arg_parm)
829 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300830 printed += sc->arg_scnprintf[arg.idx](bf + printed,
831 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300832 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300833 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300834 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300835 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300836 }
837 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300838 int i = 0;
839
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300840 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300841 printed += scnprintf(bf + printed, size - printed,
842 "%sarg%d: %ld",
843 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300844 ++i;
845 }
846 }
847
848 return printed;
849}
850
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300851typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
852 struct perf_sample *sample);
853
854static struct syscall *trace__syscall_info(struct trace *trace,
855 struct perf_evsel *evsel,
856 struct perf_sample *sample)
857{
858 int id = perf_evsel__intval(evsel, sample, "id");
859
860 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -0300861
862 /*
863 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
864 * before that, leaving at a higher verbosity level till that is
865 * explained. Reproduced with plain ftrace with:
866 *
867 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
868 * grep "NR -1 " /t/trace_pipe
869 *
870 * After generating some load on the machine.
871 */
872 if (verbose > 1) {
873 static u64 n;
874 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
875 id, perf_evsel__name(evsel), ++n);
876 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300877 return NULL;
878 }
879
880 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
881 trace__read_syscall_info(trace, id))
882 goto out_cant_read;
883
884 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
885 goto out_cant_read;
886
887 return &trace->syscalls.table[id];
888
889out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -0300890 if (verbose) {
891 fprintf(trace->output, "Problems reading syscall %d", id);
892 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
893 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
894 fputs(" information\n", trace->output);
895 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300896 return NULL;
897}
898
899static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
900 struct perf_sample *sample)
901{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300902 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300903 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300904 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300905 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300906 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300907 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300908
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300909 if (sc == NULL)
910 return -1;
911
912 if (sc->filtered)
913 return 0;
914
Adrian Hunter314add62013-08-27 11:23:03 +0300915 thread = machine__findnew_thread(&trace->host, sample->pid,
916 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300917 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300918 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300919 return -1;
920
921 args = perf_evsel__rawptr(evsel, sample, "args");
922 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300923 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300924 return -1;
925 }
926
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300927 ttrace = thread->priv;
928
929 if (ttrace->entry_str == NULL) {
930 ttrace->entry_str = malloc(1024);
931 if (!ttrace->entry_str)
932 return -1;
933 }
934
935 ttrace->entry_time = sample->time;
936 msg = ttrace->entry_str;
937 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
938
939 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
940
941 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300942 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300943 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
944 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300945 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300946 } else
947 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300948
949 return 0;
950}
951
952static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
953 struct perf_sample *sample)
954{
955 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200956 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300957 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300958 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300959 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300960
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300961 if (sc == NULL)
962 return -1;
963
964 if (sc->filtered)
965 return 0;
966
Adrian Hunter314add62013-08-27 11:23:03 +0300967 thread = machine__findnew_thread(&trace->host, sample->pid,
968 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300969 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300970 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300971 return -1;
972
973 ret = perf_evsel__intval(evsel, sample, "ret");
974
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300975 ttrace = thread->priv;
976
977 ttrace->exit_time = sample->time;
978
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300979 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200980 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300981 if (trace__filter_duration(trace, duration))
982 goto out;
983 } else if (trace->duration_filter)
984 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200985
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300986 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300987
988 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300989 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300990 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300991 fprintf(trace->output, " ... [");
992 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
993 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300994 }
995
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -0300996 if (sc->fmt == NULL) {
997signed_print:
998 fprintf(trace->output, ") = %d", ret);
999 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001000 char bf[256];
1001 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1002 *e = audit_errno_to_name(-ret);
1003
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001004 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001005 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001006 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001007 else if (sc->fmt->hexret)
1008 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001009 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001010 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001011
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001012 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001013out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001014 ttrace->entry_pending = false;
1015
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001016 return 0;
1017}
1018
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001019static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1020 struct perf_sample *sample)
1021{
1022 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1023 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
Adrian Hunter314add62013-08-27 11:23:03 +03001024 struct thread *thread = machine__findnew_thread(&trace->host,
1025 sample->pid,
1026 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001027 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001028
1029 if (ttrace == NULL)
1030 goto out_dump;
1031
1032 ttrace->runtime_ms += runtime_ms;
1033 trace->runtime_ms += runtime_ms;
1034 return 0;
1035
1036out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001037 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001038 evsel->name,
1039 perf_evsel__strval(evsel, sample, "comm"),
1040 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1041 runtime,
1042 perf_evsel__intval(evsel, sample, "vruntime"));
1043 return 0;
1044}
1045
David Ahernbdc89662013-08-28 22:29:53 -06001046static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1047{
1048 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1049 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1050 return false;
1051
1052 if (trace->pid_list || trace->tid_list)
1053 return true;
1054
1055 return false;
1056}
1057
David Ahern6810fc92013-08-28 22:29:52 -06001058static int trace__process_sample(struct perf_tool *tool,
1059 union perf_event *event __maybe_unused,
1060 struct perf_sample *sample,
1061 struct perf_evsel *evsel,
1062 struct machine *machine __maybe_unused)
1063{
1064 struct trace *trace = container_of(tool, struct trace, tool);
1065 int err = 0;
1066
1067 tracepoint_handler handler = evsel->handler.func;
1068
David Ahernbdc89662013-08-28 22:29:53 -06001069 if (skip_sample(trace, sample))
1070 return 0;
1071
David Ahern4bb09192013-09-04 12:37:43 -06001072 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001073 trace->base_time = sample->time;
1074
1075 if (handler)
1076 handler(trace, evsel, sample);
1077
1078 return err;
1079}
1080
1081static bool
1082perf_session__has_tp(struct perf_session *session, const char *name)
1083{
1084 struct perf_evsel *evsel;
1085
1086 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1087
1088 return evsel != NULL;
1089}
1090
David Ahernbdc89662013-08-28 22:29:53 -06001091static int parse_target_str(struct trace *trace)
1092{
1093 if (trace->opts.target.pid) {
1094 trace->pid_list = intlist__new(trace->opts.target.pid);
1095 if (trace->pid_list == NULL) {
1096 pr_err("Error parsing process id string\n");
1097 return -EINVAL;
1098 }
1099 }
1100
1101 if (trace->opts.target.tid) {
1102 trace->tid_list = intlist__new(trace->opts.target.tid);
1103 if (trace->tid_list == NULL) {
1104 pr_err("Error parsing thread id string\n");
1105 return -EINVAL;
1106 }
1107 }
1108
1109 return 0;
1110}
1111
Namhyung Kimf15eb532012-10-05 14:02:16 +09001112static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001113{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001114 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001115 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001116 int err = -1, i;
1117 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001118 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001119
1120 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001121 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001122 goto out;
1123 }
1124
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001125 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1126 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001127 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001128 goto out_delete_evlist;
1129 }
1130
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001131 if (trace->sched &&
1132 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1133 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001134 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001135 goto out_delete_evlist;
1136 }
1137
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001138 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1139 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001140 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001141 goto out_delete_evlist;
1142 }
1143
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001144 err = trace__symbols_init(trace, evlist);
1145 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001146 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001147 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001148 }
1149
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001150 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001151
Namhyung Kimf15eb532012-10-05 14:02:16 +09001152 signal(SIGCHLD, sig_handler);
1153 signal(SIGINT, sig_handler);
1154
1155 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001156 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001157 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001158 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001159 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001160 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001161 }
1162 }
1163
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001164 err = perf_evlist__open(evlist);
1165 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001166 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001167 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001168 }
1169
1170 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1171 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001172 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001173 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001174 }
1175
1176 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001177
1178 if (forks)
1179 perf_evlist__start_workload(evlist);
1180
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001181 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001182again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001183 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001184
1185 for (i = 0; i < evlist->nr_mmaps; i++) {
1186 union perf_event *event;
1187
1188 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1189 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001190 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001191 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001192
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001193 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001194
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001195 err = perf_evlist__parse_sample(evlist, event, &sample);
1196 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001197 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001198 continue;
1199 }
1200
David Ahern4bb09192013-09-04 12:37:43 -06001201 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001202 trace->base_time = sample.time;
1203
1204 if (type != PERF_RECORD_SAMPLE) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001205 trace__process_event(trace, &trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001206 continue;
1207 }
1208
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001209 evsel = perf_evlist__id2evsel(evlist, sample.id);
1210 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001211 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001212 continue;
1213 }
1214
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001215 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001216 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 -03001217 perf_evsel__name(evsel), sample.tid,
1218 sample.cpu, sample.raw_size);
1219 continue;
1220 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001221
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001222 handler = evsel->handler.func;
1223 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001224
1225 if (done)
1226 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001227 }
1228 }
1229
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001230 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001231 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001232 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001233
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001234 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001235 }
1236
1237 if (done)
1238 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001239
1240 goto again;
1241
Namhyung Kim3beb0862013-03-15 14:48:50 +09001242out_unmap_evlist:
1243 perf_evlist__munmap(evlist);
1244out_close_evlist:
1245 perf_evlist__close(evlist);
1246out_delete_maps:
1247 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001248out_delete_evlist:
1249 perf_evlist__delete(evlist);
1250out:
1251 return err;
1252}
1253
David Ahern6810fc92013-08-28 22:29:52 -06001254static int trace__replay(struct trace *trace)
1255{
1256 const struct perf_evsel_str_handler handlers[] = {
1257 { "raw_syscalls:sys_enter", trace__sys_enter, },
1258 { "raw_syscalls:sys_exit", trace__sys_exit, },
1259 };
1260
1261 struct perf_session *session;
1262 int err = -1;
1263
1264 trace->tool.sample = trace__process_sample;
1265 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001266 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001267 trace->tool.comm = perf_event__process_comm;
1268 trace->tool.exit = perf_event__process_exit;
1269 trace->tool.fork = perf_event__process_fork;
1270 trace->tool.attr = perf_event__process_attr;
1271 trace->tool.tracing_data = perf_event__process_tracing_data;
1272 trace->tool.build_id = perf_event__process_build_id;
1273
1274 trace->tool.ordered_samples = true;
1275 trace->tool.ordering_requires_timestamps = true;
1276
1277 /* add tid to output */
1278 trace->multiple_threads = true;
1279
1280 if (symbol__init() < 0)
1281 return -1;
1282
1283 session = perf_session__new(input_name, O_RDONLY, 0, false,
1284 &trace->tool);
1285 if (session == NULL)
1286 return -ENOMEM;
1287
1288 err = perf_session__set_tracepoints_handlers(session, handlers);
1289 if (err)
1290 goto out;
1291
1292 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1293 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1294 goto out;
1295 }
1296
1297 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1298 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1299 goto out;
1300 }
1301
David Ahernbdc89662013-08-28 22:29:53 -06001302 err = parse_target_str(trace);
1303 if (err != 0)
1304 goto out;
1305
David Ahern6810fc92013-08-28 22:29:52 -06001306 setup_pager();
1307
1308 err = perf_session__process_events(session, &trace->tool);
1309 if (err)
1310 pr_err("Failed to process events, error %d", err);
1311
1312out:
1313 perf_session__delete(session);
1314
1315 return err;
1316}
1317
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001318static size_t trace__fprintf_threads_header(FILE *fp)
1319{
1320 size_t printed;
1321
1322 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1323 printed += fprintf(fp," __) Summary of events (__\n\n");
1324 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1325 printed += fprintf(fp," _____________________________________________________________________\n\n");
1326
1327 return printed;
1328}
1329
1330static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1331{
1332 size_t printed = trace__fprintf_threads_header(fp);
1333 struct rb_node *nd;
1334
1335 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1336 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1337 struct thread_trace *ttrace = thread->priv;
1338 const char *color;
1339 double ratio;
1340
1341 if (ttrace == NULL)
1342 continue;
1343
1344 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1345
1346 color = PERF_COLOR_NORMAL;
1347 if (ratio > 50.0)
1348 color = PERF_COLOR_RED;
1349 else if (ratio > 25.0)
1350 color = PERF_COLOR_GREEN;
1351 else if (ratio > 5.0)
1352 color = PERF_COLOR_YELLOW;
1353
1354 printed += color_fprintf(fp, color, "%20s", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001355 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001356 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1357 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1358 }
1359
1360 return printed;
1361}
1362
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001363static int trace__set_duration(const struct option *opt, const char *str,
1364 int unset __maybe_unused)
1365{
1366 struct trace *trace = opt->value;
1367
1368 trace->duration_filter = atof(str);
1369 return 0;
1370}
1371
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001372static int trace__open_output(struct trace *trace, const char *filename)
1373{
1374 struct stat st;
1375
1376 if (!stat(filename, &st) && st.st_size) {
1377 char oldname[PATH_MAX];
1378
1379 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1380 unlink(oldname);
1381 rename(filename, oldname);
1382 }
1383
1384 trace->output = fopen(filename, "w");
1385
1386 return trace->output == NULL ? -errno : 0;
1387}
1388
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001389int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1390{
1391 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001392 "perf trace [<options>] [<command>]",
1393 "perf trace [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001394 NULL
1395 };
1396 struct trace trace = {
1397 .audit_machine = audit_detect_machine(),
1398 .syscalls = {
1399 . max = -1,
1400 },
1401 .opts = {
1402 .target = {
1403 .uid = UINT_MAX,
1404 .uses_mmap = true,
1405 },
1406 .user_freq = UINT_MAX,
1407 .user_interval = ULLONG_MAX,
1408 .no_delay = true,
1409 .mmap_pages = 1024,
1410 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001411 .output = stdout,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001412 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001413 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001414 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001415 const struct option trace_options[] = {
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001416 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1417 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001418 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001419 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001420 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1421 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001422 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001423 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001424 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001425 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001426 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001427 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001428 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001429 "child tasks do not inherit counters"),
David Ahernac9be8e2013-08-20 11:15:45 -06001430 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001431 "number of mmap data pages"),
David Ahernac9be8e2013-08-20 11:15:45 -06001432 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001433 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001434 OPT_CALLBACK(0, "duration", &trace, "float",
1435 "show only events with duration > N.M ms",
1436 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001437 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001438 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06001439 OPT_BOOLEAN('T', "time", &trace.full_time,
1440 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001441 OPT_END()
1442 };
1443 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001444 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001445
1446 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001447
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001448 if (output_name != NULL) {
1449 err = trace__open_output(&trace, output_name);
1450 if (err < 0) {
1451 perror("failed to create output file");
1452 goto out;
1453 }
1454 }
1455
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001456 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001457 const char *s = ev_qualifier_str;
1458
1459 trace.not_ev_qualifier = *s == '!';
1460 if (trace.not_ev_qualifier)
1461 ++s;
1462 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001463 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001464 fputs("Not enough memory to parse event qualifier",
1465 trace.output);
1466 err = -ENOMEM;
1467 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001468 }
1469 }
1470
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001471 err = perf_target__validate(&trace.opts.target);
1472 if (err) {
1473 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001474 fprintf(trace.output, "%s", bf);
1475 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001476 }
1477
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001478 err = perf_target__parse_uid(&trace.opts.target);
1479 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001480 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001481 fprintf(trace.output, "%s", bf);
1482 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001483 }
1484
Namhyung Kimf15eb532012-10-05 14:02:16 +09001485 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001486 trace.opts.target.system_wide = true;
1487
David Ahern6810fc92013-08-28 22:29:52 -06001488 if (input_name)
1489 err = trace__replay(&trace);
1490 else
1491 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001492
1493 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001494 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001495
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001496out_close:
1497 if (output_name != NULL)
1498 fclose(trace.output);
1499out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001500 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001501}