blob: 7ce036ee863bf5164712cde9e95c90d5cc491206 [file] [log] [blame]
Robert Richter4e319022013-06-11 17:29:18 +02001#include <traceevent/event-parse.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03003#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03004#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03005#include "util/evlist.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03006#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -06007#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03008#include "util/thread.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03009#include "util/parse-options.h"
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030010#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060011#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030012#include "util/thread_map.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030013
14#include <libaudit.h>
15#include <stdlib.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030016#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030017#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030018
Ingo Molnar456857b2013-09-12 15:29:00 +020019/* For older distros: */
20#ifndef MAP_STACK
21# define MAP_STACK 0x20000
22#endif
23
24#ifndef MADV_HWPOISON
25# define MADV_HWPOISON 100
26#endif
27
28#ifndef MADV_MERGEABLE
29# define MADV_MERGEABLE 12
30#endif
31
32#ifndef MADV_UNMERGEABLE
33# define MADV_UNMERGEABLE 13
34#endif
35
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030036struct syscall_arg {
37 unsigned long val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030038 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030039 u8 idx;
40 u8 mask;
41};
42
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030043struct strarray {
44 int nr_entries;
45 const char **entries;
46};
47
48#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
49 .nr_entries = ARRAY_SIZE(array), \
50 .entries = array, \
51}
52
53static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
54 struct syscall_arg *arg)
55{
56 int idx = arg->val;
57 struct strarray *sa = arg->parm;
58
59 if (idx < 0 || idx >= sa->nr_entries)
60 return scnprintf(bf, size, "%d", idx);
61
62 return scnprintf(bf, size, "%s", sa->entries[idx]);
63}
64
65#define SCA_STRARRAY syscall_arg__scnprintf_strarray
66
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -030067static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030068 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030069{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030070 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030071}
72
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -030073#define SCA_HEX syscall_arg__scnprintf_hex
74
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -030075static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030076 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030077{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030078 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030079
80 if (prot == PROT_NONE)
81 return scnprintf(bf, size, "NONE");
82#define P_MMAP_PROT(n) \
83 if (prot & PROT_##n) { \
84 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
85 prot &= ~PROT_##n; \
86 }
87
88 P_MMAP_PROT(EXEC);
89 P_MMAP_PROT(READ);
90 P_MMAP_PROT(WRITE);
91#ifdef PROT_SEM
92 P_MMAP_PROT(SEM);
93#endif
94 P_MMAP_PROT(GROWSDOWN);
95 P_MMAP_PROT(GROWSUP);
96#undef P_MMAP_PROT
97
98 if (prot)
99 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
100
101 return printed;
102}
103
104#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
105
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300106static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300107 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300108{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300109 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300110
111#define P_MMAP_FLAG(n) \
112 if (flags & MAP_##n) { \
113 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
114 flags &= ~MAP_##n; \
115 }
116
117 P_MMAP_FLAG(SHARED);
118 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400119#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300120 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400121#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300122 P_MMAP_FLAG(ANONYMOUS);
123 P_MMAP_FLAG(DENYWRITE);
124 P_MMAP_FLAG(EXECUTABLE);
125 P_MMAP_FLAG(FILE);
126 P_MMAP_FLAG(FIXED);
127 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600128#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300129 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600130#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300131 P_MMAP_FLAG(LOCKED);
132 P_MMAP_FLAG(NONBLOCK);
133 P_MMAP_FLAG(NORESERVE);
134 P_MMAP_FLAG(POPULATE);
135 P_MMAP_FLAG(STACK);
136#ifdef MAP_UNINITIALIZED
137 P_MMAP_FLAG(UNINITIALIZED);
138#endif
139#undef P_MMAP_FLAG
140
141 if (flags)
142 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
143
144 return printed;
145}
146
147#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
148
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300149static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300150 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300151{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300152 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300153
154 switch (behavior) {
155#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
156 P_MADV_BHV(NORMAL);
157 P_MADV_BHV(RANDOM);
158 P_MADV_BHV(SEQUENTIAL);
159 P_MADV_BHV(WILLNEED);
160 P_MADV_BHV(DONTNEED);
161 P_MADV_BHV(REMOVE);
162 P_MADV_BHV(DONTFORK);
163 P_MADV_BHV(DOFORK);
164 P_MADV_BHV(HWPOISON);
165#ifdef MADV_SOFT_OFFLINE
166 P_MADV_BHV(SOFT_OFFLINE);
167#endif
168 P_MADV_BHV(MERGEABLE);
169 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600170#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300171 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600172#endif
173#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300174 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600175#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300176#ifdef MADV_DONTDUMP
177 P_MADV_BHV(DONTDUMP);
178#endif
179#ifdef MADV_DODUMP
180 P_MADV_BHV(DODUMP);
181#endif
182#undef P_MADV_PHV
183 default: break;
184 }
185
186 return scnprintf(bf, size, "%#x", behavior);
187}
188
189#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
190
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300191static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300192{
193 enum syscall_futex_args {
194 SCF_UADDR = (1 << 0),
195 SCF_OP = (1 << 1),
196 SCF_VAL = (1 << 2),
197 SCF_TIMEOUT = (1 << 3),
198 SCF_UADDR2 = (1 << 4),
199 SCF_VAL3 = (1 << 5),
200 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300201 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300202 int cmd = op & FUTEX_CMD_MASK;
203 size_t printed = 0;
204
205 switch (cmd) {
206#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300207 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
208 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
209 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
210 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
211 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
212 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300213 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300214 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
215 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
216 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
217 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
218 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300219 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
220 default: printed = scnprintf(bf, size, "%#x", cmd); break;
221 }
222
223 if (op & FUTEX_PRIVATE_FLAG)
224 printed += scnprintf(bf + printed, size - printed, "|PRIV");
225
226 if (op & FUTEX_CLOCK_REALTIME)
227 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
228
229 return printed;
230}
231
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300232#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
233
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300234static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
235static DEFINE_STRARRAY(itimers);
236
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300237static const char *whences[] = { "SET", "CUR", "END",
238#ifdef SEEK_DATA
239"DATA",
240#endif
241#ifdef SEEK_HOLE
242"HOLE",
243#endif
244};
245static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300246
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300247static const char *fcntl_cmds[] = {
248 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
249 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
250 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
251 "F_GETOWNER_UIDS",
252};
253static DEFINE_STRARRAY(fcntl_cmds);
254
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300255static const char *rlimit_resources[] = {
256 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
257 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
258 "RTTIME",
259};
260static DEFINE_STRARRAY(rlimit_resources);
261
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300262static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
263static DEFINE_STRARRAY(sighow);
264
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300265static const char *socket_families[] = {
266 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
267 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
268 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
269 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
270 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
271 "ALG", "NFC", "VSOCK",
272};
273static DEFINE_STRARRAY(socket_families);
274
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300275#ifndef SOCK_TYPE_MASK
276#define SOCK_TYPE_MASK 0xf
277#endif
278
279static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
280 struct syscall_arg *arg)
281{
282 size_t printed;
283 int type = arg->val,
284 flags = type & ~SOCK_TYPE_MASK;
285
286 type &= SOCK_TYPE_MASK;
287 /*
288 * Can't use a strarray, MIPS may override for ABI reasons.
289 */
290 switch (type) {
291#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
292 P_SK_TYPE(STREAM);
293 P_SK_TYPE(DGRAM);
294 P_SK_TYPE(RAW);
295 P_SK_TYPE(RDM);
296 P_SK_TYPE(SEQPACKET);
297 P_SK_TYPE(DCCP);
298 P_SK_TYPE(PACKET);
299#undef P_SK_TYPE
300 default:
301 printed = scnprintf(bf, size, "%#x", type);
302 }
303
304#define P_SK_FLAG(n) \
305 if (flags & SOCK_##n) { \
306 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
307 flags &= ~SOCK_##n; \
308 }
309
310 P_SK_FLAG(CLOEXEC);
311 P_SK_FLAG(NONBLOCK);
312#undef P_SK_FLAG
313
314 if (flags)
315 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
316
317 return printed;
318}
319
320#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
321
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300322static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
323 struct syscall_arg *arg)
324{
325 size_t printed = 0;
326 int mode = arg->val;
327
328 if (mode == F_OK) /* 0 */
329 return scnprintf(bf, size, "F");
330#define P_MODE(n) \
331 if (mode & n##_OK) { \
332 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
333 mode &= ~n##_OK; \
334 }
335
336 P_MODE(R);
337 P_MODE(W);
338 P_MODE(X);
339#undef P_MODE
340
341 if (mode)
342 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
343
344 return printed;
345}
346
347#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
348
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300349static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300350 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300351{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300352 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300353
354 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300355 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300356
357 if (flags == 0)
358 return scnprintf(bf, size, "RDONLY");
359#define P_FLAG(n) \
360 if (flags & O_##n) { \
361 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
362 flags &= ~O_##n; \
363 }
364
365 P_FLAG(APPEND);
366 P_FLAG(ASYNC);
367 P_FLAG(CLOEXEC);
368 P_FLAG(CREAT);
369 P_FLAG(DIRECT);
370 P_FLAG(DIRECTORY);
371 P_FLAG(EXCL);
372 P_FLAG(LARGEFILE);
373 P_FLAG(NOATIME);
374 P_FLAG(NOCTTY);
375#ifdef O_NONBLOCK
376 P_FLAG(NONBLOCK);
377#elif O_NDELAY
378 P_FLAG(NDELAY);
379#endif
380#ifdef O_PATH
381 P_FLAG(PATH);
382#endif
383 P_FLAG(RDWR);
384#ifdef O_DSYNC
385 if ((flags & O_SYNC) == O_SYNC)
386 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
387 else {
388 P_FLAG(DSYNC);
389 }
390#else
391 P_FLAG(SYNC);
392#endif
393 P_FLAG(TRUNC);
394 P_FLAG(WRONLY);
395#undef P_FLAG
396
397 if (flags)
398 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
399
400 return printed;
401}
402
403#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
404
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300405static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
406{
407 int sig = arg->val;
408
409 switch (sig) {
410#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
411 P_SIGNUM(HUP);
412 P_SIGNUM(INT);
413 P_SIGNUM(QUIT);
414 P_SIGNUM(ILL);
415 P_SIGNUM(TRAP);
416 P_SIGNUM(ABRT);
417 P_SIGNUM(BUS);
418 P_SIGNUM(FPE);
419 P_SIGNUM(KILL);
420 P_SIGNUM(USR1);
421 P_SIGNUM(SEGV);
422 P_SIGNUM(USR2);
423 P_SIGNUM(PIPE);
424 P_SIGNUM(ALRM);
425 P_SIGNUM(TERM);
426 P_SIGNUM(STKFLT);
427 P_SIGNUM(CHLD);
428 P_SIGNUM(CONT);
429 P_SIGNUM(STOP);
430 P_SIGNUM(TSTP);
431 P_SIGNUM(TTIN);
432 P_SIGNUM(TTOU);
433 P_SIGNUM(URG);
434 P_SIGNUM(XCPU);
435 P_SIGNUM(XFSZ);
436 P_SIGNUM(VTALRM);
437 P_SIGNUM(PROF);
438 P_SIGNUM(WINCH);
439 P_SIGNUM(IO);
440 P_SIGNUM(PWR);
441 P_SIGNUM(SYS);
442 default: break;
443 }
444
445 return scnprintf(bf, size, "%#x", sig);
446}
447
448#define SCA_SIGNUM syscall_arg__scnprintf_signum
449
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300450static struct syscall_fmt {
451 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300452 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300453 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300454 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300455 bool errmsg;
456 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300457 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300458} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300459 { .name = "access", .errmsg = true,
460 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300461 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300462 { .name = "brk", .hexret = true,
463 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300464 { .name = "mmap", .hexret = true, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300465 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300466 { .name = "fcntl", .errmsg = true,
467 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
468 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300469 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
470 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300471 { .name = "futex", .errmsg = true,
472 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300473 { .name = "getitimer", .errmsg = true,
474 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
475 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300476 { .name = "getrlimit", .errmsg = true,
477 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
478 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300479 { .name = "ioctl", .errmsg = true,
480 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300481 { .name = "kill", .errmsg = true,
482 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo579e7862013-09-02 15:37:32 -0300483 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300484 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
485 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300486 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300487 { .name = "madvise", .errmsg = true,
488 .arg_scnprintf = { [0] = SCA_HEX, /* start */
489 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300490 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300491 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300492 [2] = SCA_MMAP_PROT, /* prot */
493 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300494 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300495 .arg_scnprintf = { [0] = SCA_HEX, /* start */
496 [2] = SCA_MMAP_PROT, /* prot */ }, },
497 { .name = "mremap", .hexret = true,
498 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
499 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300500 { .name = "munmap", .errmsg = true,
501 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300502 { .name = "open", .errmsg = true,
503 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300504 { .name = "open_by_handle_at", .errmsg = true,
505 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
506 { .name = "openat", .errmsg = true,
507 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300508 { .name = "poll", .errmsg = true, .timeout = true, },
509 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300510 { .name = "pread", .errmsg = true, .alias = "pread64", },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300511 { .name = "prlimit64", .errmsg = true,
512 .arg_scnprintf = { [1] = SCA_STRARRAY, /* resource */ },
513 .arg_parm = { [1] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300514 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300515 { .name = "read", .errmsg = true, },
516 { .name = "recvfrom", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300517 { .name = "rt_sigaction", .errmsg = true,
518 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300519 { .name = "rt_sigprocmask", .errmsg = true,
520 .arg_scnprintf = { [0] = SCA_STRARRAY, /* how */ },
521 .arg_parm = { [0] = &strarray__sighow, /* how */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300522 { .name = "rt_sigqueueinfo", .errmsg = true,
523 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
524 { .name = "rt_tgsigqueueinfo", .errmsg = true,
525 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300526 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300527 { .name = "setitimer", .errmsg = true,
528 .arg_scnprintf = { [0] = SCA_STRARRAY, /* which */ },
529 .arg_parm = { [0] = &strarray__itimers, /* which */ }, },
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300530 { .name = "setrlimit", .errmsg = true,
531 .arg_scnprintf = { [0] = SCA_STRARRAY, /* resource */ },
532 .arg_parm = { [0] = &strarray__rlimit_resources, /* resource */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300533 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300534 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
535 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300536 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300537 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300538 { .name = "tgkill", .errmsg = true,
539 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
540 { .name = "tkill", .errmsg = true,
541 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300542 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300543};
544
545static int syscall_fmt__cmp(const void *name, const void *fmtp)
546{
547 const struct syscall_fmt *fmt = fmtp;
548 return strcmp(name, fmt->name);
549}
550
551static struct syscall_fmt *syscall_fmt__find(const char *name)
552{
553 const int nmemb = ARRAY_SIZE(syscall_fmts);
554 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
555}
556
557struct syscall {
558 struct event_format *tp_format;
559 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300560 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300561 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300562 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300563 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300564};
565
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200566static size_t fprintf_duration(unsigned long t, FILE *fp)
567{
568 double duration = (double)t / NSEC_PER_MSEC;
569 size_t printed = fprintf(fp, "(");
570
571 if (duration >= 1.0)
572 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
573 else if (duration >= 0.01)
574 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
575 else
576 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300577 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200578}
579
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300580struct thread_trace {
581 u64 entry_time;
582 u64 exit_time;
583 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300584 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300585 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300586 double runtime_ms;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300587};
588
589static struct thread_trace *thread_trace__new(void)
590{
591 return zalloc(sizeof(struct thread_trace));
592}
593
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300594static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300595{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300596 struct thread_trace *ttrace;
597
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300598 if (thread == NULL)
599 goto fail;
600
601 if (thread->priv == NULL)
602 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300603
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300604 if (thread->priv == NULL)
605 goto fail;
606
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300607 ttrace = thread->priv;
608 ++ttrace->nr_events;
609
610 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300611fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300612 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300613 "WARNING: not enough memory, dropping samples!\n");
614 return NULL;
615}
616
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300617struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300618 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300619 int audit_machine;
620 struct {
621 int max;
622 struct syscall *table;
623 } syscalls;
624 struct perf_record_opts opts;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300625 struct machine host;
626 u64 base_time;
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 Melo752fde42012-10-06 18:43:19 -0300821 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300822 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300823 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
824 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300825 if (sc->arg_parm)
826 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300827 printed += sc->arg_scnprintf[arg.idx](bf + printed,
828 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300829 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300830 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300831 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300832 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300833 }
834 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300835 int i = 0;
836
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300837 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300838 printed += scnprintf(bf + printed, size - printed,
839 "%sarg%d: %ld",
840 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300841 ++i;
842 }
843 }
844
845 return printed;
846}
847
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300848typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
849 struct perf_sample *sample);
850
851static struct syscall *trace__syscall_info(struct trace *trace,
852 struct perf_evsel *evsel,
853 struct perf_sample *sample)
854{
855 int id = perf_evsel__intval(evsel, sample, "id");
856
857 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -0300858
859 /*
860 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
861 * before that, leaving at a higher verbosity level till that is
862 * explained. Reproduced with plain ftrace with:
863 *
864 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
865 * grep "NR -1 " /t/trace_pipe
866 *
867 * After generating some load on the machine.
868 */
869 if (verbose > 1) {
870 static u64 n;
871 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
872 id, perf_evsel__name(evsel), ++n);
873 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300874 return NULL;
875 }
876
877 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
878 trace__read_syscall_info(trace, id))
879 goto out_cant_read;
880
881 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
882 goto out_cant_read;
883
884 return &trace->syscalls.table[id];
885
886out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -0300887 if (verbose) {
888 fprintf(trace->output, "Problems reading syscall %d", id);
889 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
890 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
891 fputs(" information\n", trace->output);
892 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300893 return NULL;
894}
895
896static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
897 struct perf_sample *sample)
898{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300899 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300900 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300901 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300902 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300903 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300904 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300905
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300906 if (sc == NULL)
907 return -1;
908
909 if (sc->filtered)
910 return 0;
911
Adrian Hunter314add62013-08-27 11:23:03 +0300912 thread = machine__findnew_thread(&trace->host, sample->pid,
913 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300914 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300915 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300916 return -1;
917
918 args = perf_evsel__rawptr(evsel, sample, "args");
919 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300920 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300921 return -1;
922 }
923
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300924 ttrace = thread->priv;
925
926 if (ttrace->entry_str == NULL) {
927 ttrace->entry_str = malloc(1024);
928 if (!ttrace->entry_str)
929 return -1;
930 }
931
932 ttrace->entry_time = sample->time;
933 msg = ttrace->entry_str;
934 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
935
936 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
937
938 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300939 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300940 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
941 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300942 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300943 } else
944 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300945
946 return 0;
947}
948
949static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
950 struct perf_sample *sample)
951{
952 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200953 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300954 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300955 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300956 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300957
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300958 if (sc == NULL)
959 return -1;
960
961 if (sc->filtered)
962 return 0;
963
Adrian Hunter314add62013-08-27 11:23:03 +0300964 thread = machine__findnew_thread(&trace->host, sample->pid,
965 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300966 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300967 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300968 return -1;
969
970 ret = perf_evsel__intval(evsel, sample, "ret");
971
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300972 ttrace = thread->priv;
973
974 ttrace->exit_time = sample->time;
975
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300976 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200977 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300978 if (trace__filter_duration(trace, duration))
979 goto out;
980 } else if (trace->duration_filter)
981 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200982
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300983 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300984
985 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300986 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300987 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300988 fprintf(trace->output, " ... [");
989 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
990 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300991 }
992
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -0300993 if (sc->fmt == NULL) {
994signed_print:
995 fprintf(trace->output, ") = %d", ret);
996 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300997 char bf[256];
998 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
999 *e = audit_errno_to_name(-ret);
1000
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001001 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001002 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001003 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001004 else if (sc->fmt->hexret)
1005 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001006 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001007 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001008
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001009 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001010out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001011 ttrace->entry_pending = false;
1012
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001013 return 0;
1014}
1015
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001016static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1017 struct perf_sample *sample)
1018{
1019 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1020 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
Adrian Hunter314add62013-08-27 11:23:03 +03001021 struct thread *thread = machine__findnew_thread(&trace->host,
1022 sample->pid,
1023 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001024 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001025
1026 if (ttrace == NULL)
1027 goto out_dump;
1028
1029 ttrace->runtime_ms += runtime_ms;
1030 trace->runtime_ms += runtime_ms;
1031 return 0;
1032
1033out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001034 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001035 evsel->name,
1036 perf_evsel__strval(evsel, sample, "comm"),
1037 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1038 runtime,
1039 perf_evsel__intval(evsel, sample, "vruntime"));
1040 return 0;
1041}
1042
David Ahernbdc89662013-08-28 22:29:53 -06001043static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1044{
1045 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1046 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1047 return false;
1048
1049 if (trace->pid_list || trace->tid_list)
1050 return true;
1051
1052 return false;
1053}
1054
David Ahern6810fc92013-08-28 22:29:52 -06001055static int trace__process_sample(struct perf_tool *tool,
1056 union perf_event *event __maybe_unused,
1057 struct perf_sample *sample,
1058 struct perf_evsel *evsel,
1059 struct machine *machine __maybe_unused)
1060{
1061 struct trace *trace = container_of(tool, struct trace, tool);
1062 int err = 0;
1063
1064 tracepoint_handler handler = evsel->handler.func;
1065
David Ahernbdc89662013-08-28 22:29:53 -06001066 if (skip_sample(trace, sample))
1067 return 0;
1068
David Ahern6810fc92013-08-28 22:29:52 -06001069 if (trace->base_time == 0)
1070 trace->base_time = sample->time;
1071
1072 if (handler)
1073 handler(trace, evsel, sample);
1074
1075 return err;
1076}
1077
1078static bool
1079perf_session__has_tp(struct perf_session *session, const char *name)
1080{
1081 struct perf_evsel *evsel;
1082
1083 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1084
1085 return evsel != NULL;
1086}
1087
David Ahernbdc89662013-08-28 22:29:53 -06001088static int parse_target_str(struct trace *trace)
1089{
1090 if (trace->opts.target.pid) {
1091 trace->pid_list = intlist__new(trace->opts.target.pid);
1092 if (trace->pid_list == NULL) {
1093 pr_err("Error parsing process id string\n");
1094 return -EINVAL;
1095 }
1096 }
1097
1098 if (trace->opts.target.tid) {
1099 trace->tid_list = intlist__new(trace->opts.target.tid);
1100 if (trace->tid_list == NULL) {
1101 pr_err("Error parsing thread id string\n");
1102 return -EINVAL;
1103 }
1104 }
1105
1106 return 0;
1107}
1108
Namhyung Kimf15eb532012-10-05 14:02:16 +09001109static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001110{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001111 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001112 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001113 int err = -1, i;
1114 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001115 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001116
1117 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001118 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001119 goto out;
1120 }
1121
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001122 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1123 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001124 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001125 goto out_delete_evlist;
1126 }
1127
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001128 if (trace->sched &&
1129 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1130 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001131 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001132 goto out_delete_evlist;
1133 }
1134
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001135 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1136 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001137 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001138 goto out_delete_evlist;
1139 }
1140
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001141 err = trace__symbols_init(trace, evlist);
1142 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001143 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001144 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001145 }
1146
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001147 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001148
Namhyung Kimf15eb532012-10-05 14:02:16 +09001149 signal(SIGCHLD, sig_handler);
1150 signal(SIGINT, sig_handler);
1151
1152 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001153 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001154 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001155 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001156 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001157 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001158 }
1159 }
1160
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001161 err = perf_evlist__open(evlist);
1162 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001163 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001164 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001165 }
1166
1167 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1168 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001169 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001170 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001171 }
1172
1173 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001174
1175 if (forks)
1176 perf_evlist__start_workload(evlist);
1177
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001178 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001179again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001180 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001181
1182 for (i = 0; i < evlist->nr_mmaps; i++) {
1183 union perf_event *event;
1184
1185 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1186 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001187 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001188 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001189
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001190 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001191
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001192 err = perf_evlist__parse_sample(evlist, event, &sample);
1193 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001194 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001195 continue;
1196 }
1197
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001198 if (trace->base_time == 0)
1199 trace->base_time = sample.time;
1200
1201 if (type != PERF_RECORD_SAMPLE) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001202 trace__process_event(trace, &trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001203 continue;
1204 }
1205
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001206 evsel = perf_evlist__id2evsel(evlist, sample.id);
1207 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001208 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001209 continue;
1210 }
1211
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001212 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001213 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 -03001214 perf_evsel__name(evsel), sample.tid,
1215 sample.cpu, sample.raw_size);
1216 continue;
1217 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001218
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001219 handler = evsel->handler.func;
1220 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001221
1222 if (done)
1223 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001224 }
1225 }
1226
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001227 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001228 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001229 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001230
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001231 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001232 }
1233
1234 if (done)
1235 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001236
1237 goto again;
1238
Namhyung Kim3beb0862013-03-15 14:48:50 +09001239out_unmap_evlist:
1240 perf_evlist__munmap(evlist);
1241out_close_evlist:
1242 perf_evlist__close(evlist);
1243out_delete_maps:
1244 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001245out_delete_evlist:
1246 perf_evlist__delete(evlist);
1247out:
1248 return err;
1249}
1250
David Ahern6810fc92013-08-28 22:29:52 -06001251static int trace__replay(struct trace *trace)
1252{
1253 const struct perf_evsel_str_handler handlers[] = {
1254 { "raw_syscalls:sys_enter", trace__sys_enter, },
1255 { "raw_syscalls:sys_exit", trace__sys_exit, },
1256 };
1257
1258 struct perf_session *session;
1259 int err = -1;
1260
1261 trace->tool.sample = trace__process_sample;
1262 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001263 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001264 trace->tool.comm = perf_event__process_comm;
1265 trace->tool.exit = perf_event__process_exit;
1266 trace->tool.fork = perf_event__process_fork;
1267 trace->tool.attr = perf_event__process_attr;
1268 trace->tool.tracing_data = perf_event__process_tracing_data;
1269 trace->tool.build_id = perf_event__process_build_id;
1270
1271 trace->tool.ordered_samples = true;
1272 trace->tool.ordering_requires_timestamps = true;
1273
1274 /* add tid to output */
1275 trace->multiple_threads = true;
1276
1277 if (symbol__init() < 0)
1278 return -1;
1279
1280 session = perf_session__new(input_name, O_RDONLY, 0, false,
1281 &trace->tool);
1282 if (session == NULL)
1283 return -ENOMEM;
1284
1285 err = perf_session__set_tracepoints_handlers(session, handlers);
1286 if (err)
1287 goto out;
1288
1289 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1290 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1291 goto out;
1292 }
1293
1294 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1295 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1296 goto out;
1297 }
1298
David Ahernbdc89662013-08-28 22:29:53 -06001299 err = parse_target_str(trace);
1300 if (err != 0)
1301 goto out;
1302
David Ahern6810fc92013-08-28 22:29:52 -06001303 setup_pager();
1304
1305 err = perf_session__process_events(session, &trace->tool);
1306 if (err)
1307 pr_err("Failed to process events, error %d", err);
1308
1309out:
1310 perf_session__delete(session);
1311
1312 return err;
1313}
1314
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001315static size_t trace__fprintf_threads_header(FILE *fp)
1316{
1317 size_t printed;
1318
1319 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1320 printed += fprintf(fp," __) Summary of events (__\n\n");
1321 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1322 printed += fprintf(fp," _____________________________________________________________________\n\n");
1323
1324 return printed;
1325}
1326
1327static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1328{
1329 size_t printed = trace__fprintf_threads_header(fp);
1330 struct rb_node *nd;
1331
1332 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1333 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1334 struct thread_trace *ttrace = thread->priv;
1335 const char *color;
1336 double ratio;
1337
1338 if (ttrace == NULL)
1339 continue;
1340
1341 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1342
1343 color = PERF_COLOR_NORMAL;
1344 if (ratio > 50.0)
1345 color = PERF_COLOR_RED;
1346 else if (ratio > 25.0)
1347 color = PERF_COLOR_GREEN;
1348 else if (ratio > 5.0)
1349 color = PERF_COLOR_YELLOW;
1350
1351 printed += color_fprintf(fp, color, "%20s", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001352 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001353 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1354 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1355 }
1356
1357 return printed;
1358}
1359
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001360static int trace__set_duration(const struct option *opt, const char *str,
1361 int unset __maybe_unused)
1362{
1363 struct trace *trace = opt->value;
1364
1365 trace->duration_filter = atof(str);
1366 return 0;
1367}
1368
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001369static int trace__open_output(struct trace *trace, const char *filename)
1370{
1371 struct stat st;
1372
1373 if (!stat(filename, &st) && st.st_size) {
1374 char oldname[PATH_MAX];
1375
1376 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1377 unlink(oldname);
1378 rename(filename, oldname);
1379 }
1380
1381 trace->output = fopen(filename, "w");
1382
1383 return trace->output == NULL ? -errno : 0;
1384}
1385
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001386int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1387{
1388 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001389 "perf trace [<options>] [<command>]",
1390 "perf trace [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001391 NULL
1392 };
1393 struct trace trace = {
1394 .audit_machine = audit_detect_machine(),
1395 .syscalls = {
1396 . max = -1,
1397 },
1398 .opts = {
1399 .target = {
1400 .uid = UINT_MAX,
1401 .uses_mmap = true,
1402 },
1403 .user_freq = UINT_MAX,
1404 .user_interval = ULLONG_MAX,
1405 .no_delay = true,
1406 .mmap_pages = 1024,
1407 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001408 .output = stdout,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001409 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001410 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001411 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001412 const struct option trace_options[] = {
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001413 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1414 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001415 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001416 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001417 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1418 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001419 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001420 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001421 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001422 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001423 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001424 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001425 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001426 "child tasks do not inherit counters"),
David Ahernac9be8e2013-08-20 11:15:45 -06001427 OPT_UINTEGER('m', "mmap-pages", &trace.opts.mmap_pages,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001428 "number of mmap data pages"),
David Ahernac9be8e2013-08-20 11:15:45 -06001429 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001430 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001431 OPT_CALLBACK(0, "duration", &trace, "float",
1432 "show only events with duration > N.M ms",
1433 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001434 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001435 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001436 OPT_END()
1437 };
1438 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001439 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001440
1441 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001442
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001443 if (output_name != NULL) {
1444 err = trace__open_output(&trace, output_name);
1445 if (err < 0) {
1446 perror("failed to create output file");
1447 goto out;
1448 }
1449 }
1450
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001451 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001452 const char *s = ev_qualifier_str;
1453
1454 trace.not_ev_qualifier = *s == '!';
1455 if (trace.not_ev_qualifier)
1456 ++s;
1457 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001458 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001459 fputs("Not enough memory to parse event qualifier",
1460 trace.output);
1461 err = -ENOMEM;
1462 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001463 }
1464 }
1465
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001466 err = perf_target__validate(&trace.opts.target);
1467 if (err) {
1468 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001469 fprintf(trace.output, "%s", bf);
1470 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001471 }
1472
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001473 err = perf_target__parse_uid(&trace.opts.target);
1474 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001475 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001476 fprintf(trace.output, "%s", bf);
1477 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001478 }
1479
Namhyung Kimf15eb532012-10-05 14:02:16 +09001480 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001481 trace.opts.target.system_wide = true;
1482
David Ahern6810fc92013-08-28 22:29:52 -06001483 if (input_name)
1484 err = trace__replay(&trace);
1485 else
1486 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001487
1488 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001489 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001490
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001491out_close:
1492 if (output_name != NULL)
1493 fclose(trace.output);
1494out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001495 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001496}