blob: 76d9427b4b91250101d429b3073c52c5427344b7 [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 Melo49af9e92013-09-12 12:18:56 -030016#include <sys/eventfd.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030017#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030018#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030019
Ingo Molnar456857b2013-09-12 15:29:00 +020020/* For older distros: */
21#ifndef MAP_STACK
22# define MAP_STACK 0x20000
23#endif
24
25#ifndef MADV_HWPOISON
26# define MADV_HWPOISON 100
27#endif
28
29#ifndef MADV_MERGEABLE
30# define MADV_MERGEABLE 12
31#endif
32
33#ifndef MADV_UNMERGEABLE
34# define MADV_UNMERGEABLE 13
35#endif
36
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030037struct syscall_arg {
38 unsigned long val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030039 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030040 u8 idx;
41 u8 mask;
42};
43
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030044struct strarray {
45 int nr_entries;
46 const char **entries;
47};
48
49#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
50 .nr_entries = ARRAY_SIZE(array), \
51 .entries = array, \
52}
53
54static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
55 struct syscall_arg *arg)
56{
57 int idx = arg->val;
58 struct strarray *sa = arg->parm;
59
60 if (idx < 0 || idx >= sa->nr_entries)
61 return scnprintf(bf, size, "%d", idx);
62
63 return scnprintf(bf, size, "%s", sa->entries[idx]);
64}
65
66#define SCA_STRARRAY syscall_arg__scnprintf_strarray
67
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -030068static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030069 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030070{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030071 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030072}
73
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -030074#define SCA_HEX syscall_arg__scnprintf_hex
75
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -030076static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030077 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030078{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030079 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030080
81 if (prot == PROT_NONE)
82 return scnprintf(bf, size, "NONE");
83#define P_MMAP_PROT(n) \
84 if (prot & PROT_##n) { \
85 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
86 prot &= ~PROT_##n; \
87 }
88
89 P_MMAP_PROT(EXEC);
90 P_MMAP_PROT(READ);
91 P_MMAP_PROT(WRITE);
92#ifdef PROT_SEM
93 P_MMAP_PROT(SEM);
94#endif
95 P_MMAP_PROT(GROWSDOWN);
96 P_MMAP_PROT(GROWSUP);
97#undef P_MMAP_PROT
98
99 if (prot)
100 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
101
102 return printed;
103}
104
105#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
106
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300107static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300108 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300109{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300110 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300111
112#define P_MMAP_FLAG(n) \
113 if (flags & MAP_##n) { \
114 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
115 flags &= ~MAP_##n; \
116 }
117
118 P_MMAP_FLAG(SHARED);
119 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400120#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300121 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400122#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300123 P_MMAP_FLAG(ANONYMOUS);
124 P_MMAP_FLAG(DENYWRITE);
125 P_MMAP_FLAG(EXECUTABLE);
126 P_MMAP_FLAG(FILE);
127 P_MMAP_FLAG(FIXED);
128 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600129#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300130 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600131#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300132 P_MMAP_FLAG(LOCKED);
133 P_MMAP_FLAG(NONBLOCK);
134 P_MMAP_FLAG(NORESERVE);
135 P_MMAP_FLAG(POPULATE);
136 P_MMAP_FLAG(STACK);
137#ifdef MAP_UNINITIALIZED
138 P_MMAP_FLAG(UNINITIALIZED);
139#endif
140#undef P_MMAP_FLAG
141
142 if (flags)
143 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
144
145 return printed;
146}
147
148#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
149
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300150static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300151 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300152{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300153 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300154
155 switch (behavior) {
156#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
157 P_MADV_BHV(NORMAL);
158 P_MADV_BHV(RANDOM);
159 P_MADV_BHV(SEQUENTIAL);
160 P_MADV_BHV(WILLNEED);
161 P_MADV_BHV(DONTNEED);
162 P_MADV_BHV(REMOVE);
163 P_MADV_BHV(DONTFORK);
164 P_MADV_BHV(DOFORK);
165 P_MADV_BHV(HWPOISON);
166#ifdef MADV_SOFT_OFFLINE
167 P_MADV_BHV(SOFT_OFFLINE);
168#endif
169 P_MADV_BHV(MERGEABLE);
170 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600171#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300172 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600173#endif
174#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300175 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600176#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300177#ifdef MADV_DONTDUMP
178 P_MADV_BHV(DONTDUMP);
179#endif
180#ifdef MADV_DODUMP
181 P_MADV_BHV(DODUMP);
182#endif
183#undef P_MADV_PHV
184 default: break;
185 }
186
187 return scnprintf(bf, size, "%#x", behavior);
188}
189
190#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
191
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300192static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
193 struct syscall_arg *arg)
194{
195 int printed = 0, op = arg->val;
196
197 if (op == 0)
198 return scnprintf(bf, size, "NONE");
199#define P_CMD(cmd) \
200 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
201 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
202 op &= ~LOCK_##cmd; \
203 }
204
205 P_CMD(SH);
206 P_CMD(EX);
207 P_CMD(NB);
208 P_CMD(UN);
209 P_CMD(MAND);
210 P_CMD(RW);
211 P_CMD(READ);
212 P_CMD(WRITE);
213#undef P_OP
214
215 if (op)
216 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
217
218 return printed;
219}
220
221#define SCA_FLOCK syscall_arg__scnprintf_flock
222
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300223static 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 -0300224{
225 enum syscall_futex_args {
226 SCF_UADDR = (1 << 0),
227 SCF_OP = (1 << 1),
228 SCF_VAL = (1 << 2),
229 SCF_TIMEOUT = (1 << 3),
230 SCF_UADDR2 = (1 << 4),
231 SCF_VAL3 = (1 << 5),
232 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300233 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300234 int cmd = op & FUTEX_CMD_MASK;
235 size_t printed = 0;
236
237 switch (cmd) {
238#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300239 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
240 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
241 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
242 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
243 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
244 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300245 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300246 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
247 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
248 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
249 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
250 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300251 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
252 default: printed = scnprintf(bf, size, "%#x", cmd); break;
253 }
254
255 if (op & FUTEX_PRIVATE_FLAG)
256 printed += scnprintf(bf + printed, size - printed, "|PRIV");
257
258 if (op & FUTEX_CLOCK_REALTIME)
259 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
260
261 return printed;
262}
263
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300264#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
265
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300266static const char *epoll_ctl_ops[] = { [1] = "ADD", "DEL", "MOD", };
267static DEFINE_STRARRAY(epoll_ctl_ops);
268
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300269static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
270static DEFINE_STRARRAY(itimers);
271
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300272static const char *whences[] = { "SET", "CUR", "END",
273#ifdef SEEK_DATA
274"DATA",
275#endif
276#ifdef SEEK_HOLE
277"HOLE",
278#endif
279};
280static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300281
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300282static const char *fcntl_cmds[] = {
283 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
284 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
285 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
286 "F_GETOWNER_UIDS",
287};
288static DEFINE_STRARRAY(fcntl_cmds);
289
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300290static const char *rlimit_resources[] = {
291 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
292 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
293 "RTTIME",
294};
295static DEFINE_STRARRAY(rlimit_resources);
296
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300297static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
298static DEFINE_STRARRAY(sighow);
299
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300300static const char *socket_families[] = {
301 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
302 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
303 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
304 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
305 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
306 "ALG", "NFC", "VSOCK",
307};
308static DEFINE_STRARRAY(socket_families);
309
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300310#ifndef SOCK_TYPE_MASK
311#define SOCK_TYPE_MASK 0xf
312#endif
313
314static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
315 struct syscall_arg *arg)
316{
317 size_t printed;
318 int type = arg->val,
319 flags = type & ~SOCK_TYPE_MASK;
320
321 type &= SOCK_TYPE_MASK;
322 /*
323 * Can't use a strarray, MIPS may override for ABI reasons.
324 */
325 switch (type) {
326#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
327 P_SK_TYPE(STREAM);
328 P_SK_TYPE(DGRAM);
329 P_SK_TYPE(RAW);
330 P_SK_TYPE(RDM);
331 P_SK_TYPE(SEQPACKET);
332 P_SK_TYPE(DCCP);
333 P_SK_TYPE(PACKET);
334#undef P_SK_TYPE
335 default:
336 printed = scnprintf(bf, size, "%#x", type);
337 }
338
339#define P_SK_FLAG(n) \
340 if (flags & SOCK_##n) { \
341 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
342 flags &= ~SOCK_##n; \
343 }
344
345 P_SK_FLAG(CLOEXEC);
346 P_SK_FLAG(NONBLOCK);
347#undef P_SK_FLAG
348
349 if (flags)
350 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
351
352 return printed;
353}
354
355#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
356
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300357#ifndef MSG_PROBE
358#define MSG_PROBE 0x10
359#endif
360#ifndef MSG_SENDPAGE_NOTLAST
361#define MSG_SENDPAGE_NOTLAST 0x20000
362#endif
363#ifndef MSG_FASTOPEN
364#define MSG_FASTOPEN 0x20000000
365#endif
366
367static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
368 struct syscall_arg *arg)
369{
370 int printed = 0, flags = arg->val;
371
372 if (flags == 0)
373 return scnprintf(bf, size, "NONE");
374#define P_MSG_FLAG(n) \
375 if (flags & MSG_##n) { \
376 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
377 flags &= ~MSG_##n; \
378 }
379
380 P_MSG_FLAG(OOB);
381 P_MSG_FLAG(PEEK);
382 P_MSG_FLAG(DONTROUTE);
383 P_MSG_FLAG(TRYHARD);
384 P_MSG_FLAG(CTRUNC);
385 P_MSG_FLAG(PROBE);
386 P_MSG_FLAG(TRUNC);
387 P_MSG_FLAG(DONTWAIT);
388 P_MSG_FLAG(EOR);
389 P_MSG_FLAG(WAITALL);
390 P_MSG_FLAG(FIN);
391 P_MSG_FLAG(SYN);
392 P_MSG_FLAG(CONFIRM);
393 P_MSG_FLAG(RST);
394 P_MSG_FLAG(ERRQUEUE);
395 P_MSG_FLAG(NOSIGNAL);
396 P_MSG_FLAG(MORE);
397 P_MSG_FLAG(WAITFORONE);
398 P_MSG_FLAG(SENDPAGE_NOTLAST);
399 P_MSG_FLAG(FASTOPEN);
400 P_MSG_FLAG(CMSG_CLOEXEC);
401#undef P_MSG_FLAG
402
403 if (flags)
404 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
405
406 return printed;
407}
408
409#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
410
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300411static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
412 struct syscall_arg *arg)
413{
414 size_t printed = 0;
415 int mode = arg->val;
416
417 if (mode == F_OK) /* 0 */
418 return scnprintf(bf, size, "F");
419#define P_MODE(n) \
420 if (mode & n##_OK) { \
421 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
422 mode &= ~n##_OK; \
423 }
424
425 P_MODE(R);
426 P_MODE(W);
427 P_MODE(X);
428#undef P_MODE
429
430 if (mode)
431 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
432
433 return printed;
434}
435
436#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
437
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300438static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300439 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300440{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300441 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300442
443 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300444 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300445
446 if (flags == 0)
447 return scnprintf(bf, size, "RDONLY");
448#define P_FLAG(n) \
449 if (flags & O_##n) { \
450 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
451 flags &= ~O_##n; \
452 }
453
454 P_FLAG(APPEND);
455 P_FLAG(ASYNC);
456 P_FLAG(CLOEXEC);
457 P_FLAG(CREAT);
458 P_FLAG(DIRECT);
459 P_FLAG(DIRECTORY);
460 P_FLAG(EXCL);
461 P_FLAG(LARGEFILE);
462 P_FLAG(NOATIME);
463 P_FLAG(NOCTTY);
464#ifdef O_NONBLOCK
465 P_FLAG(NONBLOCK);
466#elif O_NDELAY
467 P_FLAG(NDELAY);
468#endif
469#ifdef O_PATH
470 P_FLAG(PATH);
471#endif
472 P_FLAG(RDWR);
473#ifdef O_DSYNC
474 if ((flags & O_SYNC) == O_SYNC)
475 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
476 else {
477 P_FLAG(DSYNC);
478 }
479#else
480 P_FLAG(SYNC);
481#endif
482 P_FLAG(TRUNC);
483 P_FLAG(WRONLY);
484#undef P_FLAG
485
486 if (flags)
487 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
488
489 return printed;
490}
491
492#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
493
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300494static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
495 struct syscall_arg *arg)
496{
497 int printed = 0, flags = arg->val;
498
499 if (flags == 0)
500 return scnprintf(bf, size, "NONE");
501#define P_FLAG(n) \
502 if (flags & EFD_##n) { \
503 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
504 flags &= ~EFD_##n; \
505 }
506
507 P_FLAG(SEMAPHORE);
508 P_FLAG(CLOEXEC);
509 P_FLAG(NONBLOCK);
510#undef P_FLAG
511
512 if (flags)
513 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
514
515 return printed;
516}
517
518#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
519
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300520static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
521 struct syscall_arg *arg)
522{
523 int printed = 0, flags = arg->val;
524
525#define P_FLAG(n) \
526 if (flags & O_##n) { \
527 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
528 flags &= ~O_##n; \
529 }
530
531 P_FLAG(CLOEXEC);
532 P_FLAG(NONBLOCK);
533#undef P_FLAG
534
535 if (flags)
536 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
537
538 return printed;
539}
540
541#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
542
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300543static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
544{
545 int sig = arg->val;
546
547 switch (sig) {
548#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
549 P_SIGNUM(HUP);
550 P_SIGNUM(INT);
551 P_SIGNUM(QUIT);
552 P_SIGNUM(ILL);
553 P_SIGNUM(TRAP);
554 P_SIGNUM(ABRT);
555 P_SIGNUM(BUS);
556 P_SIGNUM(FPE);
557 P_SIGNUM(KILL);
558 P_SIGNUM(USR1);
559 P_SIGNUM(SEGV);
560 P_SIGNUM(USR2);
561 P_SIGNUM(PIPE);
562 P_SIGNUM(ALRM);
563 P_SIGNUM(TERM);
564 P_SIGNUM(STKFLT);
565 P_SIGNUM(CHLD);
566 P_SIGNUM(CONT);
567 P_SIGNUM(STOP);
568 P_SIGNUM(TSTP);
569 P_SIGNUM(TTIN);
570 P_SIGNUM(TTOU);
571 P_SIGNUM(URG);
572 P_SIGNUM(XCPU);
573 P_SIGNUM(XFSZ);
574 P_SIGNUM(VTALRM);
575 P_SIGNUM(PROF);
576 P_SIGNUM(WINCH);
577 P_SIGNUM(IO);
578 P_SIGNUM(PWR);
579 P_SIGNUM(SYS);
580 default: break;
581 }
582
583 return scnprintf(bf, size, "%#x", sig);
584}
585
586#define SCA_SIGNUM syscall_arg__scnprintf_signum
587
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300588#define STRARRAY(arg, name, array) \
589 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
590 .arg_parm = { [arg] = &strarray__##array, }
591
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300592static struct syscall_fmt {
593 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300594 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300595 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300596 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300597 bool errmsg;
598 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300599 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300600} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300601 { .name = "access", .errmsg = true,
602 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300603 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300604 { .name = "brk", .hexret = true,
605 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300606 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300607 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300608 { .name = "eventfd2", .errmsg = true,
609 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300610 { .name = "fcntl", .errmsg = true, STRARRAY(1, cmd, fcntl_cmds), },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300611 { .name = "flock", .errmsg = true,
612 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300613 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
614 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300615 { .name = "futex", .errmsg = true,
616 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300617 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
618 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300619 { .name = "ioctl", .errmsg = true,
620 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300621 { .name = "kill", .errmsg = true,
622 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300623 { .name = "lseek", .errmsg = true, STRARRAY(2, whence, whences), },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300624 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300625 { .name = "madvise", .errmsg = true,
626 .arg_scnprintf = { [0] = SCA_HEX, /* start */
627 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300628 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300629 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300630 [2] = SCA_MMAP_PROT, /* prot */
631 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300632 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300633 .arg_scnprintf = { [0] = SCA_HEX, /* start */
634 [2] = SCA_MMAP_PROT, /* prot */ }, },
635 { .name = "mremap", .hexret = true,
636 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
637 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300638 { .name = "munmap", .errmsg = true,
639 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300640 { .name = "open", .errmsg = true,
641 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300642 { .name = "open_by_handle_at", .errmsg = true,
643 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
644 { .name = "openat", .errmsg = true,
645 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300646 { .name = "pipe2", .errmsg = true,
647 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300648 { .name = "poll", .errmsg = true, .timeout = true, },
649 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300650 { .name = "pread", .errmsg = true, .alias = "pread64", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300651 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300652 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300653 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300654 { .name = "recvfrom", .errmsg = true,
655 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
656 { .name = "recvmmsg", .errmsg = true,
657 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
658 { .name = "recvmsg", .errmsg = true,
659 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300660 { .name = "rt_sigaction", .errmsg = true,
661 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300662 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300663 { .name = "rt_sigqueueinfo", .errmsg = true,
664 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
665 { .name = "rt_tgsigqueueinfo", .errmsg = true,
666 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300667 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300668 { .name = "sendmmsg", .errmsg = true,
669 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
670 { .name = "sendmsg", .errmsg = true,
671 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
672 { .name = "sendto", .errmsg = true,
673 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300674 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
675 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300676 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300677 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
678 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300679 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300680 { .name = "socketpair", .errmsg = true,
681 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
682 [1] = SCA_SK_TYPE, /* type */ },
683 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300684 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300685 { .name = "tgkill", .errmsg = true,
686 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
687 { .name = "tkill", .errmsg = true,
688 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300689 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300690};
691
692static int syscall_fmt__cmp(const void *name, const void *fmtp)
693{
694 const struct syscall_fmt *fmt = fmtp;
695 return strcmp(name, fmt->name);
696}
697
698static struct syscall_fmt *syscall_fmt__find(const char *name)
699{
700 const int nmemb = ARRAY_SIZE(syscall_fmts);
701 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
702}
703
704struct syscall {
705 struct event_format *tp_format;
706 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300707 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300708 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300709 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300710 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300711};
712
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200713static size_t fprintf_duration(unsigned long t, FILE *fp)
714{
715 double duration = (double)t / NSEC_PER_MSEC;
716 size_t printed = fprintf(fp, "(");
717
718 if (duration >= 1.0)
719 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
720 else if (duration >= 0.01)
721 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
722 else
723 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300724 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200725}
726
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300727struct thread_trace {
728 u64 entry_time;
729 u64 exit_time;
730 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300731 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300732 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300733 double runtime_ms;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300734};
735
736static struct thread_trace *thread_trace__new(void)
737{
738 return zalloc(sizeof(struct thread_trace));
739}
740
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300741static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300742{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300743 struct thread_trace *ttrace;
744
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300745 if (thread == NULL)
746 goto fail;
747
748 if (thread->priv == NULL)
749 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300750
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300751 if (thread->priv == NULL)
752 goto fail;
753
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300754 ttrace = thread->priv;
755 ++ttrace->nr_events;
756
757 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300758fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300759 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300760 "WARNING: not enough memory, dropping samples!\n");
761 return NULL;
762}
763
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300764struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300765 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300766 int audit_machine;
767 struct {
768 int max;
769 struct syscall *table;
770 } syscalls;
771 struct perf_record_opts opts;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300772 struct machine host;
773 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600774 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300775 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300776 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300777 struct strlist *ev_qualifier;
778 bool not_ev_qualifier;
David Ahernbdc89662013-08-28 22:29:53 -0600779 struct intlist *tid_list;
780 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300781 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300782 bool multiple_threads;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300783 bool show_comm;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300784 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300785 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300786};
787
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300788static bool trace__filter_duration(struct trace *trace, double t)
789{
790 return t < (trace->duration_filter * NSEC_PER_MSEC);
791}
792
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300793static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
794{
795 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
796
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200797 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300798}
799
Namhyung Kimf15eb532012-10-05 14:02:16 +0900800static bool done = false;
801
802static void sig_handler(int sig __maybe_unused)
803{
804 done = true;
805}
806
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300807static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200808 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300809{
810 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200811 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300812
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300813 if (trace->multiple_threads) {
814 if (trace->show_comm)
815 printed += fprintf(fp, "%.14s/", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +0300816 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300817 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300818
819 return printed;
820}
821
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300822static int trace__process_event(struct trace *trace, struct machine *machine,
823 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300824{
825 int ret = 0;
826
827 switch (event->header.type) {
828 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300829 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300830 "LOST %" PRIu64 " events!\n", event->lost.lost);
831 ret = machine__process_lost_event(machine, event);
832 default:
833 ret = machine__process_event(machine, event);
834 break;
835 }
836
837 return ret;
838}
839
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300840static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300841 union perf_event *event,
842 struct perf_sample *sample __maybe_unused,
843 struct machine *machine)
844{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300845 struct trace *trace = container_of(tool, struct trace, tool);
846 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300847}
848
849static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
850{
851 int err = symbol__init();
852
853 if (err)
854 return err;
855
856 machine__init(&trace->host, "", HOST_KERNEL_ID);
857 machine__create_kernel_maps(&trace->host);
858
859 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300860 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300861 trace__tool_process,
862 &trace->host);
863 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300864 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300865 &trace->host);
866 }
867
868 if (err)
869 symbol__exit();
870
871 return err;
872}
873
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300874static int syscall__set_arg_fmts(struct syscall *sc)
875{
876 struct format_field *field;
877 int idx = 0;
878
879 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
880 if (sc->arg_scnprintf == NULL)
881 return -1;
882
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300883 if (sc->fmt)
884 sc->arg_parm = sc->fmt->arg_parm;
885
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300886 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300887 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
888 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
889 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300890 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
891 ++idx;
892 }
893
894 return 0;
895}
896
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300897static int trace__read_syscall_info(struct trace *trace, int id)
898{
899 char tp_name[128];
900 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300901 const char *name = audit_syscall_to_name(id, trace->audit_machine);
902
903 if (name == NULL)
904 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300905
906 if (id > trace->syscalls.max) {
907 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
908
909 if (nsyscalls == NULL)
910 return -1;
911
912 if (trace->syscalls.max != -1) {
913 memset(nsyscalls + trace->syscalls.max + 1, 0,
914 (id - trace->syscalls.max) * sizeof(*sc));
915 } else {
916 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
917 }
918
919 trace->syscalls.table = nsyscalls;
920 trace->syscalls.max = id;
921 }
922
923 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300924 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300925
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300926 if (trace->ev_qualifier) {
927 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
928
929 if (!(in ^ trace->not_ev_qualifier)) {
930 sc->filtered = true;
931 /*
932 * No need to do read tracepoint information since this will be
933 * filtered out.
934 */
935 return 0;
936 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300937 }
938
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300939 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300940
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300941 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
942 sc->tp_format = event_format__new("syscalls", tp_name);
943
944 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
945 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
946 sc->tp_format = event_format__new("syscalls", tp_name);
947 }
948
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300949 if (sc->tp_format == NULL)
950 return -1;
951
952 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300953}
954
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300955static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
956 unsigned long *args)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300957{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300958 size_t printed = 0;
959
960 if (sc->tp_format != NULL) {
961 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300962 u8 bit = 1;
963 struct syscall_arg arg = {
964 .idx = 0,
965 .mask = 0,
966 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300967
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300968 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300969 field = field->next, ++arg.idx, bit <<= 1) {
970 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300971 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -0300972 /*
973 * Suppress this argument if its value is zero and
974 * and we don't have a string associated in an
975 * strarray for it.
976 */
977 if (args[arg.idx] == 0 &&
978 !(sc->arg_scnprintf &&
979 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
980 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -0300981 continue;
982
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300983 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300984 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300985 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
986 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300987 if (sc->arg_parm)
988 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300989 printed += sc->arg_scnprintf[arg.idx](bf + printed,
990 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300991 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300992 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300993 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300994 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300995 }
996 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300997 int i = 0;
998
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300999 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001000 printed += scnprintf(bf + printed, size - printed,
1001 "%sarg%d: %ld",
1002 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001003 ++i;
1004 }
1005 }
1006
1007 return printed;
1008}
1009
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001010typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1011 struct perf_sample *sample);
1012
1013static struct syscall *trace__syscall_info(struct trace *trace,
1014 struct perf_evsel *evsel,
1015 struct perf_sample *sample)
1016{
1017 int id = perf_evsel__intval(evsel, sample, "id");
1018
1019 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001020
1021 /*
1022 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1023 * before that, leaving at a higher verbosity level till that is
1024 * explained. Reproduced with plain ftrace with:
1025 *
1026 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1027 * grep "NR -1 " /t/trace_pipe
1028 *
1029 * After generating some load on the machine.
1030 */
1031 if (verbose > 1) {
1032 static u64 n;
1033 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1034 id, perf_evsel__name(evsel), ++n);
1035 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001036 return NULL;
1037 }
1038
1039 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1040 trace__read_syscall_info(trace, id))
1041 goto out_cant_read;
1042
1043 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1044 goto out_cant_read;
1045
1046 return &trace->syscalls.table[id];
1047
1048out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001049 if (verbose) {
1050 fprintf(trace->output, "Problems reading syscall %d", id);
1051 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1052 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1053 fputs(" information\n", trace->output);
1054 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001055 return NULL;
1056}
1057
1058static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1059 struct perf_sample *sample)
1060{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001061 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001062 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001063 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001064 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001065 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001066 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001067
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001068 if (sc == NULL)
1069 return -1;
1070
1071 if (sc->filtered)
1072 return 0;
1073
Adrian Hunter314add62013-08-27 11:23:03 +03001074 thread = machine__findnew_thread(&trace->host, sample->pid,
1075 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001076 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001077 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001078 return -1;
1079
1080 args = perf_evsel__rawptr(evsel, sample, "args");
1081 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001082 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001083 return -1;
1084 }
1085
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001086 ttrace = thread->priv;
1087
1088 if (ttrace->entry_str == NULL) {
1089 ttrace->entry_str = malloc(1024);
1090 if (!ttrace->entry_str)
1091 return -1;
1092 }
1093
1094 ttrace->entry_time = sample->time;
1095 msg = ttrace->entry_str;
1096 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1097
1098 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
1099
1100 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001101 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001102 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1103 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001104 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001105 } else
1106 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001107
1108 return 0;
1109}
1110
1111static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1112 struct perf_sample *sample)
1113{
1114 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001115 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001116 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001117 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001118 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001119
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001120 if (sc == NULL)
1121 return -1;
1122
1123 if (sc->filtered)
1124 return 0;
1125
Adrian Hunter314add62013-08-27 11:23:03 +03001126 thread = machine__findnew_thread(&trace->host, sample->pid,
1127 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001128 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001129 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001130 return -1;
1131
1132 ret = perf_evsel__intval(evsel, sample, "ret");
1133
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001134 ttrace = thread->priv;
1135
1136 ttrace->exit_time = sample->time;
1137
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001138 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001139 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001140 if (trace__filter_duration(trace, duration))
1141 goto out;
1142 } else if (trace->duration_filter)
1143 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001144
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001145 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001146
1147 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001148 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001149 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001150 fprintf(trace->output, " ... [");
1151 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1152 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001153 }
1154
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001155 if (sc->fmt == NULL) {
1156signed_print:
1157 fprintf(trace->output, ") = %d", ret);
1158 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001159 char bf[256];
1160 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1161 *e = audit_errno_to_name(-ret);
1162
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001163 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001164 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001165 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001166 else if (sc->fmt->hexret)
1167 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001168 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001169 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001170
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001171 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001172out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001173 ttrace->entry_pending = false;
1174
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001175 return 0;
1176}
1177
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001178static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1179 struct perf_sample *sample)
1180{
1181 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1182 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
Adrian Hunter314add62013-08-27 11:23:03 +03001183 struct thread *thread = machine__findnew_thread(&trace->host,
1184 sample->pid,
1185 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001186 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001187
1188 if (ttrace == NULL)
1189 goto out_dump;
1190
1191 ttrace->runtime_ms += runtime_ms;
1192 trace->runtime_ms += runtime_ms;
1193 return 0;
1194
1195out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001196 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001197 evsel->name,
1198 perf_evsel__strval(evsel, sample, "comm"),
1199 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1200 runtime,
1201 perf_evsel__intval(evsel, sample, "vruntime"));
1202 return 0;
1203}
1204
David Ahernbdc89662013-08-28 22:29:53 -06001205static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1206{
1207 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1208 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1209 return false;
1210
1211 if (trace->pid_list || trace->tid_list)
1212 return true;
1213
1214 return false;
1215}
1216
David Ahern6810fc92013-08-28 22:29:52 -06001217static int trace__process_sample(struct perf_tool *tool,
1218 union perf_event *event __maybe_unused,
1219 struct perf_sample *sample,
1220 struct perf_evsel *evsel,
1221 struct machine *machine __maybe_unused)
1222{
1223 struct trace *trace = container_of(tool, struct trace, tool);
1224 int err = 0;
1225
1226 tracepoint_handler handler = evsel->handler.func;
1227
David Ahernbdc89662013-08-28 22:29:53 -06001228 if (skip_sample(trace, sample))
1229 return 0;
1230
David Ahern4bb09192013-09-04 12:37:43 -06001231 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001232 trace->base_time = sample->time;
1233
1234 if (handler)
1235 handler(trace, evsel, sample);
1236
1237 return err;
1238}
1239
1240static bool
1241perf_session__has_tp(struct perf_session *session, const char *name)
1242{
1243 struct perf_evsel *evsel;
1244
1245 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1246
1247 return evsel != NULL;
1248}
1249
David Ahernbdc89662013-08-28 22:29:53 -06001250static int parse_target_str(struct trace *trace)
1251{
1252 if (trace->opts.target.pid) {
1253 trace->pid_list = intlist__new(trace->opts.target.pid);
1254 if (trace->pid_list == NULL) {
1255 pr_err("Error parsing process id string\n");
1256 return -EINVAL;
1257 }
1258 }
1259
1260 if (trace->opts.target.tid) {
1261 trace->tid_list = intlist__new(trace->opts.target.tid);
1262 if (trace->tid_list == NULL) {
1263 pr_err("Error parsing thread id string\n");
1264 return -EINVAL;
1265 }
1266 }
1267
1268 return 0;
1269}
1270
Namhyung Kimf15eb532012-10-05 14:02:16 +09001271static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001272{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001273 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001274 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001275 int err = -1, i;
1276 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001277 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001278
1279 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001280 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001281 goto out;
1282 }
1283
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001284 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1285 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001286 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001287 goto out_delete_evlist;
1288 }
1289
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001290 if (trace->sched &&
1291 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1292 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001293 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001294 goto out_delete_evlist;
1295 }
1296
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001297 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1298 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001299 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001300 goto out_delete_evlist;
1301 }
1302
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001303 err = trace__symbols_init(trace, evlist);
1304 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001305 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001306 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001307 }
1308
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001309 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001310
Namhyung Kimf15eb532012-10-05 14:02:16 +09001311 signal(SIGCHLD, sig_handler);
1312 signal(SIGINT, sig_handler);
1313
1314 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001315 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001316 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001317 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001318 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001319 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001320 }
1321 }
1322
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001323 err = perf_evlist__open(evlist);
1324 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001325 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001326 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001327 }
1328
1329 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1330 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001331 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001332 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001333 }
1334
1335 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001336
1337 if (forks)
1338 perf_evlist__start_workload(evlist);
1339
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001340 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001341again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001342 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001343
1344 for (i = 0; i < evlist->nr_mmaps; i++) {
1345 union perf_event *event;
1346
1347 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1348 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001349 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001350 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001351
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001352 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001353
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001354 err = perf_evlist__parse_sample(evlist, event, &sample);
1355 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001356 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001357 continue;
1358 }
1359
David Ahern4bb09192013-09-04 12:37:43 -06001360 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001361 trace->base_time = sample.time;
1362
1363 if (type != PERF_RECORD_SAMPLE) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001364 trace__process_event(trace, &trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001365 continue;
1366 }
1367
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001368 evsel = perf_evlist__id2evsel(evlist, sample.id);
1369 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001370 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001371 continue;
1372 }
1373
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001374 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001375 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 -03001376 perf_evsel__name(evsel), sample.tid,
1377 sample.cpu, sample.raw_size);
1378 continue;
1379 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001380
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001381 handler = evsel->handler.func;
1382 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001383
1384 if (done)
1385 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001386 }
1387 }
1388
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001389 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001390 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001391 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001392
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001393 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001394 }
1395
1396 if (done)
1397 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001398
1399 goto again;
1400
Namhyung Kim3beb0862013-03-15 14:48:50 +09001401out_unmap_evlist:
1402 perf_evlist__munmap(evlist);
1403out_close_evlist:
1404 perf_evlist__close(evlist);
1405out_delete_maps:
1406 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001407out_delete_evlist:
1408 perf_evlist__delete(evlist);
1409out:
1410 return err;
1411}
1412
David Ahern6810fc92013-08-28 22:29:52 -06001413static int trace__replay(struct trace *trace)
1414{
1415 const struct perf_evsel_str_handler handlers[] = {
1416 { "raw_syscalls:sys_enter", trace__sys_enter, },
1417 { "raw_syscalls:sys_exit", trace__sys_exit, },
1418 };
1419
1420 struct perf_session *session;
1421 int err = -1;
1422
1423 trace->tool.sample = trace__process_sample;
1424 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001425 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001426 trace->tool.comm = perf_event__process_comm;
1427 trace->tool.exit = perf_event__process_exit;
1428 trace->tool.fork = perf_event__process_fork;
1429 trace->tool.attr = perf_event__process_attr;
1430 trace->tool.tracing_data = perf_event__process_tracing_data;
1431 trace->tool.build_id = perf_event__process_build_id;
1432
1433 trace->tool.ordered_samples = true;
1434 trace->tool.ordering_requires_timestamps = true;
1435
1436 /* add tid to output */
1437 trace->multiple_threads = true;
1438
1439 if (symbol__init() < 0)
1440 return -1;
1441
1442 session = perf_session__new(input_name, O_RDONLY, 0, false,
1443 &trace->tool);
1444 if (session == NULL)
1445 return -ENOMEM;
1446
1447 err = perf_session__set_tracepoints_handlers(session, handlers);
1448 if (err)
1449 goto out;
1450
1451 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1452 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1453 goto out;
1454 }
1455
1456 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1457 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1458 goto out;
1459 }
1460
David Ahernbdc89662013-08-28 22:29:53 -06001461 err = parse_target_str(trace);
1462 if (err != 0)
1463 goto out;
1464
David Ahern6810fc92013-08-28 22:29:52 -06001465 setup_pager();
1466
1467 err = perf_session__process_events(session, &trace->tool);
1468 if (err)
1469 pr_err("Failed to process events, error %d", err);
1470
1471out:
1472 perf_session__delete(session);
1473
1474 return err;
1475}
1476
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001477static size_t trace__fprintf_threads_header(FILE *fp)
1478{
1479 size_t printed;
1480
1481 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1482 printed += fprintf(fp," __) Summary of events (__\n\n");
1483 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1484 printed += fprintf(fp," _____________________________________________________________________\n\n");
1485
1486 return printed;
1487}
1488
1489static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1490{
1491 size_t printed = trace__fprintf_threads_header(fp);
1492 struct rb_node *nd;
1493
1494 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1495 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1496 struct thread_trace *ttrace = thread->priv;
1497 const char *color;
1498 double ratio;
1499
1500 if (ttrace == NULL)
1501 continue;
1502
1503 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1504
1505 color = PERF_COLOR_NORMAL;
1506 if (ratio > 50.0)
1507 color = PERF_COLOR_RED;
1508 else if (ratio > 25.0)
1509 color = PERF_COLOR_GREEN;
1510 else if (ratio > 5.0)
1511 color = PERF_COLOR_YELLOW;
1512
1513 printed += color_fprintf(fp, color, "%20s", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001514 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001515 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1516 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1517 }
1518
1519 return printed;
1520}
1521
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001522static int trace__set_duration(const struct option *opt, const char *str,
1523 int unset __maybe_unused)
1524{
1525 struct trace *trace = opt->value;
1526
1527 trace->duration_filter = atof(str);
1528 return 0;
1529}
1530
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001531static int trace__open_output(struct trace *trace, const char *filename)
1532{
1533 struct stat st;
1534
1535 if (!stat(filename, &st) && st.st_size) {
1536 char oldname[PATH_MAX];
1537
1538 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1539 unlink(oldname);
1540 rename(filename, oldname);
1541 }
1542
1543 trace->output = fopen(filename, "w");
1544
1545 return trace->output == NULL ? -errno : 0;
1546}
1547
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001548int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1549{
1550 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001551 "perf trace [<options>] [<command>]",
1552 "perf trace [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001553 NULL
1554 };
1555 struct trace trace = {
1556 .audit_machine = audit_detect_machine(),
1557 .syscalls = {
1558 . max = -1,
1559 },
1560 .opts = {
1561 .target = {
1562 .uid = UINT_MAX,
1563 .uses_mmap = true,
1564 },
1565 .user_freq = UINT_MAX,
1566 .user_interval = ULLONG_MAX,
1567 .no_delay = true,
1568 .mmap_pages = 1024,
1569 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001570 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001571 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001572 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001573 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001574 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001575 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001576 OPT_BOOLEAN(0, "comm", &trace.show_comm,
1577 "show the thread COMM next to its id"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001578 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1579 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001580 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001581 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001582 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1583 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001584 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001585 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001586 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001587 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001588 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001589 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001590 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001591 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02001592 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1593 "number of mmap data pages",
1594 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06001595 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001596 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001597 OPT_CALLBACK(0, "duration", &trace, "float",
1598 "show only events with duration > N.M ms",
1599 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001600 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001601 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06001602 OPT_BOOLEAN('T', "time", &trace.full_time,
1603 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001604 OPT_END()
1605 };
1606 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001607 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001608
1609 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001610
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001611 if (output_name != NULL) {
1612 err = trace__open_output(&trace, output_name);
1613 if (err < 0) {
1614 perror("failed to create output file");
1615 goto out;
1616 }
1617 }
1618
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001619 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001620 const char *s = ev_qualifier_str;
1621
1622 trace.not_ev_qualifier = *s == '!';
1623 if (trace.not_ev_qualifier)
1624 ++s;
1625 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001626 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001627 fputs("Not enough memory to parse event qualifier",
1628 trace.output);
1629 err = -ENOMEM;
1630 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001631 }
1632 }
1633
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001634 err = perf_target__validate(&trace.opts.target);
1635 if (err) {
1636 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001637 fprintf(trace.output, "%s", bf);
1638 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001639 }
1640
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001641 err = perf_target__parse_uid(&trace.opts.target);
1642 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001643 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001644 fprintf(trace.output, "%s", bf);
1645 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001646 }
1647
Namhyung Kimf15eb532012-10-05 14:02:16 +09001648 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001649 trace.opts.target.system_wide = true;
1650
David Ahern6810fc92013-08-28 22:29:52 -06001651 if (input_name)
1652 err = trace__replay(&trace);
1653 else
1654 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001655
1656 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001657 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001658
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001659out_close:
1660 if (output_name != NULL)
1661 fclose(trace.output);
1662out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001663 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001664}