blob: 78b0d6a5fdff2a51fdb6f4436406464669bd4fae [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 Meloc5227392013-09-27 18:06:19 -0300954 struct {
955 int machine;
956 int open_id;
957 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300958 struct {
959 int max;
960 struct syscall *table;
961 } syscalls;
962 struct perf_record_opts opts;
David Ahern8fb598e2013-09-28 13:13:00 -0600963 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300964 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600965 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300966 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300967 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300968 struct strlist *ev_qualifier;
969 bool not_ev_qualifier;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300970 bool live;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300971 const char *last_vfs_getname;
David Ahernbdc89662013-08-28 22:29:53 -0600972 struct intlist *tid_list;
973 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300974 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300975 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -0600976 bool summary;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300977 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300978 bool show_tool_stats;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300979 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300980 double runtime_ms;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300981 struct {
982 u64 vfs_getname, proc_getname;
983 } stats;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300984};
985
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300986static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300987{
988 struct thread_trace *ttrace = thread->priv;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300989
990 if (fd > ttrace->paths.max) {
991 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
992
993 if (npath == NULL)
994 return -1;
995
996 if (ttrace->paths.max != -1) {
997 memset(npath + ttrace->paths.max + 1, 0,
998 (fd - ttrace->paths.max) * sizeof(char *));
999 } else {
1000 memset(npath, 0, (fd + 1) * sizeof(char *));
1001 }
1002
1003 ttrace->paths.table = npath;
1004 ttrace->paths.max = fd;
1005 }
1006
1007 ttrace->paths.table[fd] = strdup(pathname);
1008
1009 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1010}
1011
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001012static int thread__read_fd_path(struct thread *thread, int fd)
1013{
1014 char linkname[PATH_MAX], pathname[PATH_MAX];
1015 struct stat st;
1016 int ret;
1017
1018 if (thread->pid_ == thread->tid) {
1019 scnprintf(linkname, sizeof(linkname),
1020 "/proc/%d/fd/%d", thread->pid_, fd);
1021 } else {
1022 scnprintf(linkname, sizeof(linkname),
1023 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1024 }
1025
1026 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1027 return -1;
1028
1029 ret = readlink(linkname, pathname, sizeof(pathname));
1030
1031 if (ret < 0 || ret > st.st_size)
1032 return -1;
1033
1034 pathname[ret] = '\0';
1035 return trace__set_fd_pathname(thread, fd, pathname);
1036}
1037
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001038static const char *thread__fd_path(struct thread *thread, int fd,
1039 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001040{
1041 struct thread_trace *ttrace = thread->priv;
1042
1043 if (ttrace == NULL)
1044 return NULL;
1045
1046 if (fd < 0)
1047 return NULL;
1048
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001049 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL))
1050 if (!trace->live)
1051 return NULL;
1052 ++trace->stats.proc_getname;
1053 if (thread__read_fd_path(thread, fd)) {
1054 return NULL;
1055 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001056
1057 return ttrace->paths.table[fd];
1058}
1059
1060static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1061 struct syscall_arg *arg)
1062{
1063 int fd = arg->val;
1064 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001065 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001066
1067 if (path)
1068 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1069
1070 return printed;
1071}
1072
1073static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1074 struct syscall_arg *arg)
1075{
1076 int fd = arg->val;
1077 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1078 struct thread_trace *ttrace = arg->thread->priv;
1079
1080 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
1081 free(ttrace->paths.table[fd]);
1082 ttrace->paths.table[fd] = NULL;
1083 }
1084
1085 return printed;
1086}
1087
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001088static bool trace__filter_duration(struct trace *trace, double t)
1089{
1090 return t < (trace->duration_filter * NSEC_PER_MSEC);
1091}
1092
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001093static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1094{
1095 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1096
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001097 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001098}
1099
Namhyung Kimf15eb532012-10-05 14:02:16 +09001100static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001101static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001102
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001103static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001104{
1105 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001106 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001107}
1108
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001109static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001110 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001111{
1112 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001113 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001114
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001115 if (trace->multiple_threads) {
1116 if (trace->show_comm)
1117 printed += fprintf(fp, "%.14s/", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001118 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001119 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001120
1121 return printed;
1122}
1123
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001124static int trace__process_event(struct trace *trace, struct machine *machine,
1125 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001126{
1127 int ret = 0;
1128
1129 switch (event->header.type) {
1130 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001131 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001132 "LOST %" PRIu64 " events!\n", event->lost.lost);
1133 ret = machine__process_lost_event(machine, event);
1134 default:
1135 ret = machine__process_event(machine, event);
1136 break;
1137 }
1138
1139 return ret;
1140}
1141
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001142static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001143 union perf_event *event,
1144 struct perf_sample *sample __maybe_unused,
1145 struct machine *machine)
1146{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001147 struct trace *trace = container_of(tool, struct trace, tool);
1148 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001149}
1150
1151static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1152{
1153 int err = symbol__init();
1154
1155 if (err)
1156 return err;
1157
David Ahern8fb598e2013-09-28 13:13:00 -06001158 trace->host = machine__new_host();
1159 if (trace->host == NULL)
1160 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001161
1162 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001163 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001164 trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001165 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001166 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001167 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001168 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001169 }
1170
1171 if (err)
1172 symbol__exit();
1173
1174 return err;
1175}
1176
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001177static int syscall__set_arg_fmts(struct syscall *sc)
1178{
1179 struct format_field *field;
1180 int idx = 0;
1181
1182 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1183 if (sc->arg_scnprintf == NULL)
1184 return -1;
1185
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001186 if (sc->fmt)
1187 sc->arg_parm = sc->fmt->arg_parm;
1188
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001189 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001190 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1191 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1192 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001193 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1194 ++idx;
1195 }
1196
1197 return 0;
1198}
1199
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001200static int trace__read_syscall_info(struct trace *trace, int id)
1201{
1202 char tp_name[128];
1203 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001204 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001205
1206 if (name == NULL)
1207 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001208
1209 if (id > trace->syscalls.max) {
1210 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1211
1212 if (nsyscalls == NULL)
1213 return -1;
1214
1215 if (trace->syscalls.max != -1) {
1216 memset(nsyscalls + trace->syscalls.max + 1, 0,
1217 (id - trace->syscalls.max) * sizeof(*sc));
1218 } else {
1219 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1220 }
1221
1222 trace->syscalls.table = nsyscalls;
1223 trace->syscalls.max = id;
1224 }
1225
1226 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001227 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001228
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001229 if (trace->ev_qualifier) {
1230 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1231
1232 if (!(in ^ trace->not_ev_qualifier)) {
1233 sc->filtered = true;
1234 /*
1235 * No need to do read tracepoint information since this will be
1236 * filtered out.
1237 */
1238 return 0;
1239 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001240 }
1241
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001242 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001243
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001244 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
1245 sc->tp_format = event_format__new("syscalls", tp_name);
1246
1247 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1248 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1249 sc->tp_format = event_format__new("syscalls", tp_name);
1250 }
1251
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001252 if (sc->tp_format == NULL)
1253 return -1;
1254
1255 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001256}
1257
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001258static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001259 unsigned long *args, struct trace *trace,
1260 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001261{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001262 size_t printed = 0;
1263
1264 if (sc->tp_format != NULL) {
1265 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001266 u8 bit = 1;
1267 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001268 .idx = 0,
1269 .mask = 0,
1270 .trace = trace,
1271 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001272 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001273
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001274 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001275 field = field->next, ++arg.idx, bit <<= 1) {
1276 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001277 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001278 /*
1279 * Suppress this argument if its value is zero and
1280 * and we don't have a string associated in an
1281 * strarray for it.
1282 */
1283 if (args[arg.idx] == 0 &&
1284 !(sc->arg_scnprintf &&
1285 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1286 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001287 continue;
1288
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001289 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001290 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001291 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1292 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001293 if (sc->arg_parm)
1294 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001295 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1296 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001297 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001298 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001299 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001300 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001301 }
1302 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001303 int i = 0;
1304
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001305 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001306 printed += scnprintf(bf + printed, size - printed,
1307 "%sarg%d: %ld",
1308 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001309 ++i;
1310 }
1311 }
1312
1313 return printed;
1314}
1315
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001316typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1317 struct perf_sample *sample);
1318
1319static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001320 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001321{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001322
1323 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001324
1325 /*
1326 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1327 * before that, leaving at a higher verbosity level till that is
1328 * explained. Reproduced with plain ftrace with:
1329 *
1330 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1331 * grep "NR -1 " /t/trace_pipe
1332 *
1333 * After generating some load on the machine.
1334 */
1335 if (verbose > 1) {
1336 static u64 n;
1337 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1338 id, perf_evsel__name(evsel), ++n);
1339 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001340 return NULL;
1341 }
1342
1343 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1344 trace__read_syscall_info(trace, id))
1345 goto out_cant_read;
1346
1347 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1348 goto out_cant_read;
1349
1350 return &trace->syscalls.table[id];
1351
1352out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001353 if (verbose) {
1354 fprintf(trace->output, "Problems reading syscall %d", id);
1355 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1356 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1357 fputs(" information\n", trace->output);
1358 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001359 return NULL;
1360}
1361
David Ahernbf2575c2013-10-08 21:26:53 -06001362static void thread__update_stats(struct thread_trace *ttrace,
1363 int id, struct perf_sample *sample)
1364{
1365 struct int_node *inode;
1366 struct stats *stats;
1367 u64 duration = 0;
1368
1369 inode = intlist__findnew(ttrace->syscall_stats, id);
1370 if (inode == NULL)
1371 return;
1372
1373 stats = inode->priv;
1374 if (stats == NULL) {
1375 stats = malloc(sizeof(struct stats));
1376 if (stats == NULL)
1377 return;
1378 init_stats(stats);
1379 inode->priv = stats;
1380 }
1381
1382 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1383 duration = sample->time - ttrace->entry_time;
1384
1385 update_stats(stats, duration);
1386}
1387
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001388static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1389 struct perf_sample *sample)
1390{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001391 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001392 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001393 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001394 struct thread *thread;
David Ahernbf2575c2013-10-08 21:26:53 -06001395 int id = perf_evsel__intval(evsel, sample, "id");
1396 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001397 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001398
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001399 if (sc == NULL)
1400 return -1;
1401
1402 if (sc->filtered)
1403 return 0;
1404
David Ahern8fb598e2013-09-28 13:13:00 -06001405 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001406 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001407 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001408 return -1;
1409
1410 args = perf_evsel__rawptr(evsel, sample, "args");
1411 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001412 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001413 return -1;
1414 }
1415
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001416 ttrace = thread->priv;
1417
1418 if (ttrace->entry_str == NULL) {
1419 ttrace->entry_str = malloc(1024);
1420 if (!ttrace->entry_str)
1421 return -1;
1422 }
1423
1424 ttrace->entry_time = sample->time;
1425 msg = ttrace->entry_str;
1426 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1427
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001428 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1429 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001430
1431 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001432 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001433 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1434 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001435 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001436 } else
1437 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001438
1439 return 0;
1440}
1441
1442static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1443 struct perf_sample *sample)
1444{
1445 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001446 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001447 struct thread *thread;
David Ahernbf2575c2013-10-08 21:26:53 -06001448 int id = perf_evsel__intval(evsel, sample, "id");
1449 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001450 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001451
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001452 if (sc == NULL)
1453 return -1;
1454
1455 if (sc->filtered)
1456 return 0;
1457
David Ahern8fb598e2013-09-28 13:13:00 -06001458 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001459 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001460 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001461 return -1;
1462
David Ahernbf2575c2013-10-08 21:26:53 -06001463 if (trace->summary)
1464 thread__update_stats(ttrace, id, sample);
1465
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001466 ret = perf_evsel__intval(evsel, sample, "ret");
1467
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001468 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1469 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1470 trace->last_vfs_getname = NULL;
1471 ++trace->stats.vfs_getname;
1472 }
1473
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001474 ttrace = thread->priv;
1475
1476 ttrace->exit_time = sample->time;
1477
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001478 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001479 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001480 if (trace__filter_duration(trace, duration))
1481 goto out;
1482 } else if (trace->duration_filter)
1483 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001484
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001485 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001486
1487 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001488 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001489 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001490 fprintf(trace->output, " ... [");
1491 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1492 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001493 }
1494
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001495 if (sc->fmt == NULL) {
1496signed_print:
1497 fprintf(trace->output, ") = %d", ret);
1498 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001499 char bf[256];
1500 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1501 *e = audit_errno_to_name(-ret);
1502
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001503 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001504 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001505 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001506 else if (sc->fmt->hexret)
1507 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001508 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001509 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001510
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001511 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001512out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001513 ttrace->entry_pending = false;
1514
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001515 return 0;
1516}
1517
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001518static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1519 struct perf_sample *sample)
1520{
1521 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1522 return 0;
1523}
1524
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001525static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1526 struct perf_sample *sample)
1527{
1528 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1529 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001530 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001531 sample->pid,
1532 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001533 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001534
1535 if (ttrace == NULL)
1536 goto out_dump;
1537
1538 ttrace->runtime_ms += runtime_ms;
1539 trace->runtime_ms += runtime_ms;
1540 return 0;
1541
1542out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001543 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001544 evsel->name,
1545 perf_evsel__strval(evsel, sample, "comm"),
1546 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1547 runtime,
1548 perf_evsel__intval(evsel, sample, "vruntime"));
1549 return 0;
1550}
1551
David Ahernbdc89662013-08-28 22:29:53 -06001552static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1553{
1554 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1555 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1556 return false;
1557
1558 if (trace->pid_list || trace->tid_list)
1559 return true;
1560
1561 return false;
1562}
1563
David Ahern6810fc92013-08-28 22:29:52 -06001564static int trace__process_sample(struct perf_tool *tool,
1565 union perf_event *event __maybe_unused,
1566 struct perf_sample *sample,
1567 struct perf_evsel *evsel,
1568 struct machine *machine __maybe_unused)
1569{
1570 struct trace *trace = container_of(tool, struct trace, tool);
1571 int err = 0;
1572
1573 tracepoint_handler handler = evsel->handler.func;
1574
David Ahernbdc89662013-08-28 22:29:53 -06001575 if (skip_sample(trace, sample))
1576 return 0;
1577
David Ahern4bb09192013-09-04 12:37:43 -06001578 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001579 trace->base_time = sample->time;
1580
1581 if (handler)
1582 handler(trace, evsel, sample);
1583
1584 return err;
1585}
1586
1587static bool
1588perf_session__has_tp(struct perf_session *session, const char *name)
1589{
1590 struct perf_evsel *evsel;
1591
1592 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1593
1594 return evsel != NULL;
1595}
1596
David Ahernbdc89662013-08-28 22:29:53 -06001597static int parse_target_str(struct trace *trace)
1598{
1599 if (trace->opts.target.pid) {
1600 trace->pid_list = intlist__new(trace->opts.target.pid);
1601 if (trace->pid_list == NULL) {
1602 pr_err("Error parsing process id string\n");
1603 return -EINVAL;
1604 }
1605 }
1606
1607 if (trace->opts.target.tid) {
1608 trace->tid_list = intlist__new(trace->opts.target.tid);
1609 if (trace->tid_list == NULL) {
1610 pr_err("Error parsing thread id string\n");
1611 return -EINVAL;
1612 }
1613 }
1614
1615 return 0;
1616}
1617
David Ahern5e2485b2013-09-28 13:13:01 -06001618static int trace__record(int argc, const char **argv)
1619{
1620 unsigned int rec_argc, i, j;
1621 const char **rec_argv;
1622 const char * const record_args[] = {
1623 "record",
1624 "-R",
1625 "-m", "1024",
1626 "-c", "1",
1627 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
1628 };
1629
1630 rec_argc = ARRAY_SIZE(record_args) + argc;
1631 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1632
1633 if (rec_argv == NULL)
1634 return -ENOMEM;
1635
1636 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1637 rec_argv[i] = record_args[i];
1638
1639 for (j = 0; j < (unsigned int)argc; j++, i++)
1640 rec_argv[i] = argv[j];
1641
1642 return cmd_record(i, rec_argv, NULL);
1643}
1644
David Ahernbf2575c2013-10-08 21:26:53 -06001645static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1646
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001647static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1648{
1649 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname",
1650 evlist->nr_entries);
1651 if (evsel == NULL)
1652 return;
1653
1654 if (perf_evsel__field(evsel, "pathname") == NULL) {
1655 perf_evsel__delete(evsel);
1656 return;
1657 }
1658
1659 evsel->handler.func = trace__vfs_getname;
1660 perf_evlist__add(evlist, evsel);
1661}
1662
Namhyung Kimf15eb532012-10-05 14:02:16 +09001663static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001664{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001665 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001666 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001667 int err = -1, i;
1668 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001669 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001670
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001671 trace->live = true;
1672
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001673 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001674 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001675 goto out;
1676 }
1677
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001678 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301679 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit))
1680 goto out_error_tp;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001681
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001682 perf_evlist__add_vfs_getname(evlist);
1683
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001684 if (trace->sched &&
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301685 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1686 trace__sched_stat_runtime))
1687 goto out_error_tp;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001688
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001689 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1690 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001691 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001692 goto out_delete_evlist;
1693 }
1694
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001695 err = trace__symbols_init(trace, evlist);
1696 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001697 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001698 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001699 }
1700
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001701 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001702
Namhyung Kimf15eb532012-10-05 14:02:16 +09001703 signal(SIGCHLD, sig_handler);
1704 signal(SIGINT, sig_handler);
1705
1706 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001707 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001708 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001709 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001710 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001711 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001712 }
1713 }
1714
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001715 err = perf_evlist__open(evlist);
1716 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001717 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001718 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001719 }
1720
1721 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1722 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001723 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001724 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001725 }
1726
1727 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001728
1729 if (forks)
1730 perf_evlist__start_workload(evlist);
1731
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001732 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001733again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001734 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001735
1736 for (i = 0; i < evlist->nr_mmaps; i++) {
1737 union perf_event *event;
1738
1739 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1740 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001741 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001742 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001743
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001744 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001745
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001746 err = perf_evlist__parse_sample(evlist, event, &sample);
1747 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001748 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001749 continue;
1750 }
1751
David Ahern4bb09192013-09-04 12:37:43 -06001752 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001753 trace->base_time = sample.time;
1754
1755 if (type != PERF_RECORD_SAMPLE) {
David Ahern8fb598e2013-09-28 13:13:00 -06001756 trace__process_event(trace, trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001757 continue;
1758 }
1759
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001760 evsel = perf_evlist__id2evsel(evlist, sample.id);
1761 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001762 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001763 continue;
1764 }
1765
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001766 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001767 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 -03001768 perf_evsel__name(evsel), sample.tid,
1769 sample.cpu, sample.raw_size);
1770 continue;
1771 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001772
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001773 handler = evsel->handler.func;
1774 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001775
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001776 if (interrupted)
1777 goto out_disable;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001778 }
1779 }
1780
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001781 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001782 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001783
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001784 if (poll(evlist->pollfd, evlist->nr_fds, timeout) > 0)
1785 goto again;
1786 } else {
1787 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001788 }
1789
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001790out_disable:
1791 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001792
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001793 if (!err) {
1794 if (trace->summary)
1795 trace__fprintf_thread_summary(trace, trace->output);
1796
1797 if (trace->show_tool_stats) {
1798 fprintf(trace->output, "Stats:\n "
1799 " vfs_getname : %" PRIu64 "\n"
1800 " proc_getname: %" PRIu64 "\n",
1801 trace->stats.vfs_getname,
1802 trace->stats.proc_getname);
1803 }
1804 }
David Ahernbf2575c2013-10-08 21:26:53 -06001805
Namhyung Kim3beb0862013-03-15 14:48:50 +09001806 perf_evlist__munmap(evlist);
1807out_close_evlist:
1808 perf_evlist__close(evlist);
1809out_delete_maps:
1810 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001811out_delete_evlist:
1812 perf_evlist__delete(evlist);
1813out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001814 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001815 return err;
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301816out_error_tp:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03001817{
1818 char errbuf[BUFSIZ];
1819 perf_evlist__strerror_tp(evlist, errno, errbuf, sizeof(errbuf));
1820 fprintf(trace->output, "%s\n", errbuf);
1821}
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301822 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001823}
1824
David Ahern6810fc92013-08-28 22:29:52 -06001825static int trace__replay(struct trace *trace)
1826{
1827 const struct perf_evsel_str_handler handlers[] = {
1828 { "raw_syscalls:sys_enter", trace__sys_enter, },
1829 { "raw_syscalls:sys_exit", trace__sys_exit, },
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001830 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06001831 };
1832
1833 struct perf_session *session;
1834 int err = -1;
1835
1836 trace->tool.sample = trace__process_sample;
1837 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001838 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001839 trace->tool.comm = perf_event__process_comm;
1840 trace->tool.exit = perf_event__process_exit;
1841 trace->tool.fork = perf_event__process_fork;
1842 trace->tool.attr = perf_event__process_attr;
1843 trace->tool.tracing_data = perf_event__process_tracing_data;
1844 trace->tool.build_id = perf_event__process_build_id;
1845
1846 trace->tool.ordered_samples = true;
1847 trace->tool.ordering_requires_timestamps = true;
1848
1849 /* add tid to output */
1850 trace->multiple_threads = true;
1851
1852 if (symbol__init() < 0)
1853 return -1;
1854
1855 session = perf_session__new(input_name, O_RDONLY, 0, false,
1856 &trace->tool);
1857 if (session == NULL)
1858 return -ENOMEM;
1859
David Ahern8fb598e2013-09-28 13:13:00 -06001860 trace->host = &session->machines.host;
1861
David Ahern6810fc92013-08-28 22:29:52 -06001862 err = perf_session__set_tracepoints_handlers(session, handlers);
1863 if (err)
1864 goto out;
1865
1866 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1867 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1868 goto out;
1869 }
1870
1871 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1872 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1873 goto out;
1874 }
1875
David Ahernbdc89662013-08-28 22:29:53 -06001876 err = parse_target_str(trace);
1877 if (err != 0)
1878 goto out;
1879
David Ahern6810fc92013-08-28 22:29:52 -06001880 setup_pager();
1881
1882 err = perf_session__process_events(session, &trace->tool);
1883 if (err)
1884 pr_err("Failed to process events, error %d", err);
1885
David Ahernbf2575c2013-10-08 21:26:53 -06001886 else if (trace->summary)
1887 trace__fprintf_thread_summary(trace, trace->output);
1888
David Ahern6810fc92013-08-28 22:29:52 -06001889out:
1890 perf_session__delete(session);
1891
1892 return err;
1893}
1894
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001895static size_t trace__fprintf_threads_header(FILE *fp)
1896{
1897 size_t printed;
1898
David Ahernbf2575c2013-10-08 21:26:53 -06001899 printed = fprintf(fp, "\n _____________________________________________________________________________\n");
1900 printed += fprintf(fp, " __) Summary of events (__\n\n");
1901 printed += fprintf(fp, " [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1902 printed += fprintf(fp, " syscall count min max avg stddev\n");
1903 printed += fprintf(fp, " msec msec msec %%\n");
1904 printed += fprintf(fp, " _____________________________________________________________________________\n\n");
1905
1906 return printed;
1907}
1908
1909static size_t thread__dump_stats(struct thread_trace *ttrace,
1910 struct trace *trace, FILE *fp)
1911{
1912 struct stats *stats;
1913 size_t printed = 0;
1914 struct syscall *sc;
1915 struct int_node *inode = intlist__first(ttrace->syscall_stats);
1916
1917 if (inode == NULL)
1918 return 0;
1919
1920 printed += fprintf(fp, "\n");
1921
1922 /* each int_node is a syscall */
1923 while (inode) {
1924 stats = inode->priv;
1925 if (stats) {
1926 double min = (double)(stats->min) / NSEC_PER_MSEC;
1927 double max = (double)(stats->max) / NSEC_PER_MSEC;
1928 double avg = avg_stats(stats);
1929 double pct;
1930 u64 n = (u64) stats->n;
1931
1932 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
1933 avg /= NSEC_PER_MSEC;
1934
1935 sc = &trace->syscalls.table[inode->i];
1936 printed += fprintf(fp, "%24s %14s : ", "", sc->name);
1937 printed += fprintf(fp, "%5" PRIu64 " %8.3f %8.3f",
1938 n, min, max);
1939 printed += fprintf(fp, " %8.3f %6.2f\n", avg, pct);
1940 }
1941
1942 inode = intlist__next(inode);
1943 }
1944
1945 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001946
1947 return printed;
1948}
1949
David Ahern896cbb52013-09-28 13:12:59 -06001950/* struct used to pass data to per-thread function */
1951struct summary_data {
1952 FILE *fp;
1953 struct trace *trace;
1954 size_t printed;
1955};
1956
1957static int trace__fprintf_one_thread(struct thread *thread, void *priv)
1958{
1959 struct summary_data *data = priv;
1960 FILE *fp = data->fp;
1961 size_t printed = data->printed;
1962 struct trace *trace = data->trace;
1963 struct thread_trace *ttrace = thread->priv;
1964 const char *color;
1965 double ratio;
1966
1967 if (ttrace == NULL)
1968 return 0;
1969
1970 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1971
1972 color = PERF_COLOR_NORMAL;
1973 if (ratio > 50.0)
1974 color = PERF_COLOR_RED;
1975 else if (ratio > 25.0)
1976 color = PERF_COLOR_GREEN;
1977 else if (ratio > 5.0)
1978 color = PERF_COLOR_YELLOW;
1979
1980 printed += color_fprintf(fp, color, "%20s", thread->comm);
1981 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1982 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1983 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06001984 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06001985
1986 data->printed += printed;
1987
1988 return 0;
1989}
1990
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001991static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1992{
David Ahern896cbb52013-09-28 13:12:59 -06001993 struct summary_data data = {
1994 .fp = fp,
1995 .trace = trace
1996 };
1997 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001998
David Ahern896cbb52013-09-28 13:12:59 -06001999 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002000
David Ahern896cbb52013-09-28 13:12:59 -06002001 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002002}
2003
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002004static int trace__set_duration(const struct option *opt, const char *str,
2005 int unset __maybe_unused)
2006{
2007 struct trace *trace = opt->value;
2008
2009 trace->duration_filter = atof(str);
2010 return 0;
2011}
2012
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002013static int trace__open_output(struct trace *trace, const char *filename)
2014{
2015 struct stat st;
2016
2017 if (!stat(filename, &st) && st.st_size) {
2018 char oldname[PATH_MAX];
2019
2020 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2021 unlink(oldname);
2022 rename(filename, oldname);
2023 }
2024
2025 trace->output = fopen(filename, "w");
2026
2027 return trace->output == NULL ? -errno : 0;
2028}
2029
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002030int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2031{
2032 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002033 "perf trace [<options>] [<command>]",
2034 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002035 "perf trace record [<options>] [<command>]",
2036 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002037 NULL
2038 };
2039 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002040 .audit = {
2041 .machine = audit_detect_machine(),
2042 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2043 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002044 .syscalls = {
2045 . max = -1,
2046 },
2047 .opts = {
2048 .target = {
2049 .uid = UINT_MAX,
2050 .uses_mmap = true,
2051 },
2052 .user_freq = UINT_MAX,
2053 .user_interval = ULLONG_MAX,
2054 .no_delay = true,
2055 .mmap_pages = 1024,
2056 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002057 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002058 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002059 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002060 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002061 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002062 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002063 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2064 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002065 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002066 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2067 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002068 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002069 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002070 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2071 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002072 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002073 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002074 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002075 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002076 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002077 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002078 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002079 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002080 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2081 "number of mmap data pages",
2082 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002083 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002084 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002085 OPT_CALLBACK(0, "duration", &trace, "float",
2086 "show only events with duration > N.M ms",
2087 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002088 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002089 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002090 OPT_BOOLEAN('T', "time", &trace.full_time,
2091 "Show full timestamp, not time relative to first start"),
David Ahernbf2575c2013-10-08 21:26:53 -06002092 OPT_BOOLEAN(0, "summary", &trace.summary,
2093 "Show syscall summary with statistics"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002094 OPT_END()
2095 };
2096 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002097 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002098
David Ahern5e2485b2013-09-28 13:13:01 -06002099 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
2100 return trace__record(argc-2, &argv[2]);
2101
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002102 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002103
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002104 if (output_name != NULL) {
2105 err = trace__open_output(&trace, output_name);
2106 if (err < 0) {
2107 perror("failed to create output file");
2108 goto out;
2109 }
2110 }
2111
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002112 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002113 const char *s = ev_qualifier_str;
2114
2115 trace.not_ev_qualifier = *s == '!';
2116 if (trace.not_ev_qualifier)
2117 ++s;
2118 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002119 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002120 fputs("Not enough memory to parse event qualifier",
2121 trace.output);
2122 err = -ENOMEM;
2123 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002124 }
2125 }
2126
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002127 err = perf_target__validate(&trace.opts.target);
2128 if (err) {
2129 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002130 fprintf(trace.output, "%s", bf);
2131 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002132 }
2133
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002134 err = perf_target__parse_uid(&trace.opts.target);
2135 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002136 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002137 fprintf(trace.output, "%s", bf);
2138 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002139 }
2140
Namhyung Kimf15eb532012-10-05 14:02:16 +09002141 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002142 trace.opts.target.system_wide = true;
2143
David Ahern6810fc92013-08-28 22:29:52 -06002144 if (input_name)
2145 err = trace__replay(&trace);
2146 else
2147 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002148
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002149out_close:
2150 if (output_name != NULL)
2151 fclose(trace.output);
2152out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002153 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002154}