blob: 7424298b87e342290612e3e16dbde1e4a16df0c6 [file] [log] [blame]
Robert Richter4e319022013-06-11 17:29:18 +02001#include <traceevent/event-parse.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03003#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03004#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03005#include "util/evlist.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03006#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -06007#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03008#include "util/thread.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03009#include "util/parse-options.h"
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030010#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060011#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030012#include "util/thread_map.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030013
14#include <libaudit.h>
15#include <stdlib.h>
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -030016#include <sys/eventfd.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030017#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030018#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030019
Ingo Molnar456857b2013-09-12 15:29:00 +020020/* For older distros: */
21#ifndef MAP_STACK
22# define MAP_STACK 0x20000
23#endif
24
25#ifndef MADV_HWPOISON
26# define MADV_HWPOISON 100
27#endif
28
29#ifndef MADV_MERGEABLE
30# define MADV_MERGEABLE 12
31#endif
32
33#ifndef MADV_UNMERGEABLE
34# define MADV_UNMERGEABLE 13
35#endif
36
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030037struct syscall_arg {
38 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -030039 struct thread *thread;
40 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030041 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030042 u8 idx;
43 u8 mask;
44};
45
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030046struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -030047 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030048 int nr_entries;
49 const char **entries;
50};
51
52#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
53 .nr_entries = ARRAY_SIZE(array), \
54 .entries = array, \
55}
56
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -030057#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
58 .offset = off, \
59 .nr_entries = ARRAY_SIZE(array), \
60 .entries = array, \
61}
62
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030063static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
64 struct syscall_arg *arg)
65{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030066 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -030067 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030068
69 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -030070 return scnprintf(bf, size, "%d", arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030071
72 return scnprintf(bf, size, "%s", sa->entries[idx]);
73}
74
75#define SCA_STRARRAY syscall_arg__scnprintf_strarray
76
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -030077static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
78 struct syscall_arg *arg);
79
80#define SCA_FD syscall_arg__scnprintf_fd
81
82static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
83 struct syscall_arg *arg)
84{
85 int fd = arg->val;
86
87 if (fd == AT_FDCWD)
88 return scnprintf(bf, size, "CWD");
89
90 return syscall_arg__scnprintf_fd(bf, size, arg);
91}
92
93#define SCA_FDAT syscall_arg__scnprintf_fd_at
94
95static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
96 struct syscall_arg *arg);
97
98#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
99
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300100static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300101 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300102{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300103 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300104}
105
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300106#define SCA_HEX syscall_arg__scnprintf_hex
107
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300108static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300109 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300110{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300111 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300112
113 if (prot == PROT_NONE)
114 return scnprintf(bf, size, "NONE");
115#define P_MMAP_PROT(n) \
116 if (prot & PROT_##n) { \
117 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
118 prot &= ~PROT_##n; \
119 }
120
121 P_MMAP_PROT(EXEC);
122 P_MMAP_PROT(READ);
123 P_MMAP_PROT(WRITE);
124#ifdef PROT_SEM
125 P_MMAP_PROT(SEM);
126#endif
127 P_MMAP_PROT(GROWSDOWN);
128 P_MMAP_PROT(GROWSUP);
129#undef P_MMAP_PROT
130
131 if (prot)
132 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
133
134 return printed;
135}
136
137#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
138
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300139static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300140 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300141{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300142 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300143
144#define P_MMAP_FLAG(n) \
145 if (flags & MAP_##n) { \
146 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
147 flags &= ~MAP_##n; \
148 }
149
150 P_MMAP_FLAG(SHARED);
151 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400152#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300153 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400154#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300155 P_MMAP_FLAG(ANONYMOUS);
156 P_MMAP_FLAG(DENYWRITE);
157 P_MMAP_FLAG(EXECUTABLE);
158 P_MMAP_FLAG(FILE);
159 P_MMAP_FLAG(FIXED);
160 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600161#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300162 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600163#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300164 P_MMAP_FLAG(LOCKED);
165 P_MMAP_FLAG(NONBLOCK);
166 P_MMAP_FLAG(NORESERVE);
167 P_MMAP_FLAG(POPULATE);
168 P_MMAP_FLAG(STACK);
169#ifdef MAP_UNINITIALIZED
170 P_MMAP_FLAG(UNINITIALIZED);
171#endif
172#undef P_MMAP_FLAG
173
174 if (flags)
175 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
176
177 return printed;
178}
179
180#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
181
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300182static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300183 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300184{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300185 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300186
187 switch (behavior) {
188#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
189 P_MADV_BHV(NORMAL);
190 P_MADV_BHV(RANDOM);
191 P_MADV_BHV(SEQUENTIAL);
192 P_MADV_BHV(WILLNEED);
193 P_MADV_BHV(DONTNEED);
194 P_MADV_BHV(REMOVE);
195 P_MADV_BHV(DONTFORK);
196 P_MADV_BHV(DOFORK);
197 P_MADV_BHV(HWPOISON);
198#ifdef MADV_SOFT_OFFLINE
199 P_MADV_BHV(SOFT_OFFLINE);
200#endif
201 P_MADV_BHV(MERGEABLE);
202 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600203#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300204 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600205#endif
206#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300207 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600208#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300209#ifdef MADV_DONTDUMP
210 P_MADV_BHV(DONTDUMP);
211#endif
212#ifdef MADV_DODUMP
213 P_MADV_BHV(DODUMP);
214#endif
215#undef P_MADV_PHV
216 default: break;
217 }
218
219 return scnprintf(bf, size, "%#x", behavior);
220}
221
222#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
223
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300224static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
225 struct syscall_arg *arg)
226{
227 int printed = 0, op = arg->val;
228
229 if (op == 0)
230 return scnprintf(bf, size, "NONE");
231#define P_CMD(cmd) \
232 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
233 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
234 op &= ~LOCK_##cmd; \
235 }
236
237 P_CMD(SH);
238 P_CMD(EX);
239 P_CMD(NB);
240 P_CMD(UN);
241 P_CMD(MAND);
242 P_CMD(RW);
243 P_CMD(READ);
244 P_CMD(WRITE);
245#undef P_OP
246
247 if (op)
248 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
249
250 return printed;
251}
252
253#define SCA_FLOCK syscall_arg__scnprintf_flock
254
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300255static 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 -0300256{
257 enum syscall_futex_args {
258 SCF_UADDR = (1 << 0),
259 SCF_OP = (1 << 1),
260 SCF_VAL = (1 << 2),
261 SCF_TIMEOUT = (1 << 3),
262 SCF_UADDR2 = (1 << 4),
263 SCF_VAL3 = (1 << 5),
264 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300265 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300266 int cmd = op & FUTEX_CMD_MASK;
267 size_t printed = 0;
268
269 switch (cmd) {
270#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300271 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
272 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
273 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
274 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
275 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
276 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300277 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300278 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
279 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
280 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
281 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
282 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300283 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
284 default: printed = scnprintf(bf, size, "%#x", cmd); break;
285 }
286
287 if (op & FUTEX_PRIVATE_FLAG)
288 printed += scnprintf(bf + printed, size - printed, "|PRIV");
289
290 if (op & FUTEX_CLOCK_REALTIME)
291 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
292
293 return printed;
294}
295
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300296#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
297
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300298static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
299static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300300
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300301static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
302static DEFINE_STRARRAY(itimers);
303
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300304static const char *whences[] = { "SET", "CUR", "END",
305#ifdef SEEK_DATA
306"DATA",
307#endif
308#ifdef SEEK_HOLE
309"HOLE",
310#endif
311};
312static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300313
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300314static const char *fcntl_cmds[] = {
315 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
316 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
317 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
318 "F_GETOWNER_UIDS",
319};
320static DEFINE_STRARRAY(fcntl_cmds);
321
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300322static const char *rlimit_resources[] = {
323 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
324 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
325 "RTTIME",
326};
327static DEFINE_STRARRAY(rlimit_resources);
328
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300329static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
330static DEFINE_STRARRAY(sighow);
331
David Ahern4f8c1b72013-09-22 19:45:00 -0600332static const char *clockid[] = {
333 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
334 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
335};
336static DEFINE_STRARRAY(clockid);
337
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300338static const char *socket_families[] = {
339 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
340 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
341 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
342 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
343 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
344 "ALG", "NFC", "VSOCK",
345};
346static DEFINE_STRARRAY(socket_families);
347
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300348#ifndef SOCK_TYPE_MASK
349#define SOCK_TYPE_MASK 0xf
350#endif
351
352static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
353 struct syscall_arg *arg)
354{
355 size_t printed;
356 int type = arg->val,
357 flags = type & ~SOCK_TYPE_MASK;
358
359 type &= SOCK_TYPE_MASK;
360 /*
361 * Can't use a strarray, MIPS may override for ABI reasons.
362 */
363 switch (type) {
364#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
365 P_SK_TYPE(STREAM);
366 P_SK_TYPE(DGRAM);
367 P_SK_TYPE(RAW);
368 P_SK_TYPE(RDM);
369 P_SK_TYPE(SEQPACKET);
370 P_SK_TYPE(DCCP);
371 P_SK_TYPE(PACKET);
372#undef P_SK_TYPE
373 default:
374 printed = scnprintf(bf, size, "%#x", type);
375 }
376
377#define P_SK_FLAG(n) \
378 if (flags & SOCK_##n) { \
379 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
380 flags &= ~SOCK_##n; \
381 }
382
383 P_SK_FLAG(CLOEXEC);
384 P_SK_FLAG(NONBLOCK);
385#undef P_SK_FLAG
386
387 if (flags)
388 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
389
390 return printed;
391}
392
393#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
394
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300395#ifndef MSG_PROBE
396#define MSG_PROBE 0x10
397#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600398#ifndef MSG_WAITFORONE
399#define MSG_WAITFORONE 0x10000
400#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300401#ifndef MSG_SENDPAGE_NOTLAST
402#define MSG_SENDPAGE_NOTLAST 0x20000
403#endif
404#ifndef MSG_FASTOPEN
405#define MSG_FASTOPEN 0x20000000
406#endif
407
408static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
409 struct syscall_arg *arg)
410{
411 int printed = 0, flags = arg->val;
412
413 if (flags == 0)
414 return scnprintf(bf, size, "NONE");
415#define P_MSG_FLAG(n) \
416 if (flags & MSG_##n) { \
417 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
418 flags &= ~MSG_##n; \
419 }
420
421 P_MSG_FLAG(OOB);
422 P_MSG_FLAG(PEEK);
423 P_MSG_FLAG(DONTROUTE);
424 P_MSG_FLAG(TRYHARD);
425 P_MSG_FLAG(CTRUNC);
426 P_MSG_FLAG(PROBE);
427 P_MSG_FLAG(TRUNC);
428 P_MSG_FLAG(DONTWAIT);
429 P_MSG_FLAG(EOR);
430 P_MSG_FLAG(WAITALL);
431 P_MSG_FLAG(FIN);
432 P_MSG_FLAG(SYN);
433 P_MSG_FLAG(CONFIRM);
434 P_MSG_FLAG(RST);
435 P_MSG_FLAG(ERRQUEUE);
436 P_MSG_FLAG(NOSIGNAL);
437 P_MSG_FLAG(MORE);
438 P_MSG_FLAG(WAITFORONE);
439 P_MSG_FLAG(SENDPAGE_NOTLAST);
440 P_MSG_FLAG(FASTOPEN);
441 P_MSG_FLAG(CMSG_CLOEXEC);
442#undef P_MSG_FLAG
443
444 if (flags)
445 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
446
447 return printed;
448}
449
450#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
451
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300452static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
453 struct syscall_arg *arg)
454{
455 size_t printed = 0;
456 int mode = arg->val;
457
458 if (mode == F_OK) /* 0 */
459 return scnprintf(bf, size, "F");
460#define P_MODE(n) \
461 if (mode & n##_OK) { \
462 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
463 mode &= ~n##_OK; \
464 }
465
466 P_MODE(R);
467 P_MODE(W);
468 P_MODE(X);
469#undef P_MODE
470
471 if (mode)
472 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
473
474 return printed;
475}
476
477#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
478
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300479static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300480 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300481{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300482 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300483
484 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300485 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300486
487 if (flags == 0)
488 return scnprintf(bf, size, "RDONLY");
489#define P_FLAG(n) \
490 if (flags & O_##n) { \
491 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
492 flags &= ~O_##n; \
493 }
494
495 P_FLAG(APPEND);
496 P_FLAG(ASYNC);
497 P_FLAG(CLOEXEC);
498 P_FLAG(CREAT);
499 P_FLAG(DIRECT);
500 P_FLAG(DIRECTORY);
501 P_FLAG(EXCL);
502 P_FLAG(LARGEFILE);
503 P_FLAG(NOATIME);
504 P_FLAG(NOCTTY);
505#ifdef O_NONBLOCK
506 P_FLAG(NONBLOCK);
507#elif O_NDELAY
508 P_FLAG(NDELAY);
509#endif
510#ifdef O_PATH
511 P_FLAG(PATH);
512#endif
513 P_FLAG(RDWR);
514#ifdef O_DSYNC
515 if ((flags & O_SYNC) == O_SYNC)
516 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
517 else {
518 P_FLAG(DSYNC);
519 }
520#else
521 P_FLAG(SYNC);
522#endif
523 P_FLAG(TRUNC);
524 P_FLAG(WRONLY);
525#undef P_FLAG
526
527 if (flags)
528 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
529
530 return printed;
531}
532
533#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
534
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300535static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
536 struct syscall_arg *arg)
537{
538 int printed = 0, flags = arg->val;
539
540 if (flags == 0)
541 return scnprintf(bf, size, "NONE");
542#define P_FLAG(n) \
543 if (flags & EFD_##n) { \
544 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
545 flags &= ~EFD_##n; \
546 }
547
548 P_FLAG(SEMAPHORE);
549 P_FLAG(CLOEXEC);
550 P_FLAG(NONBLOCK);
551#undef P_FLAG
552
553 if (flags)
554 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
555
556 return printed;
557}
558
559#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
560
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300561static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
562 struct syscall_arg *arg)
563{
564 int printed = 0, flags = arg->val;
565
566#define P_FLAG(n) \
567 if (flags & O_##n) { \
568 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
569 flags &= ~O_##n; \
570 }
571
572 P_FLAG(CLOEXEC);
573 P_FLAG(NONBLOCK);
574#undef P_FLAG
575
576 if (flags)
577 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
578
579 return printed;
580}
581
582#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
583
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300584static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
585{
586 int sig = arg->val;
587
588 switch (sig) {
589#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
590 P_SIGNUM(HUP);
591 P_SIGNUM(INT);
592 P_SIGNUM(QUIT);
593 P_SIGNUM(ILL);
594 P_SIGNUM(TRAP);
595 P_SIGNUM(ABRT);
596 P_SIGNUM(BUS);
597 P_SIGNUM(FPE);
598 P_SIGNUM(KILL);
599 P_SIGNUM(USR1);
600 P_SIGNUM(SEGV);
601 P_SIGNUM(USR2);
602 P_SIGNUM(PIPE);
603 P_SIGNUM(ALRM);
604 P_SIGNUM(TERM);
605 P_SIGNUM(STKFLT);
606 P_SIGNUM(CHLD);
607 P_SIGNUM(CONT);
608 P_SIGNUM(STOP);
609 P_SIGNUM(TSTP);
610 P_SIGNUM(TTIN);
611 P_SIGNUM(TTOU);
612 P_SIGNUM(URG);
613 P_SIGNUM(XCPU);
614 P_SIGNUM(XFSZ);
615 P_SIGNUM(VTALRM);
616 P_SIGNUM(PROF);
617 P_SIGNUM(WINCH);
618 P_SIGNUM(IO);
619 P_SIGNUM(PWR);
620 P_SIGNUM(SYS);
621 default: break;
622 }
623
624 return scnprintf(bf, size, "%#x", sig);
625}
626
627#define SCA_SIGNUM syscall_arg__scnprintf_signum
628
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300629#define STRARRAY(arg, name, array) \
630 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
631 .arg_parm = { [arg] = &strarray__##array, }
632
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300633static struct syscall_fmt {
634 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300635 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300636 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300637 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300638 bool errmsg;
639 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300640 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300641} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300642 { .name = "access", .errmsg = true,
643 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300644 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300645 { .name = "brk", .hexret = true,
646 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600647 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300648 { .name = "close", .errmsg = true,
649 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300650 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300651 { .name = "dup", .errmsg = true,
652 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
653 { .name = "dup2", .errmsg = true,
654 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
655 { .name = "dup3", .errmsg = true,
656 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300657 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300658 { .name = "eventfd2", .errmsg = true,
659 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300660 { .name = "faccessat", .errmsg = true,
661 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
662 { .name = "fadvise64", .errmsg = true,
663 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
664 { .name = "fallocate", .errmsg = true,
665 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
666 { .name = "fchdir", .errmsg = true,
667 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
668 { .name = "fchmod", .errmsg = true,
669 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
670 { .name = "fchmodat", .errmsg = true,
671 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
672 { .name = "fchown", .errmsg = true,
673 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
674 { .name = "fchownat", .errmsg = true,
675 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
676 { .name = "fcntl", .errmsg = true,
677 .arg_scnprintf = { [0] = SCA_FD, /* fd */
678 [1] = SCA_STRARRAY, /* cmd */ },
679 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
680 { .name = "fdatasync", .errmsg = true,
681 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300682 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300683 .arg_scnprintf = { [0] = SCA_FD, /* fd */
684 [1] = SCA_FLOCK, /* cmd */ }, },
685 { .name = "fsetxattr", .errmsg = true,
686 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
687 { .name = "fstat", .errmsg = true, .alias = "newfstat",
688 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
689 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
690 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
691 { .name = "fstatfs", .errmsg = true,
692 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
693 { .name = "fsync", .errmsg = true,
694 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
695 { .name = "ftruncate", .errmsg = true,
696 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300697 { .name = "futex", .errmsg = true,
698 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300699 { .name = "futimesat", .errmsg = true,
700 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
701 { .name = "getdents", .errmsg = true,
702 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
703 { .name = "getdents64", .errmsg = true,
704 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300705 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
706 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300707 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300708 .arg_scnprintf = { [0] = SCA_FD, /* fd */
709 [2] = SCA_HEX, /* arg */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300710 { .name = "kill", .errmsg = true,
711 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300712 { .name = "linkat", .errmsg = true,
713 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
714 { .name = "lseek", .errmsg = true,
715 .arg_scnprintf = { [0] = SCA_FD, /* fd */
716 [2] = SCA_STRARRAY, /* whence */ },
717 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300718 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300719 { .name = "madvise", .errmsg = true,
720 .arg_scnprintf = { [0] = SCA_HEX, /* start */
721 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300722 { .name = "mkdirat", .errmsg = true,
723 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
724 { .name = "mknodat", .errmsg = true,
725 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300726 { .name = "mlock", .errmsg = true,
727 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
728 { .name = "mlockall", .errmsg = true,
729 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300730 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300731 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300732 [2] = SCA_MMAP_PROT, /* prot */
733 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300734 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300735 .arg_scnprintf = { [0] = SCA_HEX, /* start */
736 [2] = SCA_MMAP_PROT, /* prot */ }, },
737 { .name = "mremap", .hexret = true,
738 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
739 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300740 { .name = "munlock", .errmsg = true,
741 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300742 { .name = "munmap", .errmsg = true,
743 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300744 { .name = "name_to_handle_at", .errmsg = true,
745 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
746 { .name = "newfstatat", .errmsg = true,
747 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300748 { .name = "open", .errmsg = true,
749 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300750 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300751 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
752 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300753 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300754 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
755 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300756 { .name = "pipe2", .errmsg = true,
757 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300758 { .name = "poll", .errmsg = true, .timeout = true, },
759 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300760 { .name = "pread", .errmsg = true, .alias = "pread64",
761 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
762 { .name = "preadv", .errmsg = true, .alias = "pread",
763 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300764 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300765 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
766 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
767 { .name = "pwritev", .errmsg = true,
768 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
769 { .name = "read", .errmsg = true,
770 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
771 { .name = "readlinkat", .errmsg = true,
772 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
773 { .name = "readv", .errmsg = true,
774 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300775 { .name = "recvfrom", .errmsg = true,
776 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
777 { .name = "recvmmsg", .errmsg = true,
778 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
779 { .name = "recvmsg", .errmsg = true,
780 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300781 { .name = "renameat", .errmsg = true,
782 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300783 { .name = "rt_sigaction", .errmsg = true,
784 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300785 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300786 { .name = "rt_sigqueueinfo", .errmsg = true,
787 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
788 { .name = "rt_tgsigqueueinfo", .errmsg = true,
789 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300790 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300791 { .name = "sendmmsg", .errmsg = true,
792 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
793 { .name = "sendmsg", .errmsg = true,
794 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
795 { .name = "sendto", .errmsg = true,
796 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300797 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
798 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300799 { .name = "shutdown", .errmsg = true,
800 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300801 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300802 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
803 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300804 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300805 { .name = "socketpair", .errmsg = true,
806 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
807 [1] = SCA_SK_TYPE, /* type */ },
808 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300809 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300810 { .name = "symlinkat", .errmsg = true,
811 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300812 { .name = "tgkill", .errmsg = true,
813 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
814 { .name = "tkill", .errmsg = true,
815 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300816 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300817 { .name = "unlinkat", .errmsg = true,
818 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
819 { .name = "utimensat", .errmsg = true,
820 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
821 { .name = "write", .errmsg = true,
822 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
823 { .name = "writev", .errmsg = true,
824 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300825};
826
827static int syscall_fmt__cmp(const void *name, const void *fmtp)
828{
829 const struct syscall_fmt *fmt = fmtp;
830 return strcmp(name, fmt->name);
831}
832
833static struct syscall_fmt *syscall_fmt__find(const char *name)
834{
835 const int nmemb = ARRAY_SIZE(syscall_fmts);
836 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
837}
838
839struct syscall {
840 struct event_format *tp_format;
841 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300842 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300843 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300844 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300845 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300846};
847
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200848static size_t fprintf_duration(unsigned long t, FILE *fp)
849{
850 double duration = (double)t / NSEC_PER_MSEC;
851 size_t printed = fprintf(fp, "(");
852
853 if (duration >= 1.0)
854 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
855 else if (duration >= 0.01)
856 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
857 else
858 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300859 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200860}
861
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300862struct thread_trace {
863 u64 entry_time;
864 u64 exit_time;
865 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300866 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300867 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300868 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300869 struct {
870 int max;
871 char **table;
872 } paths;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300873};
874
875static struct thread_trace *thread_trace__new(void)
876{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300877 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
878
879 if (ttrace)
880 ttrace->paths.max = -1;
881
882 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300883}
884
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300885static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300886{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300887 struct thread_trace *ttrace;
888
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300889 if (thread == NULL)
890 goto fail;
891
892 if (thread->priv == NULL)
893 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300894
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300895 if (thread->priv == NULL)
896 goto fail;
897
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300898 ttrace = thread->priv;
899 ++ttrace->nr_events;
900
901 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300902fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300903 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300904 "WARNING: not enough memory, dropping samples!\n");
905 return NULL;
906}
907
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300908struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300909 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300910 int audit_machine;
911 struct {
912 int max;
913 struct syscall *table;
914 } syscalls;
915 struct perf_record_opts opts;
David Ahern8fb598e2013-09-28 13:13:00 -0600916 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300917 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600918 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300919 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300920 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300921 struct strlist *ev_qualifier;
922 bool not_ev_qualifier;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300923 bool live;
David Ahernbdc89662013-08-28 22:29:53 -0600924 struct intlist *tid_list;
925 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300926 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300927 bool multiple_threads;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300928 bool show_comm;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300929 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300930 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300931};
932
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300933static int thread__read_fd_path(struct thread *thread, int fd)
934{
935 struct thread_trace *ttrace = thread->priv;
936 char linkname[PATH_MAX], pathname[PATH_MAX];
937 struct stat st;
938 int ret;
939
940 if (thread->pid_ == thread->tid) {
941 scnprintf(linkname, sizeof(linkname),
942 "/proc/%d/fd/%d", thread->pid_, fd);
943 } else {
944 scnprintf(linkname, sizeof(linkname),
945 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
946 }
947
948 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
949 return -1;
950
951 ret = readlink(linkname, pathname, sizeof(pathname));
952
953 if (ret < 0 || ret > st.st_size)
954 return -1;
955
956 pathname[ret] = '\0';
957
958 if (fd > ttrace->paths.max) {
959 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
960
961 if (npath == NULL)
962 return -1;
963
964 if (ttrace->paths.max != -1) {
965 memset(npath + ttrace->paths.max + 1, 0,
966 (fd - ttrace->paths.max) * sizeof(char *));
967 } else {
968 memset(npath, 0, (fd + 1) * sizeof(char *));
969 }
970
971 ttrace->paths.table = npath;
972 ttrace->paths.max = fd;
973 }
974
975 ttrace->paths.table[fd] = strdup(pathname);
976
977 return ttrace->paths.table[fd] != NULL ? 0 : -1;
978}
979
980static const char *thread__fd_path(struct thread *thread, int fd, bool live)
981{
982 struct thread_trace *ttrace = thread->priv;
983
984 if (ttrace == NULL)
985 return NULL;
986
987 if (fd < 0)
988 return NULL;
989
990 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL) &&
991 (!live || thread__read_fd_path(thread, fd)))
992 return NULL;
993
994 return ttrace->paths.table[fd];
995}
996
997static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
998 struct syscall_arg *arg)
999{
1000 int fd = arg->val;
1001 size_t printed = scnprintf(bf, size, "%d", fd);
1002 const char *path = thread__fd_path(arg->thread, fd, arg->trace->live);
1003
1004 if (path)
1005 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1006
1007 return printed;
1008}
1009
1010static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1011 struct syscall_arg *arg)
1012{
1013 int fd = arg->val;
1014 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1015 struct thread_trace *ttrace = arg->thread->priv;
1016
1017 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
1018 free(ttrace->paths.table[fd]);
1019 ttrace->paths.table[fd] = NULL;
1020 }
1021
1022 return printed;
1023}
1024
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001025static bool trace__filter_duration(struct trace *trace, double t)
1026{
1027 return t < (trace->duration_filter * NSEC_PER_MSEC);
1028}
1029
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001030static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1031{
1032 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1033
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001034 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001035}
1036
Namhyung Kimf15eb532012-10-05 14:02:16 +09001037static bool done = false;
1038
1039static void sig_handler(int sig __maybe_unused)
1040{
1041 done = true;
1042}
1043
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001044static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001045 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001046{
1047 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001048 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001049
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001050 if (trace->multiple_threads) {
1051 if (trace->show_comm)
1052 printed += fprintf(fp, "%.14s/", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001053 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001054 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001055
1056 return printed;
1057}
1058
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001059static int trace__process_event(struct trace *trace, struct machine *machine,
1060 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001061{
1062 int ret = 0;
1063
1064 switch (event->header.type) {
1065 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001066 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001067 "LOST %" PRIu64 " events!\n", event->lost.lost);
1068 ret = machine__process_lost_event(machine, event);
1069 default:
1070 ret = machine__process_event(machine, event);
1071 break;
1072 }
1073
1074 return ret;
1075}
1076
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001077static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001078 union perf_event *event,
1079 struct perf_sample *sample __maybe_unused,
1080 struct machine *machine)
1081{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001082 struct trace *trace = container_of(tool, struct trace, tool);
1083 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001084}
1085
1086static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1087{
1088 int err = symbol__init();
1089
1090 if (err)
1091 return err;
1092
David Ahern8fb598e2013-09-28 13:13:00 -06001093 trace->host = machine__new_host();
1094 if (trace->host == NULL)
1095 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001096
1097 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001098 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001099 trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001100 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001101 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001102 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001103 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001104 }
1105
1106 if (err)
1107 symbol__exit();
1108
1109 return err;
1110}
1111
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001112static int syscall__set_arg_fmts(struct syscall *sc)
1113{
1114 struct format_field *field;
1115 int idx = 0;
1116
1117 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1118 if (sc->arg_scnprintf == NULL)
1119 return -1;
1120
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001121 if (sc->fmt)
1122 sc->arg_parm = sc->fmt->arg_parm;
1123
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001124 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001125 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1126 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1127 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001128 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1129 ++idx;
1130 }
1131
1132 return 0;
1133}
1134
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001135static int trace__read_syscall_info(struct trace *trace, int id)
1136{
1137 char tp_name[128];
1138 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001139 const char *name = audit_syscall_to_name(id, trace->audit_machine);
1140
1141 if (name == NULL)
1142 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001143
1144 if (id > trace->syscalls.max) {
1145 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1146
1147 if (nsyscalls == NULL)
1148 return -1;
1149
1150 if (trace->syscalls.max != -1) {
1151 memset(nsyscalls + trace->syscalls.max + 1, 0,
1152 (id - trace->syscalls.max) * sizeof(*sc));
1153 } else {
1154 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1155 }
1156
1157 trace->syscalls.table = nsyscalls;
1158 trace->syscalls.max = id;
1159 }
1160
1161 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001162 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001163
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001164 if (trace->ev_qualifier) {
1165 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1166
1167 if (!(in ^ trace->not_ev_qualifier)) {
1168 sc->filtered = true;
1169 /*
1170 * No need to do read tracepoint information since this will be
1171 * filtered out.
1172 */
1173 return 0;
1174 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001175 }
1176
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001177 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001178
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001179 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
1180 sc->tp_format = event_format__new("syscalls", tp_name);
1181
1182 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1183 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1184 sc->tp_format = event_format__new("syscalls", tp_name);
1185 }
1186
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001187 if (sc->tp_format == NULL)
1188 return -1;
1189
1190 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001191}
1192
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001193static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001194 unsigned long *args, struct trace *trace,
1195 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001196{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001197 size_t printed = 0;
1198
1199 if (sc->tp_format != NULL) {
1200 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001201 u8 bit = 1;
1202 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001203 .idx = 0,
1204 .mask = 0,
1205 .trace = trace,
1206 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001207 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001208
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001209 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001210 field = field->next, ++arg.idx, bit <<= 1) {
1211 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001212 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001213 /*
1214 * Suppress this argument if its value is zero and
1215 * and we don't have a string associated in an
1216 * strarray for it.
1217 */
1218 if (args[arg.idx] == 0 &&
1219 !(sc->arg_scnprintf &&
1220 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1221 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001222 continue;
1223
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001224 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001225 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001226 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1227 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001228 if (sc->arg_parm)
1229 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001230 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1231 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001232 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001233 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001234 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001235 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001236 }
1237 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001238 int i = 0;
1239
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001240 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001241 printed += scnprintf(bf + printed, size - printed,
1242 "%sarg%d: %ld",
1243 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001244 ++i;
1245 }
1246 }
1247
1248 return printed;
1249}
1250
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001251typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1252 struct perf_sample *sample);
1253
1254static struct syscall *trace__syscall_info(struct trace *trace,
1255 struct perf_evsel *evsel,
1256 struct perf_sample *sample)
1257{
1258 int id = perf_evsel__intval(evsel, sample, "id");
1259
1260 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001261
1262 /*
1263 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1264 * before that, leaving at a higher verbosity level till that is
1265 * explained. Reproduced with plain ftrace with:
1266 *
1267 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1268 * grep "NR -1 " /t/trace_pipe
1269 *
1270 * After generating some load on the machine.
1271 */
1272 if (verbose > 1) {
1273 static u64 n;
1274 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1275 id, perf_evsel__name(evsel), ++n);
1276 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001277 return NULL;
1278 }
1279
1280 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1281 trace__read_syscall_info(trace, id))
1282 goto out_cant_read;
1283
1284 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1285 goto out_cant_read;
1286
1287 return &trace->syscalls.table[id];
1288
1289out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001290 if (verbose) {
1291 fprintf(trace->output, "Problems reading syscall %d", id);
1292 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1293 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1294 fputs(" information\n", trace->output);
1295 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001296 return NULL;
1297}
1298
1299static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1300 struct perf_sample *sample)
1301{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001302 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001303 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001304 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001305 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001306 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001307 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001308
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001309 if (sc == NULL)
1310 return -1;
1311
1312 if (sc->filtered)
1313 return 0;
1314
David Ahern8fb598e2013-09-28 13:13:00 -06001315 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001316 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001317 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001318 return -1;
1319
1320 args = perf_evsel__rawptr(evsel, sample, "args");
1321 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001322 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001323 return -1;
1324 }
1325
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001326 ttrace = thread->priv;
1327
1328 if (ttrace->entry_str == NULL) {
1329 ttrace->entry_str = malloc(1024);
1330 if (!ttrace->entry_str)
1331 return -1;
1332 }
1333
1334 ttrace->entry_time = sample->time;
1335 msg = ttrace->entry_str;
1336 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1337
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001338 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1339 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001340
1341 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001342 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001343 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1344 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001345 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001346 } else
1347 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001348
1349 return 0;
1350}
1351
1352static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1353 struct perf_sample *sample)
1354{
1355 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001356 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001357 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001358 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001359 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001360
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001361 if (sc == NULL)
1362 return -1;
1363
1364 if (sc->filtered)
1365 return 0;
1366
David Ahern8fb598e2013-09-28 13:13:00 -06001367 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001368 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001369 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001370 return -1;
1371
1372 ret = perf_evsel__intval(evsel, sample, "ret");
1373
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001374 ttrace = thread->priv;
1375
1376 ttrace->exit_time = sample->time;
1377
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001378 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001379 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001380 if (trace__filter_duration(trace, duration))
1381 goto out;
1382 } else if (trace->duration_filter)
1383 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001384
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001385 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001386
1387 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001388 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001389 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001390 fprintf(trace->output, " ... [");
1391 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1392 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001393 }
1394
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001395 if (sc->fmt == NULL) {
1396signed_print:
1397 fprintf(trace->output, ") = %d", ret);
1398 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001399 char bf[256];
1400 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1401 *e = audit_errno_to_name(-ret);
1402
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001403 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001404 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001405 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001406 else if (sc->fmt->hexret)
1407 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001408 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001409 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001410
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001411 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001412out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001413 ttrace->entry_pending = false;
1414
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001415 return 0;
1416}
1417
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001418static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1419 struct perf_sample *sample)
1420{
1421 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1422 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001423 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001424 sample->pid,
1425 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001426 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001427
1428 if (ttrace == NULL)
1429 goto out_dump;
1430
1431 ttrace->runtime_ms += runtime_ms;
1432 trace->runtime_ms += runtime_ms;
1433 return 0;
1434
1435out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001436 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001437 evsel->name,
1438 perf_evsel__strval(evsel, sample, "comm"),
1439 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1440 runtime,
1441 perf_evsel__intval(evsel, sample, "vruntime"));
1442 return 0;
1443}
1444
David Ahernbdc89662013-08-28 22:29:53 -06001445static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1446{
1447 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1448 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1449 return false;
1450
1451 if (trace->pid_list || trace->tid_list)
1452 return true;
1453
1454 return false;
1455}
1456
David Ahern6810fc92013-08-28 22:29:52 -06001457static int trace__process_sample(struct perf_tool *tool,
1458 union perf_event *event __maybe_unused,
1459 struct perf_sample *sample,
1460 struct perf_evsel *evsel,
1461 struct machine *machine __maybe_unused)
1462{
1463 struct trace *trace = container_of(tool, struct trace, tool);
1464 int err = 0;
1465
1466 tracepoint_handler handler = evsel->handler.func;
1467
David Ahernbdc89662013-08-28 22:29:53 -06001468 if (skip_sample(trace, sample))
1469 return 0;
1470
David Ahern4bb09192013-09-04 12:37:43 -06001471 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001472 trace->base_time = sample->time;
1473
1474 if (handler)
1475 handler(trace, evsel, sample);
1476
1477 return err;
1478}
1479
1480static bool
1481perf_session__has_tp(struct perf_session *session, const char *name)
1482{
1483 struct perf_evsel *evsel;
1484
1485 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1486
1487 return evsel != NULL;
1488}
1489
David Ahernbdc89662013-08-28 22:29:53 -06001490static int parse_target_str(struct trace *trace)
1491{
1492 if (trace->opts.target.pid) {
1493 trace->pid_list = intlist__new(trace->opts.target.pid);
1494 if (trace->pid_list == NULL) {
1495 pr_err("Error parsing process id string\n");
1496 return -EINVAL;
1497 }
1498 }
1499
1500 if (trace->opts.target.tid) {
1501 trace->tid_list = intlist__new(trace->opts.target.tid);
1502 if (trace->tid_list == NULL) {
1503 pr_err("Error parsing thread id string\n");
1504 return -EINVAL;
1505 }
1506 }
1507
1508 return 0;
1509}
1510
David Ahern5e2485b2013-09-28 13:13:01 -06001511static int trace__record(int argc, const char **argv)
1512{
1513 unsigned int rec_argc, i, j;
1514 const char **rec_argv;
1515 const char * const record_args[] = {
1516 "record",
1517 "-R",
1518 "-m", "1024",
1519 "-c", "1",
1520 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
1521 };
1522
1523 rec_argc = ARRAY_SIZE(record_args) + argc;
1524 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1525
1526 if (rec_argv == NULL)
1527 return -ENOMEM;
1528
1529 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1530 rec_argv[i] = record_args[i];
1531
1532 for (j = 0; j < (unsigned int)argc; j++, i++)
1533 rec_argv[i] = argv[j];
1534
1535 return cmd_record(i, rec_argv, NULL);
1536}
1537
Namhyung Kimf15eb532012-10-05 14:02:16 +09001538static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001539{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001540 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001541 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001542 int err = -1, i;
1543 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001544 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001545
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001546 trace->live = true;
1547
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001548 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001549 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001550 goto out;
1551 }
1552
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001553 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1554 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001555 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001556 goto out_delete_evlist;
1557 }
1558
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001559 if (trace->sched &&
1560 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1561 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001562 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001563 goto out_delete_evlist;
1564 }
1565
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001566 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1567 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001568 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001569 goto out_delete_evlist;
1570 }
1571
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001572 err = trace__symbols_init(trace, evlist);
1573 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001574 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001575 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001576 }
1577
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001578 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001579
Namhyung Kimf15eb532012-10-05 14:02:16 +09001580 signal(SIGCHLD, sig_handler);
1581 signal(SIGINT, sig_handler);
1582
1583 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001584 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001585 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001586 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001587 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001588 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001589 }
1590 }
1591
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001592 err = perf_evlist__open(evlist);
1593 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001594 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001595 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001596 }
1597
1598 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1599 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001600 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001601 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001602 }
1603
1604 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001605
1606 if (forks)
1607 perf_evlist__start_workload(evlist);
1608
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001609 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001610again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001611 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001612
1613 for (i = 0; i < evlist->nr_mmaps; i++) {
1614 union perf_event *event;
1615
1616 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1617 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001618 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001619 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001620
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001621 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001622
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001623 err = perf_evlist__parse_sample(evlist, event, &sample);
1624 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001625 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001626 continue;
1627 }
1628
David Ahern4bb09192013-09-04 12:37:43 -06001629 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001630 trace->base_time = sample.time;
1631
1632 if (type != PERF_RECORD_SAMPLE) {
David Ahern8fb598e2013-09-28 13:13:00 -06001633 trace__process_event(trace, trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001634 continue;
1635 }
1636
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001637 evsel = perf_evlist__id2evsel(evlist, sample.id);
1638 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001639 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001640 continue;
1641 }
1642
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001643 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001644 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 -03001645 perf_evsel__name(evsel), sample.tid,
1646 sample.cpu, sample.raw_size);
1647 continue;
1648 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001649
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001650 handler = evsel->handler.func;
1651 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001652
1653 if (done)
1654 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001655 }
1656 }
1657
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001658 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001659 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001660 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001661
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001662 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001663 }
1664
1665 if (done)
1666 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001667
1668 goto again;
1669
Namhyung Kim3beb0862013-03-15 14:48:50 +09001670out_unmap_evlist:
1671 perf_evlist__munmap(evlist);
1672out_close_evlist:
1673 perf_evlist__close(evlist);
1674out_delete_maps:
1675 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001676out_delete_evlist:
1677 perf_evlist__delete(evlist);
1678out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001679 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001680 return err;
1681}
1682
David Ahern6810fc92013-08-28 22:29:52 -06001683static int trace__replay(struct trace *trace)
1684{
1685 const struct perf_evsel_str_handler handlers[] = {
1686 { "raw_syscalls:sys_enter", trace__sys_enter, },
1687 { "raw_syscalls:sys_exit", trace__sys_exit, },
1688 };
1689
1690 struct perf_session *session;
1691 int err = -1;
1692
1693 trace->tool.sample = trace__process_sample;
1694 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001695 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001696 trace->tool.comm = perf_event__process_comm;
1697 trace->tool.exit = perf_event__process_exit;
1698 trace->tool.fork = perf_event__process_fork;
1699 trace->tool.attr = perf_event__process_attr;
1700 trace->tool.tracing_data = perf_event__process_tracing_data;
1701 trace->tool.build_id = perf_event__process_build_id;
1702
1703 trace->tool.ordered_samples = true;
1704 trace->tool.ordering_requires_timestamps = true;
1705
1706 /* add tid to output */
1707 trace->multiple_threads = true;
1708
1709 if (symbol__init() < 0)
1710 return -1;
1711
1712 session = perf_session__new(input_name, O_RDONLY, 0, false,
1713 &trace->tool);
1714 if (session == NULL)
1715 return -ENOMEM;
1716
David Ahern8fb598e2013-09-28 13:13:00 -06001717 trace->host = &session->machines.host;
1718
David Ahern6810fc92013-08-28 22:29:52 -06001719 err = perf_session__set_tracepoints_handlers(session, handlers);
1720 if (err)
1721 goto out;
1722
1723 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1724 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1725 goto out;
1726 }
1727
1728 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1729 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1730 goto out;
1731 }
1732
David Ahernbdc89662013-08-28 22:29:53 -06001733 err = parse_target_str(trace);
1734 if (err != 0)
1735 goto out;
1736
David Ahern6810fc92013-08-28 22:29:52 -06001737 setup_pager();
1738
1739 err = perf_session__process_events(session, &trace->tool);
1740 if (err)
1741 pr_err("Failed to process events, error %d", err);
1742
1743out:
1744 perf_session__delete(session);
1745
1746 return err;
1747}
1748
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001749static size_t trace__fprintf_threads_header(FILE *fp)
1750{
1751 size_t printed;
1752
1753 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1754 printed += fprintf(fp," __) Summary of events (__\n\n");
1755 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1756 printed += fprintf(fp," _____________________________________________________________________\n\n");
1757
1758 return printed;
1759}
1760
David Ahern896cbb52013-09-28 13:12:59 -06001761/* struct used to pass data to per-thread function */
1762struct summary_data {
1763 FILE *fp;
1764 struct trace *trace;
1765 size_t printed;
1766};
1767
1768static int trace__fprintf_one_thread(struct thread *thread, void *priv)
1769{
1770 struct summary_data *data = priv;
1771 FILE *fp = data->fp;
1772 size_t printed = data->printed;
1773 struct trace *trace = data->trace;
1774 struct thread_trace *ttrace = thread->priv;
1775 const char *color;
1776 double ratio;
1777
1778 if (ttrace == NULL)
1779 return 0;
1780
1781 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1782
1783 color = PERF_COLOR_NORMAL;
1784 if (ratio > 50.0)
1785 color = PERF_COLOR_RED;
1786 else if (ratio > 25.0)
1787 color = PERF_COLOR_GREEN;
1788 else if (ratio > 5.0)
1789 color = PERF_COLOR_YELLOW;
1790
1791 printed += color_fprintf(fp, color, "%20s", thread->comm);
1792 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1793 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1794 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1795
1796 data->printed += printed;
1797
1798 return 0;
1799}
1800
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001801static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1802{
David Ahern896cbb52013-09-28 13:12:59 -06001803 struct summary_data data = {
1804 .fp = fp,
1805 .trace = trace
1806 };
1807 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001808
David Ahern896cbb52013-09-28 13:12:59 -06001809 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001810
David Ahern896cbb52013-09-28 13:12:59 -06001811 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001812}
1813
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001814static int trace__set_duration(const struct option *opt, const char *str,
1815 int unset __maybe_unused)
1816{
1817 struct trace *trace = opt->value;
1818
1819 trace->duration_filter = atof(str);
1820 return 0;
1821}
1822
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001823static int trace__open_output(struct trace *trace, const char *filename)
1824{
1825 struct stat st;
1826
1827 if (!stat(filename, &st) && st.st_size) {
1828 char oldname[PATH_MAX];
1829
1830 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1831 unlink(oldname);
1832 rename(filename, oldname);
1833 }
1834
1835 trace->output = fopen(filename, "w");
1836
1837 return trace->output == NULL ? -errno : 0;
1838}
1839
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001840int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1841{
1842 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001843 "perf trace [<options>] [<command>]",
1844 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06001845 "perf trace record [<options>] [<command>]",
1846 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001847 NULL
1848 };
1849 struct trace trace = {
1850 .audit_machine = audit_detect_machine(),
1851 .syscalls = {
1852 . max = -1,
1853 },
1854 .opts = {
1855 .target = {
1856 .uid = UINT_MAX,
1857 .uses_mmap = true,
1858 },
1859 .user_freq = UINT_MAX,
1860 .user_interval = ULLONG_MAX,
1861 .no_delay = true,
1862 .mmap_pages = 1024,
1863 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001864 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001865 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001866 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001867 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001868 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001869 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001870 OPT_BOOLEAN(0, "comm", &trace.show_comm,
1871 "show the thread COMM next to its id"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001872 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1873 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001874 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001875 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001876 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1877 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001878 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001879 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001880 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001881 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001882 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001883 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001884 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001885 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02001886 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1887 "number of mmap data pages",
1888 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06001889 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001890 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001891 OPT_CALLBACK(0, "duration", &trace, "float",
1892 "show only events with duration > N.M ms",
1893 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001894 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001895 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06001896 OPT_BOOLEAN('T', "time", &trace.full_time,
1897 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001898 OPT_END()
1899 };
1900 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001901 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001902
David Ahern5e2485b2013-09-28 13:13:01 -06001903 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
1904 return trace__record(argc-2, &argv[2]);
1905
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001906 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001907
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001908 if (output_name != NULL) {
1909 err = trace__open_output(&trace, output_name);
1910 if (err < 0) {
1911 perror("failed to create output file");
1912 goto out;
1913 }
1914 }
1915
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001916 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001917 const char *s = ev_qualifier_str;
1918
1919 trace.not_ev_qualifier = *s == '!';
1920 if (trace.not_ev_qualifier)
1921 ++s;
1922 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001923 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001924 fputs("Not enough memory to parse event qualifier",
1925 trace.output);
1926 err = -ENOMEM;
1927 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001928 }
1929 }
1930
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001931 err = perf_target__validate(&trace.opts.target);
1932 if (err) {
1933 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001934 fprintf(trace.output, "%s", bf);
1935 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001936 }
1937
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001938 err = perf_target__parse_uid(&trace.opts.target);
1939 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001940 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001941 fprintf(trace.output, "%s", bf);
1942 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001943 }
1944
Namhyung Kimf15eb532012-10-05 14:02:16 +09001945 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001946 trace.opts.target.system_wide = true;
1947
David Ahern6810fc92013-08-28 22:29:52 -06001948 if (input_name)
1949 err = trace__replay(&trace);
1950 else
1951 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001952
1953 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001954 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001955
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001956out_close:
1957 if (output_name != NULL)
1958 fclose(trace.output);
1959out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001960 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001961}