blob: 763bef45afadd8c18592afe665503a083c700b0d [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"
David Ahernbf2575c2013-10-08 21:26:53 -060013#include "util/stat.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030014
15#include <libaudit.h>
16#include <stdlib.h>
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -030017#include <sys/eventfd.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030018#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030019#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030020
Ingo Molnar456857b2013-09-12 15:29:00 +020021/* For older distros: */
22#ifndef MAP_STACK
23# define MAP_STACK 0x20000
24#endif
25
26#ifndef MADV_HWPOISON
27# define MADV_HWPOISON 100
28#endif
29
30#ifndef MADV_MERGEABLE
31# define MADV_MERGEABLE 12
32#endif
33
34#ifndef MADV_UNMERGEABLE
35# define MADV_UNMERGEABLE 13
36#endif
37
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030038struct syscall_arg {
39 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -030040 struct thread *thread;
41 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030042 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030043 u8 idx;
44 u8 mask;
45};
46
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030047struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -030048 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030049 int nr_entries;
50 const char **entries;
51};
52
53#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
54 .nr_entries = ARRAY_SIZE(array), \
55 .entries = array, \
56}
57
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -030058#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
59 .offset = off, \
60 .nr_entries = ARRAY_SIZE(array), \
61 .entries = array, \
62}
63
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -030064static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
65 const char *intfmt,
66 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030067{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030068 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -030069 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030070
71 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -030072 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030073
74 return scnprintf(bf, size, "%s", sa->entries[idx]);
75}
76
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -030077static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
78 struct syscall_arg *arg)
79{
80 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
81}
82
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030083#define SCA_STRARRAY syscall_arg__scnprintf_strarray
84
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -030085static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
86 struct syscall_arg *arg)
87{
88 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
89}
90
91#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
92
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -030093static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
94 struct syscall_arg *arg);
95
96#define SCA_FD syscall_arg__scnprintf_fd
97
98static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
99 struct syscall_arg *arg)
100{
101 int fd = arg->val;
102
103 if (fd == AT_FDCWD)
104 return scnprintf(bf, size, "CWD");
105
106 return syscall_arg__scnprintf_fd(bf, size, arg);
107}
108
109#define SCA_FDAT syscall_arg__scnprintf_fd_at
110
111static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
112 struct syscall_arg *arg);
113
114#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
115
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300116static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300117 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300118{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300119 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300120}
121
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300122#define SCA_HEX syscall_arg__scnprintf_hex
123
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300124static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300125 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300126{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300127 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300128
129 if (prot == PROT_NONE)
130 return scnprintf(bf, size, "NONE");
131#define P_MMAP_PROT(n) \
132 if (prot & PROT_##n) { \
133 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
134 prot &= ~PROT_##n; \
135 }
136
137 P_MMAP_PROT(EXEC);
138 P_MMAP_PROT(READ);
139 P_MMAP_PROT(WRITE);
140#ifdef PROT_SEM
141 P_MMAP_PROT(SEM);
142#endif
143 P_MMAP_PROT(GROWSDOWN);
144 P_MMAP_PROT(GROWSUP);
145#undef P_MMAP_PROT
146
147 if (prot)
148 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
149
150 return printed;
151}
152
153#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
154
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300155static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300156 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300157{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300158 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300159
160#define P_MMAP_FLAG(n) \
161 if (flags & MAP_##n) { \
162 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
163 flags &= ~MAP_##n; \
164 }
165
166 P_MMAP_FLAG(SHARED);
167 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400168#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300169 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400170#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300171 P_MMAP_FLAG(ANONYMOUS);
172 P_MMAP_FLAG(DENYWRITE);
173 P_MMAP_FLAG(EXECUTABLE);
174 P_MMAP_FLAG(FILE);
175 P_MMAP_FLAG(FIXED);
176 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600177#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300178 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600179#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300180 P_MMAP_FLAG(LOCKED);
181 P_MMAP_FLAG(NONBLOCK);
182 P_MMAP_FLAG(NORESERVE);
183 P_MMAP_FLAG(POPULATE);
184 P_MMAP_FLAG(STACK);
185#ifdef MAP_UNINITIALIZED
186 P_MMAP_FLAG(UNINITIALIZED);
187#endif
188#undef P_MMAP_FLAG
189
190 if (flags)
191 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
192
193 return printed;
194}
195
196#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
197
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300198static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300199 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300200{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300201 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300202
203 switch (behavior) {
204#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
205 P_MADV_BHV(NORMAL);
206 P_MADV_BHV(RANDOM);
207 P_MADV_BHV(SEQUENTIAL);
208 P_MADV_BHV(WILLNEED);
209 P_MADV_BHV(DONTNEED);
210 P_MADV_BHV(REMOVE);
211 P_MADV_BHV(DONTFORK);
212 P_MADV_BHV(DOFORK);
213 P_MADV_BHV(HWPOISON);
214#ifdef MADV_SOFT_OFFLINE
215 P_MADV_BHV(SOFT_OFFLINE);
216#endif
217 P_MADV_BHV(MERGEABLE);
218 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600219#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300220 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600221#endif
222#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300223 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600224#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300225#ifdef MADV_DONTDUMP
226 P_MADV_BHV(DONTDUMP);
227#endif
228#ifdef MADV_DODUMP
229 P_MADV_BHV(DODUMP);
230#endif
231#undef P_MADV_PHV
232 default: break;
233 }
234
235 return scnprintf(bf, size, "%#x", behavior);
236}
237
238#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
239
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300240static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
241 struct syscall_arg *arg)
242{
243 int printed = 0, op = arg->val;
244
245 if (op == 0)
246 return scnprintf(bf, size, "NONE");
247#define P_CMD(cmd) \
248 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
249 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
250 op &= ~LOCK_##cmd; \
251 }
252
253 P_CMD(SH);
254 P_CMD(EX);
255 P_CMD(NB);
256 P_CMD(UN);
257 P_CMD(MAND);
258 P_CMD(RW);
259 P_CMD(READ);
260 P_CMD(WRITE);
261#undef P_OP
262
263 if (op)
264 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
265
266 return printed;
267}
268
269#define SCA_FLOCK syscall_arg__scnprintf_flock
270
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300271static 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 -0300272{
273 enum syscall_futex_args {
274 SCF_UADDR = (1 << 0),
275 SCF_OP = (1 << 1),
276 SCF_VAL = (1 << 2),
277 SCF_TIMEOUT = (1 << 3),
278 SCF_UADDR2 = (1 << 4),
279 SCF_VAL3 = (1 << 5),
280 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300281 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300282 int cmd = op & FUTEX_CMD_MASK;
283 size_t printed = 0;
284
285 switch (cmd) {
286#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300287 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
288 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
289 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
290 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
291 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
292 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300293 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300294 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
295 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
296 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
297 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
298 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300299 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
300 default: printed = scnprintf(bf, size, "%#x", cmd); break;
301 }
302
303 if (op & FUTEX_PRIVATE_FLAG)
304 printed += scnprintf(bf + printed, size - printed, "|PRIV");
305
306 if (op & FUTEX_CLOCK_REALTIME)
307 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
308
309 return printed;
310}
311
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300312#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
313
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300314static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
315static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300316
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300317static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
318static DEFINE_STRARRAY(itimers);
319
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300320static const char *whences[] = { "SET", "CUR", "END",
321#ifdef SEEK_DATA
322"DATA",
323#endif
324#ifdef SEEK_HOLE
325"HOLE",
326#endif
327};
328static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300329
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300330static const char *fcntl_cmds[] = {
331 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
332 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
333 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
334 "F_GETOWNER_UIDS",
335};
336static DEFINE_STRARRAY(fcntl_cmds);
337
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300338static const char *rlimit_resources[] = {
339 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
340 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
341 "RTTIME",
342};
343static DEFINE_STRARRAY(rlimit_resources);
344
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300345static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
346static DEFINE_STRARRAY(sighow);
347
David Ahern4f8c1b72013-09-22 19:45:00 -0600348static const char *clockid[] = {
349 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
350 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
351};
352static DEFINE_STRARRAY(clockid);
353
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300354static const char *socket_families[] = {
355 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
356 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
357 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
358 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
359 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
360 "ALG", "NFC", "VSOCK",
361};
362static DEFINE_STRARRAY(socket_families);
363
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300364#ifndef SOCK_TYPE_MASK
365#define SOCK_TYPE_MASK 0xf
366#endif
367
368static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
369 struct syscall_arg *arg)
370{
371 size_t printed;
372 int type = arg->val,
373 flags = type & ~SOCK_TYPE_MASK;
374
375 type &= SOCK_TYPE_MASK;
376 /*
377 * Can't use a strarray, MIPS may override for ABI reasons.
378 */
379 switch (type) {
380#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
381 P_SK_TYPE(STREAM);
382 P_SK_TYPE(DGRAM);
383 P_SK_TYPE(RAW);
384 P_SK_TYPE(RDM);
385 P_SK_TYPE(SEQPACKET);
386 P_SK_TYPE(DCCP);
387 P_SK_TYPE(PACKET);
388#undef P_SK_TYPE
389 default:
390 printed = scnprintf(bf, size, "%#x", type);
391 }
392
393#define P_SK_FLAG(n) \
394 if (flags & SOCK_##n) { \
395 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
396 flags &= ~SOCK_##n; \
397 }
398
399 P_SK_FLAG(CLOEXEC);
400 P_SK_FLAG(NONBLOCK);
401#undef P_SK_FLAG
402
403 if (flags)
404 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
405
406 return printed;
407}
408
409#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
410
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300411#ifndef MSG_PROBE
412#define MSG_PROBE 0x10
413#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600414#ifndef MSG_WAITFORONE
415#define MSG_WAITFORONE 0x10000
416#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300417#ifndef MSG_SENDPAGE_NOTLAST
418#define MSG_SENDPAGE_NOTLAST 0x20000
419#endif
420#ifndef MSG_FASTOPEN
421#define MSG_FASTOPEN 0x20000000
422#endif
423
424static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
425 struct syscall_arg *arg)
426{
427 int printed = 0, flags = arg->val;
428
429 if (flags == 0)
430 return scnprintf(bf, size, "NONE");
431#define P_MSG_FLAG(n) \
432 if (flags & MSG_##n) { \
433 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
434 flags &= ~MSG_##n; \
435 }
436
437 P_MSG_FLAG(OOB);
438 P_MSG_FLAG(PEEK);
439 P_MSG_FLAG(DONTROUTE);
440 P_MSG_FLAG(TRYHARD);
441 P_MSG_FLAG(CTRUNC);
442 P_MSG_FLAG(PROBE);
443 P_MSG_FLAG(TRUNC);
444 P_MSG_FLAG(DONTWAIT);
445 P_MSG_FLAG(EOR);
446 P_MSG_FLAG(WAITALL);
447 P_MSG_FLAG(FIN);
448 P_MSG_FLAG(SYN);
449 P_MSG_FLAG(CONFIRM);
450 P_MSG_FLAG(RST);
451 P_MSG_FLAG(ERRQUEUE);
452 P_MSG_FLAG(NOSIGNAL);
453 P_MSG_FLAG(MORE);
454 P_MSG_FLAG(WAITFORONE);
455 P_MSG_FLAG(SENDPAGE_NOTLAST);
456 P_MSG_FLAG(FASTOPEN);
457 P_MSG_FLAG(CMSG_CLOEXEC);
458#undef P_MSG_FLAG
459
460 if (flags)
461 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
462
463 return printed;
464}
465
466#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
467
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300468static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
469 struct syscall_arg *arg)
470{
471 size_t printed = 0;
472 int mode = arg->val;
473
474 if (mode == F_OK) /* 0 */
475 return scnprintf(bf, size, "F");
476#define P_MODE(n) \
477 if (mode & n##_OK) { \
478 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
479 mode &= ~n##_OK; \
480 }
481
482 P_MODE(R);
483 P_MODE(W);
484 P_MODE(X);
485#undef P_MODE
486
487 if (mode)
488 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
489
490 return printed;
491}
492
493#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
494
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300495static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300496 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300497{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300498 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300499
500 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300501 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300502
503 if (flags == 0)
504 return scnprintf(bf, size, "RDONLY");
505#define P_FLAG(n) \
506 if (flags & O_##n) { \
507 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
508 flags &= ~O_##n; \
509 }
510
511 P_FLAG(APPEND);
512 P_FLAG(ASYNC);
513 P_FLAG(CLOEXEC);
514 P_FLAG(CREAT);
515 P_FLAG(DIRECT);
516 P_FLAG(DIRECTORY);
517 P_FLAG(EXCL);
518 P_FLAG(LARGEFILE);
519 P_FLAG(NOATIME);
520 P_FLAG(NOCTTY);
521#ifdef O_NONBLOCK
522 P_FLAG(NONBLOCK);
523#elif O_NDELAY
524 P_FLAG(NDELAY);
525#endif
526#ifdef O_PATH
527 P_FLAG(PATH);
528#endif
529 P_FLAG(RDWR);
530#ifdef O_DSYNC
531 if ((flags & O_SYNC) == O_SYNC)
532 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
533 else {
534 P_FLAG(DSYNC);
535 }
536#else
537 P_FLAG(SYNC);
538#endif
539 P_FLAG(TRUNC);
540 P_FLAG(WRONLY);
541#undef P_FLAG
542
543 if (flags)
544 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
545
546 return printed;
547}
548
549#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
550
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300551static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
552 struct syscall_arg *arg)
553{
554 int printed = 0, flags = arg->val;
555
556 if (flags == 0)
557 return scnprintf(bf, size, "NONE");
558#define P_FLAG(n) \
559 if (flags & EFD_##n) { \
560 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
561 flags &= ~EFD_##n; \
562 }
563
564 P_FLAG(SEMAPHORE);
565 P_FLAG(CLOEXEC);
566 P_FLAG(NONBLOCK);
567#undef P_FLAG
568
569 if (flags)
570 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
571
572 return printed;
573}
574
575#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
576
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300577static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
578 struct syscall_arg *arg)
579{
580 int printed = 0, flags = arg->val;
581
582#define P_FLAG(n) \
583 if (flags & O_##n) { \
584 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
585 flags &= ~O_##n; \
586 }
587
588 P_FLAG(CLOEXEC);
589 P_FLAG(NONBLOCK);
590#undef P_FLAG
591
592 if (flags)
593 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
594
595 return printed;
596}
597
598#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
599
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300600static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
601{
602 int sig = arg->val;
603
604 switch (sig) {
605#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
606 P_SIGNUM(HUP);
607 P_SIGNUM(INT);
608 P_SIGNUM(QUIT);
609 P_SIGNUM(ILL);
610 P_SIGNUM(TRAP);
611 P_SIGNUM(ABRT);
612 P_SIGNUM(BUS);
613 P_SIGNUM(FPE);
614 P_SIGNUM(KILL);
615 P_SIGNUM(USR1);
616 P_SIGNUM(SEGV);
617 P_SIGNUM(USR2);
618 P_SIGNUM(PIPE);
619 P_SIGNUM(ALRM);
620 P_SIGNUM(TERM);
621 P_SIGNUM(STKFLT);
622 P_SIGNUM(CHLD);
623 P_SIGNUM(CONT);
624 P_SIGNUM(STOP);
625 P_SIGNUM(TSTP);
626 P_SIGNUM(TTIN);
627 P_SIGNUM(TTOU);
628 P_SIGNUM(URG);
629 P_SIGNUM(XCPU);
630 P_SIGNUM(XFSZ);
631 P_SIGNUM(VTALRM);
632 P_SIGNUM(PROF);
633 P_SIGNUM(WINCH);
634 P_SIGNUM(IO);
635 P_SIGNUM(PWR);
636 P_SIGNUM(SYS);
637 default: break;
638 }
639
640 return scnprintf(bf, size, "%#x", sig);
641}
642
643#define SCA_SIGNUM syscall_arg__scnprintf_signum
644
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300645#define TCGETS 0x5401
646
647static const char *tioctls[] = {
648 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
649 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
650 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
651 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
652 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
653 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
654 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
655 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
656 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
657 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
658 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
659 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
660 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
661 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
662 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
663};
664
665static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
666
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300667#define STRARRAY(arg, name, array) \
668 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
669 .arg_parm = { [arg] = &strarray__##array, }
670
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300671static struct syscall_fmt {
672 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300673 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300674 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300675 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300676 bool errmsg;
677 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300678 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300679} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300680 { .name = "access", .errmsg = true,
681 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300682 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300683 { .name = "brk", .hexret = true,
684 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600685 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300686 { .name = "close", .errmsg = true,
687 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300688 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300689 { .name = "dup", .errmsg = true,
690 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
691 { .name = "dup2", .errmsg = true,
692 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
693 { .name = "dup3", .errmsg = true,
694 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300695 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300696 { .name = "eventfd2", .errmsg = true,
697 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300698 { .name = "faccessat", .errmsg = true,
699 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
700 { .name = "fadvise64", .errmsg = true,
701 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
702 { .name = "fallocate", .errmsg = true,
703 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
704 { .name = "fchdir", .errmsg = true,
705 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
706 { .name = "fchmod", .errmsg = true,
707 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
708 { .name = "fchmodat", .errmsg = true,
709 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
710 { .name = "fchown", .errmsg = true,
711 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
712 { .name = "fchownat", .errmsg = true,
713 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
714 { .name = "fcntl", .errmsg = true,
715 .arg_scnprintf = { [0] = SCA_FD, /* fd */
716 [1] = SCA_STRARRAY, /* cmd */ },
717 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
718 { .name = "fdatasync", .errmsg = true,
719 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300720 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300721 .arg_scnprintf = { [0] = SCA_FD, /* fd */
722 [1] = SCA_FLOCK, /* cmd */ }, },
723 { .name = "fsetxattr", .errmsg = true,
724 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
725 { .name = "fstat", .errmsg = true, .alias = "newfstat",
726 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
727 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
728 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
729 { .name = "fstatfs", .errmsg = true,
730 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
731 { .name = "fsync", .errmsg = true,
732 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
733 { .name = "ftruncate", .errmsg = true,
734 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300735 { .name = "futex", .errmsg = true,
736 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300737 { .name = "futimesat", .errmsg = true,
738 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
739 { .name = "getdents", .errmsg = true,
740 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
741 { .name = "getdents64", .errmsg = true,
742 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300743 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
744 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300745 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300746 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300747 [1] = SCA_STRHEXARRAY, /* cmd */
748 [2] = SCA_HEX, /* arg */ },
749 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300750 { .name = "kill", .errmsg = true,
751 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300752 { .name = "linkat", .errmsg = true,
753 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
754 { .name = "lseek", .errmsg = true,
755 .arg_scnprintf = { [0] = SCA_FD, /* fd */
756 [2] = SCA_STRARRAY, /* whence */ },
757 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300758 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300759 { .name = "madvise", .errmsg = true,
760 .arg_scnprintf = { [0] = SCA_HEX, /* start */
761 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300762 { .name = "mkdirat", .errmsg = true,
763 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
764 { .name = "mknodat", .errmsg = true,
765 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300766 { .name = "mlock", .errmsg = true,
767 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
768 { .name = "mlockall", .errmsg = true,
769 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300770 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300771 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300772 [2] = SCA_MMAP_PROT, /* prot */
773 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300774 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300775 .arg_scnprintf = { [0] = SCA_HEX, /* start */
776 [2] = SCA_MMAP_PROT, /* prot */ }, },
777 { .name = "mremap", .hexret = true,
778 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
779 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300780 { .name = "munlock", .errmsg = true,
781 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300782 { .name = "munmap", .errmsg = true,
783 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300784 { .name = "name_to_handle_at", .errmsg = true,
785 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
786 { .name = "newfstatat", .errmsg = true,
787 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300788 { .name = "open", .errmsg = true,
789 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300790 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300791 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
792 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300793 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300794 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
795 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300796 { .name = "pipe2", .errmsg = true,
797 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300798 { .name = "poll", .errmsg = true, .timeout = true, },
799 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300800 { .name = "pread", .errmsg = true, .alias = "pread64",
801 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
802 { .name = "preadv", .errmsg = true, .alias = "pread",
803 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300804 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300805 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
806 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
807 { .name = "pwritev", .errmsg = true,
808 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
809 { .name = "read", .errmsg = true,
810 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
811 { .name = "readlinkat", .errmsg = true,
812 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
813 { .name = "readv", .errmsg = true,
814 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300815 { .name = "recvfrom", .errmsg = true,
816 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
817 { .name = "recvmmsg", .errmsg = true,
818 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
819 { .name = "recvmsg", .errmsg = true,
820 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300821 { .name = "renameat", .errmsg = true,
822 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300823 { .name = "rt_sigaction", .errmsg = true,
824 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300825 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300826 { .name = "rt_sigqueueinfo", .errmsg = true,
827 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
828 { .name = "rt_tgsigqueueinfo", .errmsg = true,
829 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300830 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300831 { .name = "sendmmsg", .errmsg = true,
832 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
833 { .name = "sendmsg", .errmsg = true,
834 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
835 { .name = "sendto", .errmsg = true,
836 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300837 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
838 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300839 { .name = "shutdown", .errmsg = true,
840 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300841 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300842 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
843 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300844 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300845 { .name = "socketpair", .errmsg = true,
846 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
847 [1] = SCA_SK_TYPE, /* type */ },
848 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300849 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300850 { .name = "symlinkat", .errmsg = true,
851 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300852 { .name = "tgkill", .errmsg = true,
853 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
854 { .name = "tkill", .errmsg = true,
855 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300856 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300857 { .name = "unlinkat", .errmsg = true,
858 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
859 { .name = "utimensat", .errmsg = true,
860 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
861 { .name = "write", .errmsg = true,
862 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
863 { .name = "writev", .errmsg = true,
864 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300865};
866
867static int syscall_fmt__cmp(const void *name, const void *fmtp)
868{
869 const struct syscall_fmt *fmt = fmtp;
870 return strcmp(name, fmt->name);
871}
872
873static struct syscall_fmt *syscall_fmt__find(const char *name)
874{
875 const int nmemb = ARRAY_SIZE(syscall_fmts);
876 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
877}
878
879struct syscall {
880 struct event_format *tp_format;
881 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300882 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300883 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300884 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300885 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300886};
887
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200888static size_t fprintf_duration(unsigned long t, FILE *fp)
889{
890 double duration = (double)t / NSEC_PER_MSEC;
891 size_t printed = fprintf(fp, "(");
892
893 if (duration >= 1.0)
894 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
895 else if (duration >= 0.01)
896 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
897 else
898 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300899 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200900}
901
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300902struct thread_trace {
903 u64 entry_time;
904 u64 exit_time;
905 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300906 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300907 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300908 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300909 struct {
910 int max;
911 char **table;
912 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600913
914 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300915};
916
917static struct thread_trace *thread_trace__new(void)
918{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300919 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
920
921 if (ttrace)
922 ttrace->paths.max = -1;
923
David Ahernbf2575c2013-10-08 21:26:53 -0600924 ttrace->syscall_stats = intlist__new(NULL);
925
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300926 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300927}
928
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300929static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300930{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300931 struct thread_trace *ttrace;
932
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300933 if (thread == NULL)
934 goto fail;
935
936 if (thread->priv == NULL)
937 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300938
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300939 if (thread->priv == NULL)
940 goto fail;
941
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300942 ttrace = thread->priv;
943 ++ttrace->nr_events;
944
945 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300946fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300947 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300948 "WARNING: not enough memory, dropping samples!\n");
949 return NULL;
950}
951
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300952struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300953 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300954 int audit_machine;
955 struct {
956 int max;
957 struct syscall *table;
958 } syscalls;
959 struct perf_record_opts opts;
David Ahern8fb598e2013-09-28 13:13:00 -0600960 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300961 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600962 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300963 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300964 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300965 struct strlist *ev_qualifier;
966 bool not_ev_qualifier;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300967 bool live;
David Ahernbdc89662013-08-28 22:29:53 -0600968 struct intlist *tid_list;
969 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300970 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300971 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -0600972 bool summary;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300973 bool show_comm;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300974 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300975 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300976};
977
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300978static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300979{
980 struct thread_trace *ttrace = thread->priv;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300981
982 if (fd > ttrace->paths.max) {
983 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
984
985 if (npath == NULL)
986 return -1;
987
988 if (ttrace->paths.max != -1) {
989 memset(npath + ttrace->paths.max + 1, 0,
990 (fd - ttrace->paths.max) * sizeof(char *));
991 } else {
992 memset(npath, 0, (fd + 1) * sizeof(char *));
993 }
994
995 ttrace->paths.table = npath;
996 ttrace->paths.max = fd;
997 }
998
999 ttrace->paths.table[fd] = strdup(pathname);
1000
1001 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1002}
1003
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001004static int thread__read_fd_path(struct thread *thread, int fd)
1005{
1006 char linkname[PATH_MAX], pathname[PATH_MAX];
1007 struct stat st;
1008 int ret;
1009
1010 if (thread->pid_ == thread->tid) {
1011 scnprintf(linkname, sizeof(linkname),
1012 "/proc/%d/fd/%d", thread->pid_, fd);
1013 } else {
1014 scnprintf(linkname, sizeof(linkname),
1015 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1016 }
1017
1018 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1019 return -1;
1020
1021 ret = readlink(linkname, pathname, sizeof(pathname));
1022
1023 if (ret < 0 || ret > st.st_size)
1024 return -1;
1025
1026 pathname[ret] = '\0';
1027 return trace__set_fd_pathname(thread, fd, pathname);
1028}
1029
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001030static const char *thread__fd_path(struct thread *thread, int fd, bool live)
1031{
1032 struct thread_trace *ttrace = thread->priv;
1033
1034 if (ttrace == NULL)
1035 return NULL;
1036
1037 if (fd < 0)
1038 return NULL;
1039
1040 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL) &&
1041 (!live || thread__read_fd_path(thread, fd)))
1042 return NULL;
1043
1044 return ttrace->paths.table[fd];
1045}
1046
1047static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1048 struct syscall_arg *arg)
1049{
1050 int fd = arg->val;
1051 size_t printed = scnprintf(bf, size, "%d", fd);
1052 const char *path = thread__fd_path(arg->thread, fd, arg->trace->live);
1053
1054 if (path)
1055 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1056
1057 return printed;
1058}
1059
1060static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1061 struct syscall_arg *arg)
1062{
1063 int fd = arg->val;
1064 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1065 struct thread_trace *ttrace = arg->thread->priv;
1066
1067 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
1068 free(ttrace->paths.table[fd]);
1069 ttrace->paths.table[fd] = NULL;
1070 }
1071
1072 return printed;
1073}
1074
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001075static bool trace__filter_duration(struct trace *trace, double t)
1076{
1077 return t < (trace->duration_filter * NSEC_PER_MSEC);
1078}
1079
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001080static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1081{
1082 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1083
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001084 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001085}
1086
Namhyung Kimf15eb532012-10-05 14:02:16 +09001087static bool done = false;
1088
1089static void sig_handler(int sig __maybe_unused)
1090{
1091 done = true;
1092}
1093
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001094static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001095 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001096{
1097 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001098 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001099
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001100 if (trace->multiple_threads) {
1101 if (trace->show_comm)
1102 printed += fprintf(fp, "%.14s/", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001103 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001104 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001105
1106 return printed;
1107}
1108
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001109static int trace__process_event(struct trace *trace, struct machine *machine,
1110 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001111{
1112 int ret = 0;
1113
1114 switch (event->header.type) {
1115 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001116 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001117 "LOST %" PRIu64 " events!\n", event->lost.lost);
1118 ret = machine__process_lost_event(machine, event);
1119 default:
1120 ret = machine__process_event(machine, event);
1121 break;
1122 }
1123
1124 return ret;
1125}
1126
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001127static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001128 union perf_event *event,
1129 struct perf_sample *sample __maybe_unused,
1130 struct machine *machine)
1131{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001132 struct trace *trace = container_of(tool, struct trace, tool);
1133 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001134}
1135
1136static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1137{
1138 int err = symbol__init();
1139
1140 if (err)
1141 return err;
1142
David Ahern8fb598e2013-09-28 13:13:00 -06001143 trace->host = machine__new_host();
1144 if (trace->host == NULL)
1145 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001146
1147 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001148 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001149 trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001150 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001151 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001152 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001153 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001154 }
1155
1156 if (err)
1157 symbol__exit();
1158
1159 return err;
1160}
1161
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001162static int syscall__set_arg_fmts(struct syscall *sc)
1163{
1164 struct format_field *field;
1165 int idx = 0;
1166
1167 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1168 if (sc->arg_scnprintf == NULL)
1169 return -1;
1170
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001171 if (sc->fmt)
1172 sc->arg_parm = sc->fmt->arg_parm;
1173
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001174 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001175 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1176 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1177 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001178 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1179 ++idx;
1180 }
1181
1182 return 0;
1183}
1184
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001185static int trace__read_syscall_info(struct trace *trace, int id)
1186{
1187 char tp_name[128];
1188 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001189 const char *name = audit_syscall_to_name(id, trace->audit_machine);
1190
1191 if (name == NULL)
1192 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001193
1194 if (id > trace->syscalls.max) {
1195 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1196
1197 if (nsyscalls == NULL)
1198 return -1;
1199
1200 if (trace->syscalls.max != -1) {
1201 memset(nsyscalls + trace->syscalls.max + 1, 0,
1202 (id - trace->syscalls.max) * sizeof(*sc));
1203 } else {
1204 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1205 }
1206
1207 trace->syscalls.table = nsyscalls;
1208 trace->syscalls.max = id;
1209 }
1210
1211 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001212 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001213
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001214 if (trace->ev_qualifier) {
1215 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1216
1217 if (!(in ^ trace->not_ev_qualifier)) {
1218 sc->filtered = true;
1219 /*
1220 * No need to do read tracepoint information since this will be
1221 * filtered out.
1222 */
1223 return 0;
1224 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001225 }
1226
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001227 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001228
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001229 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
1230 sc->tp_format = event_format__new("syscalls", tp_name);
1231
1232 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1233 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1234 sc->tp_format = event_format__new("syscalls", tp_name);
1235 }
1236
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001237 if (sc->tp_format == NULL)
1238 return -1;
1239
1240 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001241}
1242
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001243static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001244 unsigned long *args, struct trace *trace,
1245 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001246{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001247 size_t printed = 0;
1248
1249 if (sc->tp_format != NULL) {
1250 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001251 u8 bit = 1;
1252 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001253 .idx = 0,
1254 .mask = 0,
1255 .trace = trace,
1256 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001257 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001258
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001259 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001260 field = field->next, ++arg.idx, bit <<= 1) {
1261 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001262 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001263 /*
1264 * Suppress this argument if its value is zero and
1265 * and we don't have a string associated in an
1266 * strarray for it.
1267 */
1268 if (args[arg.idx] == 0 &&
1269 !(sc->arg_scnprintf &&
1270 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1271 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001272 continue;
1273
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001274 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001275 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001276 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1277 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001278 if (sc->arg_parm)
1279 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001280 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1281 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001282 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001283 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001284 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001285 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001286 }
1287 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001288 int i = 0;
1289
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001290 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001291 printed += scnprintf(bf + printed, size - printed,
1292 "%sarg%d: %ld",
1293 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001294 ++i;
1295 }
1296 }
1297
1298 return printed;
1299}
1300
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001301typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1302 struct perf_sample *sample);
1303
1304static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001305 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001306{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001307
1308 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001309
1310 /*
1311 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1312 * before that, leaving at a higher verbosity level till that is
1313 * explained. Reproduced with plain ftrace with:
1314 *
1315 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1316 * grep "NR -1 " /t/trace_pipe
1317 *
1318 * After generating some load on the machine.
1319 */
1320 if (verbose > 1) {
1321 static u64 n;
1322 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1323 id, perf_evsel__name(evsel), ++n);
1324 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001325 return NULL;
1326 }
1327
1328 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1329 trace__read_syscall_info(trace, id))
1330 goto out_cant_read;
1331
1332 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1333 goto out_cant_read;
1334
1335 return &trace->syscalls.table[id];
1336
1337out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001338 if (verbose) {
1339 fprintf(trace->output, "Problems reading syscall %d", id);
1340 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1341 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1342 fputs(" information\n", trace->output);
1343 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001344 return NULL;
1345}
1346
David Ahernbf2575c2013-10-08 21:26:53 -06001347static void thread__update_stats(struct thread_trace *ttrace,
1348 int id, struct perf_sample *sample)
1349{
1350 struct int_node *inode;
1351 struct stats *stats;
1352 u64 duration = 0;
1353
1354 inode = intlist__findnew(ttrace->syscall_stats, id);
1355 if (inode == NULL)
1356 return;
1357
1358 stats = inode->priv;
1359 if (stats == NULL) {
1360 stats = malloc(sizeof(struct stats));
1361 if (stats == NULL)
1362 return;
1363 init_stats(stats);
1364 inode->priv = stats;
1365 }
1366
1367 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1368 duration = sample->time - ttrace->entry_time;
1369
1370 update_stats(stats, duration);
1371}
1372
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001373static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1374 struct perf_sample *sample)
1375{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001376 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001377 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001378 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001379 struct thread *thread;
David Ahernbf2575c2013-10-08 21:26:53 -06001380 int id = perf_evsel__intval(evsel, sample, "id");
1381 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001382 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001383
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001384 if (sc == NULL)
1385 return -1;
1386
1387 if (sc->filtered)
1388 return 0;
1389
David Ahern8fb598e2013-09-28 13:13:00 -06001390 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001391 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001392 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001393 return -1;
1394
1395 args = perf_evsel__rawptr(evsel, sample, "args");
1396 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001397 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001398 return -1;
1399 }
1400
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001401 ttrace = thread->priv;
1402
1403 if (ttrace->entry_str == NULL) {
1404 ttrace->entry_str = malloc(1024);
1405 if (!ttrace->entry_str)
1406 return -1;
1407 }
1408
1409 ttrace->entry_time = sample->time;
1410 msg = ttrace->entry_str;
1411 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1412
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001413 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1414 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001415
1416 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001417 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001418 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1419 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001420 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001421 } else
1422 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001423
1424 return 0;
1425}
1426
1427static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1428 struct perf_sample *sample)
1429{
1430 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001431 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001432 struct thread *thread;
David Ahernbf2575c2013-10-08 21:26:53 -06001433 int id = perf_evsel__intval(evsel, sample, "id");
1434 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001435 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001436
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001437 if (sc == NULL)
1438 return -1;
1439
1440 if (sc->filtered)
1441 return 0;
1442
David Ahern8fb598e2013-09-28 13:13:00 -06001443 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001444 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001445 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001446 return -1;
1447
David Ahernbf2575c2013-10-08 21:26:53 -06001448 if (trace->summary)
1449 thread__update_stats(ttrace, id, sample);
1450
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001451 ret = perf_evsel__intval(evsel, sample, "ret");
1452
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001453 ttrace = thread->priv;
1454
1455 ttrace->exit_time = sample->time;
1456
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001457 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001458 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001459 if (trace__filter_duration(trace, duration))
1460 goto out;
1461 } else if (trace->duration_filter)
1462 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001463
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001464 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001465
1466 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001467 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001468 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001469 fprintf(trace->output, " ... [");
1470 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1471 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001472 }
1473
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001474 if (sc->fmt == NULL) {
1475signed_print:
1476 fprintf(trace->output, ") = %d", ret);
1477 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001478 char bf[256];
1479 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1480 *e = audit_errno_to_name(-ret);
1481
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001482 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001483 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001484 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001485 else if (sc->fmt->hexret)
1486 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001487 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001488 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001489
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001490 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001491out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001492 ttrace->entry_pending = false;
1493
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001494 return 0;
1495}
1496
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001497static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1498 struct perf_sample *sample)
1499{
1500 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1501 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001502 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001503 sample->pid,
1504 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001505 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001506
1507 if (ttrace == NULL)
1508 goto out_dump;
1509
1510 ttrace->runtime_ms += runtime_ms;
1511 trace->runtime_ms += runtime_ms;
1512 return 0;
1513
1514out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001515 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001516 evsel->name,
1517 perf_evsel__strval(evsel, sample, "comm"),
1518 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1519 runtime,
1520 perf_evsel__intval(evsel, sample, "vruntime"));
1521 return 0;
1522}
1523
David Ahernbdc89662013-08-28 22:29:53 -06001524static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1525{
1526 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1527 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1528 return false;
1529
1530 if (trace->pid_list || trace->tid_list)
1531 return true;
1532
1533 return false;
1534}
1535
David Ahern6810fc92013-08-28 22:29:52 -06001536static int trace__process_sample(struct perf_tool *tool,
1537 union perf_event *event __maybe_unused,
1538 struct perf_sample *sample,
1539 struct perf_evsel *evsel,
1540 struct machine *machine __maybe_unused)
1541{
1542 struct trace *trace = container_of(tool, struct trace, tool);
1543 int err = 0;
1544
1545 tracepoint_handler handler = evsel->handler.func;
1546
David Ahernbdc89662013-08-28 22:29:53 -06001547 if (skip_sample(trace, sample))
1548 return 0;
1549
David Ahern4bb09192013-09-04 12:37:43 -06001550 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001551 trace->base_time = sample->time;
1552
1553 if (handler)
1554 handler(trace, evsel, sample);
1555
1556 return err;
1557}
1558
1559static bool
1560perf_session__has_tp(struct perf_session *session, const char *name)
1561{
1562 struct perf_evsel *evsel;
1563
1564 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1565
1566 return evsel != NULL;
1567}
1568
David Ahernbdc89662013-08-28 22:29:53 -06001569static int parse_target_str(struct trace *trace)
1570{
1571 if (trace->opts.target.pid) {
1572 trace->pid_list = intlist__new(trace->opts.target.pid);
1573 if (trace->pid_list == NULL) {
1574 pr_err("Error parsing process id string\n");
1575 return -EINVAL;
1576 }
1577 }
1578
1579 if (trace->opts.target.tid) {
1580 trace->tid_list = intlist__new(trace->opts.target.tid);
1581 if (trace->tid_list == NULL) {
1582 pr_err("Error parsing thread id string\n");
1583 return -EINVAL;
1584 }
1585 }
1586
1587 return 0;
1588}
1589
David Ahern5e2485b2013-09-28 13:13:01 -06001590static int trace__record(int argc, const char **argv)
1591{
1592 unsigned int rec_argc, i, j;
1593 const char **rec_argv;
1594 const char * const record_args[] = {
1595 "record",
1596 "-R",
1597 "-m", "1024",
1598 "-c", "1",
1599 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
1600 };
1601
1602 rec_argc = ARRAY_SIZE(record_args) + argc;
1603 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1604
1605 if (rec_argv == NULL)
1606 return -ENOMEM;
1607
1608 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1609 rec_argv[i] = record_args[i];
1610
1611 for (j = 0; j < (unsigned int)argc; j++, i++)
1612 rec_argv[i] = argv[j];
1613
1614 return cmd_record(i, rec_argv, NULL);
1615}
1616
David Ahernbf2575c2013-10-08 21:26:53 -06001617static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1618
Namhyung Kimf15eb532012-10-05 14:02:16 +09001619static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001620{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001621 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001622 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001623 int err = -1, i;
1624 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001625 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001626
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001627 trace->live = true;
1628
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001629 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001630 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001631 goto out;
1632 }
1633
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001634 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301635 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit))
1636 goto out_error_tp;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001637
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001638 if (trace->sched &&
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301639 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1640 trace__sched_stat_runtime))
1641 goto out_error_tp;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001642
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001643 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1644 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001645 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001646 goto out_delete_evlist;
1647 }
1648
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001649 err = trace__symbols_init(trace, evlist);
1650 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001651 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001652 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001653 }
1654
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001655 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001656
Namhyung Kimf15eb532012-10-05 14:02:16 +09001657 signal(SIGCHLD, sig_handler);
1658 signal(SIGINT, sig_handler);
1659
1660 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001661 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001662 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001663 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001664 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001665 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001666 }
1667 }
1668
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001669 err = perf_evlist__open(evlist);
1670 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001671 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001672 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001673 }
1674
1675 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1676 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001677 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001678 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001679 }
1680
1681 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001682
1683 if (forks)
1684 perf_evlist__start_workload(evlist);
1685
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001686 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001687again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001688 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001689
1690 for (i = 0; i < evlist->nr_mmaps; i++) {
1691 union perf_event *event;
1692
1693 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1694 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001695 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001696 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001697
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001698 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001699
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001700 err = perf_evlist__parse_sample(evlist, event, &sample);
1701 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001702 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001703 continue;
1704 }
1705
David Ahern4bb09192013-09-04 12:37:43 -06001706 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001707 trace->base_time = sample.time;
1708
1709 if (type != PERF_RECORD_SAMPLE) {
David Ahern8fb598e2013-09-28 13:13:00 -06001710 trace__process_event(trace, trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001711 continue;
1712 }
1713
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001714 evsel = perf_evlist__id2evsel(evlist, sample.id);
1715 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001716 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001717 continue;
1718 }
1719
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001720 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001721 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 -03001722 perf_evsel__name(evsel), sample.tid,
1723 sample.cpu, sample.raw_size);
1724 continue;
1725 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001726
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001727 handler = evsel->handler.func;
1728 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001729
1730 if (done)
1731 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001732 }
1733 }
1734
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001735 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001736 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001737 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001738
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001739 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001740 }
1741
1742 if (done)
1743 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001744
1745 goto again;
1746
Namhyung Kim3beb0862013-03-15 14:48:50 +09001747out_unmap_evlist:
David Ahernbf2575c2013-10-08 21:26:53 -06001748 if (!err && trace->summary)
1749 trace__fprintf_thread_summary(trace, trace->output);
1750
Namhyung Kim3beb0862013-03-15 14:48:50 +09001751 perf_evlist__munmap(evlist);
1752out_close_evlist:
1753 perf_evlist__close(evlist);
1754out_delete_maps:
1755 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001756out_delete_evlist:
1757 perf_evlist__delete(evlist);
1758out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001759 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001760 return err;
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301761out_error_tp:
1762 switch(errno) {
1763 case ENOENT:
1764 fputs("Error:\tUnable to find debugfs\n"
1765 "Hint:\tWas your kernel was compiled with debugfs support?\n"
1766 "Hint:\tIs the debugfs filesystem mounted?\n"
1767 "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'\n",
1768 trace->output);
1769 break;
1770 case EACCES:
1771 fprintf(trace->output,
1772 "Error:\tNo permissions to read %s/tracing/events/raw_syscalls\n"
1773 "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
1774 debugfs_mountpoint, debugfs_mountpoint);
1775 break;
1776 default: {
1777 char bf[256];
1778 fprintf(trace->output, "Can't trace: %s\n",
1779 strerror_r(errno, bf, sizeof(bf)));
1780 }
1781 break;
1782 }
1783 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001784}
1785
David Ahern6810fc92013-08-28 22:29:52 -06001786static int trace__replay(struct trace *trace)
1787{
1788 const struct perf_evsel_str_handler handlers[] = {
1789 { "raw_syscalls:sys_enter", trace__sys_enter, },
1790 { "raw_syscalls:sys_exit", trace__sys_exit, },
1791 };
1792
1793 struct perf_session *session;
1794 int err = -1;
1795
1796 trace->tool.sample = trace__process_sample;
1797 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001798 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001799 trace->tool.comm = perf_event__process_comm;
1800 trace->tool.exit = perf_event__process_exit;
1801 trace->tool.fork = perf_event__process_fork;
1802 trace->tool.attr = perf_event__process_attr;
1803 trace->tool.tracing_data = perf_event__process_tracing_data;
1804 trace->tool.build_id = perf_event__process_build_id;
1805
1806 trace->tool.ordered_samples = true;
1807 trace->tool.ordering_requires_timestamps = true;
1808
1809 /* add tid to output */
1810 trace->multiple_threads = true;
1811
1812 if (symbol__init() < 0)
1813 return -1;
1814
1815 session = perf_session__new(input_name, O_RDONLY, 0, false,
1816 &trace->tool);
1817 if (session == NULL)
1818 return -ENOMEM;
1819
David Ahern8fb598e2013-09-28 13:13:00 -06001820 trace->host = &session->machines.host;
1821
David Ahern6810fc92013-08-28 22:29:52 -06001822 err = perf_session__set_tracepoints_handlers(session, handlers);
1823 if (err)
1824 goto out;
1825
1826 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1827 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1828 goto out;
1829 }
1830
1831 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1832 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1833 goto out;
1834 }
1835
David Ahernbdc89662013-08-28 22:29:53 -06001836 err = parse_target_str(trace);
1837 if (err != 0)
1838 goto out;
1839
David Ahern6810fc92013-08-28 22:29:52 -06001840 setup_pager();
1841
1842 err = perf_session__process_events(session, &trace->tool);
1843 if (err)
1844 pr_err("Failed to process events, error %d", err);
1845
David Ahernbf2575c2013-10-08 21:26:53 -06001846 else if (trace->summary)
1847 trace__fprintf_thread_summary(trace, trace->output);
1848
David Ahern6810fc92013-08-28 22:29:52 -06001849out:
1850 perf_session__delete(session);
1851
1852 return err;
1853}
1854
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001855static size_t trace__fprintf_threads_header(FILE *fp)
1856{
1857 size_t printed;
1858
David Ahernbf2575c2013-10-08 21:26:53 -06001859 printed = fprintf(fp, "\n _____________________________________________________________________________\n");
1860 printed += fprintf(fp, " __) Summary of events (__\n\n");
1861 printed += fprintf(fp, " [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1862 printed += fprintf(fp, " syscall count min max avg stddev\n");
1863 printed += fprintf(fp, " msec msec msec %%\n");
1864 printed += fprintf(fp, " _____________________________________________________________________________\n\n");
1865
1866 return printed;
1867}
1868
1869static size_t thread__dump_stats(struct thread_trace *ttrace,
1870 struct trace *trace, FILE *fp)
1871{
1872 struct stats *stats;
1873 size_t printed = 0;
1874 struct syscall *sc;
1875 struct int_node *inode = intlist__first(ttrace->syscall_stats);
1876
1877 if (inode == NULL)
1878 return 0;
1879
1880 printed += fprintf(fp, "\n");
1881
1882 /* each int_node is a syscall */
1883 while (inode) {
1884 stats = inode->priv;
1885 if (stats) {
1886 double min = (double)(stats->min) / NSEC_PER_MSEC;
1887 double max = (double)(stats->max) / NSEC_PER_MSEC;
1888 double avg = avg_stats(stats);
1889 double pct;
1890 u64 n = (u64) stats->n;
1891
1892 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
1893 avg /= NSEC_PER_MSEC;
1894
1895 sc = &trace->syscalls.table[inode->i];
1896 printed += fprintf(fp, "%24s %14s : ", "", sc->name);
1897 printed += fprintf(fp, "%5" PRIu64 " %8.3f %8.3f",
1898 n, min, max);
1899 printed += fprintf(fp, " %8.3f %6.2f\n", avg, pct);
1900 }
1901
1902 inode = intlist__next(inode);
1903 }
1904
1905 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001906
1907 return printed;
1908}
1909
David Ahern896cbb52013-09-28 13:12:59 -06001910/* struct used to pass data to per-thread function */
1911struct summary_data {
1912 FILE *fp;
1913 struct trace *trace;
1914 size_t printed;
1915};
1916
1917static int trace__fprintf_one_thread(struct thread *thread, void *priv)
1918{
1919 struct summary_data *data = priv;
1920 FILE *fp = data->fp;
1921 size_t printed = data->printed;
1922 struct trace *trace = data->trace;
1923 struct thread_trace *ttrace = thread->priv;
1924 const char *color;
1925 double ratio;
1926
1927 if (ttrace == NULL)
1928 return 0;
1929
1930 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1931
1932 color = PERF_COLOR_NORMAL;
1933 if (ratio > 50.0)
1934 color = PERF_COLOR_RED;
1935 else if (ratio > 25.0)
1936 color = PERF_COLOR_GREEN;
1937 else if (ratio > 5.0)
1938 color = PERF_COLOR_YELLOW;
1939
1940 printed += color_fprintf(fp, color, "%20s", thread->comm);
1941 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1942 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1943 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06001944 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06001945
1946 data->printed += printed;
1947
1948 return 0;
1949}
1950
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001951static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1952{
David Ahern896cbb52013-09-28 13:12:59 -06001953 struct summary_data data = {
1954 .fp = fp,
1955 .trace = trace
1956 };
1957 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001958
David Ahern896cbb52013-09-28 13:12:59 -06001959 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001960
David Ahern896cbb52013-09-28 13:12:59 -06001961 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001962}
1963
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001964static int trace__set_duration(const struct option *opt, const char *str,
1965 int unset __maybe_unused)
1966{
1967 struct trace *trace = opt->value;
1968
1969 trace->duration_filter = atof(str);
1970 return 0;
1971}
1972
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001973static int trace__open_output(struct trace *trace, const char *filename)
1974{
1975 struct stat st;
1976
1977 if (!stat(filename, &st) && st.st_size) {
1978 char oldname[PATH_MAX];
1979
1980 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1981 unlink(oldname);
1982 rename(filename, oldname);
1983 }
1984
1985 trace->output = fopen(filename, "w");
1986
1987 return trace->output == NULL ? -errno : 0;
1988}
1989
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001990int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1991{
1992 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001993 "perf trace [<options>] [<command>]",
1994 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06001995 "perf trace record [<options>] [<command>]",
1996 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001997 NULL
1998 };
1999 struct trace trace = {
2000 .audit_machine = audit_detect_machine(),
2001 .syscalls = {
2002 . max = -1,
2003 },
2004 .opts = {
2005 .target = {
2006 .uid = UINT_MAX,
2007 .uses_mmap = true,
2008 },
2009 .user_freq = UINT_MAX,
2010 .user_interval = ULLONG_MAX,
2011 .no_delay = true,
2012 .mmap_pages = 1024,
2013 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002014 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002015 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002016 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002017 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002018 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002019 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002020 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2021 "show the thread COMM next to its id"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002022 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2023 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002024 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002025 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002026 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2027 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002028 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002029 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002030 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002031 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002032 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002033 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002034 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002035 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002036 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2037 "number of mmap data pages",
2038 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002039 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002040 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002041 OPT_CALLBACK(0, "duration", &trace, "float",
2042 "show only events with duration > N.M ms",
2043 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002044 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002045 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002046 OPT_BOOLEAN('T', "time", &trace.full_time,
2047 "Show full timestamp, not time relative to first start"),
David Ahernbf2575c2013-10-08 21:26:53 -06002048 OPT_BOOLEAN(0, "summary", &trace.summary,
2049 "Show syscall summary with statistics"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002050 OPT_END()
2051 };
2052 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002053 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002054
David Ahern5e2485b2013-09-28 13:13:01 -06002055 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
2056 return trace__record(argc-2, &argv[2]);
2057
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002058 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002059
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002060 if (output_name != NULL) {
2061 err = trace__open_output(&trace, output_name);
2062 if (err < 0) {
2063 perror("failed to create output file");
2064 goto out;
2065 }
2066 }
2067
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002068 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002069 const char *s = ev_qualifier_str;
2070
2071 trace.not_ev_qualifier = *s == '!';
2072 if (trace.not_ev_qualifier)
2073 ++s;
2074 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002075 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002076 fputs("Not enough memory to parse event qualifier",
2077 trace.output);
2078 err = -ENOMEM;
2079 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002080 }
2081 }
2082
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002083 err = perf_target__validate(&trace.opts.target);
2084 if (err) {
2085 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002086 fprintf(trace.output, "%s", bf);
2087 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002088 }
2089
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002090 err = perf_target__parse_uid(&trace.opts.target);
2091 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002092 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002093 fprintf(trace.output, "%s", bf);
2094 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002095 }
2096
Namhyung Kimf15eb532012-10-05 14:02:16 +09002097 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002098 trace.opts.target.system_wide = true;
2099
David Ahern6810fc92013-08-28 22:29:52 -06002100 if (input_name)
2101 err = trace__replay(&trace);
2102 else
2103 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002104
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002105out_close:
2106 if (output_name != NULL)
2107 fclose(trace.output);
2108out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002109 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002110}