blob: 1e2368f56a74346a0d9d73da4e990698bda7e57e [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 {
47 int nr_entries;
48 const char **entries;
49};
50
51#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
52 .nr_entries = ARRAY_SIZE(array), \
53 .entries = array, \
54}
55
56static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
57 struct syscall_arg *arg)
58{
59 int idx = arg->val;
60 struct strarray *sa = arg->parm;
61
62 if (idx < 0 || idx >= sa->nr_entries)
63 return scnprintf(bf, size, "%d", idx);
64
65 return scnprintf(bf, size, "%s", sa->entries[idx]);
66}
67
68#define SCA_STRARRAY syscall_arg__scnprintf_strarray
69
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -030070static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
71 struct syscall_arg *arg);
72
73#define SCA_FD syscall_arg__scnprintf_fd
74
75static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
76 struct syscall_arg *arg)
77{
78 int fd = arg->val;
79
80 if (fd == AT_FDCWD)
81 return scnprintf(bf, size, "CWD");
82
83 return syscall_arg__scnprintf_fd(bf, size, arg);
84}
85
86#define SCA_FDAT syscall_arg__scnprintf_fd_at
87
88static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
89 struct syscall_arg *arg);
90
91#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
92
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -030093static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030094 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030095{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030096 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030097}
98
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -030099#define SCA_HEX syscall_arg__scnprintf_hex
100
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300101static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300102 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300103{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300104 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300105
106 if (prot == PROT_NONE)
107 return scnprintf(bf, size, "NONE");
108#define P_MMAP_PROT(n) \
109 if (prot & PROT_##n) { \
110 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
111 prot &= ~PROT_##n; \
112 }
113
114 P_MMAP_PROT(EXEC);
115 P_MMAP_PROT(READ);
116 P_MMAP_PROT(WRITE);
117#ifdef PROT_SEM
118 P_MMAP_PROT(SEM);
119#endif
120 P_MMAP_PROT(GROWSDOWN);
121 P_MMAP_PROT(GROWSUP);
122#undef P_MMAP_PROT
123
124 if (prot)
125 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
126
127 return printed;
128}
129
130#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
131
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300132static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300133 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300134{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300135 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300136
137#define P_MMAP_FLAG(n) \
138 if (flags & MAP_##n) { \
139 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
140 flags &= ~MAP_##n; \
141 }
142
143 P_MMAP_FLAG(SHARED);
144 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400145#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300146 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400147#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300148 P_MMAP_FLAG(ANONYMOUS);
149 P_MMAP_FLAG(DENYWRITE);
150 P_MMAP_FLAG(EXECUTABLE);
151 P_MMAP_FLAG(FILE);
152 P_MMAP_FLAG(FIXED);
153 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600154#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300155 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600156#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300157 P_MMAP_FLAG(LOCKED);
158 P_MMAP_FLAG(NONBLOCK);
159 P_MMAP_FLAG(NORESERVE);
160 P_MMAP_FLAG(POPULATE);
161 P_MMAP_FLAG(STACK);
162#ifdef MAP_UNINITIALIZED
163 P_MMAP_FLAG(UNINITIALIZED);
164#endif
165#undef P_MMAP_FLAG
166
167 if (flags)
168 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
169
170 return printed;
171}
172
173#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
174
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300175static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300176 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300177{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300178 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300179
180 switch (behavior) {
181#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
182 P_MADV_BHV(NORMAL);
183 P_MADV_BHV(RANDOM);
184 P_MADV_BHV(SEQUENTIAL);
185 P_MADV_BHV(WILLNEED);
186 P_MADV_BHV(DONTNEED);
187 P_MADV_BHV(REMOVE);
188 P_MADV_BHV(DONTFORK);
189 P_MADV_BHV(DOFORK);
190 P_MADV_BHV(HWPOISON);
191#ifdef MADV_SOFT_OFFLINE
192 P_MADV_BHV(SOFT_OFFLINE);
193#endif
194 P_MADV_BHV(MERGEABLE);
195 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600196#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300197 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600198#endif
199#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300200 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600201#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300202#ifdef MADV_DONTDUMP
203 P_MADV_BHV(DONTDUMP);
204#endif
205#ifdef MADV_DODUMP
206 P_MADV_BHV(DODUMP);
207#endif
208#undef P_MADV_PHV
209 default: break;
210 }
211
212 return scnprintf(bf, size, "%#x", behavior);
213}
214
215#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
216
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300217static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
218 struct syscall_arg *arg)
219{
220 int printed = 0, op = arg->val;
221
222 if (op == 0)
223 return scnprintf(bf, size, "NONE");
224#define P_CMD(cmd) \
225 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
226 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
227 op &= ~LOCK_##cmd; \
228 }
229
230 P_CMD(SH);
231 P_CMD(EX);
232 P_CMD(NB);
233 P_CMD(UN);
234 P_CMD(MAND);
235 P_CMD(RW);
236 P_CMD(READ);
237 P_CMD(WRITE);
238#undef P_OP
239
240 if (op)
241 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
242
243 return printed;
244}
245
246#define SCA_FLOCK syscall_arg__scnprintf_flock
247
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300248static 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 -0300249{
250 enum syscall_futex_args {
251 SCF_UADDR = (1 << 0),
252 SCF_OP = (1 << 1),
253 SCF_VAL = (1 << 2),
254 SCF_TIMEOUT = (1 << 3),
255 SCF_UADDR2 = (1 << 4),
256 SCF_VAL3 = (1 << 5),
257 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300258 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300259 int cmd = op & FUTEX_CMD_MASK;
260 size_t printed = 0;
261
262 switch (cmd) {
263#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300264 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
265 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
266 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
267 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
268 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
269 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300270 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300271 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
272 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
273 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
274 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
275 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300276 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
277 default: printed = scnprintf(bf, size, "%#x", cmd); break;
278 }
279
280 if (op & FUTEX_PRIVATE_FLAG)
281 printed += scnprintf(bf + printed, size - printed, "|PRIV");
282
283 if (op & FUTEX_CLOCK_REALTIME)
284 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
285
286 return printed;
287}
288
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300289#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
290
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300291static const char *epoll_ctl_ops[] = { [1] = "ADD", "DEL", "MOD", };
292static DEFINE_STRARRAY(epoll_ctl_ops);
293
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300294static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
295static DEFINE_STRARRAY(itimers);
296
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300297static const char *whences[] = { "SET", "CUR", "END",
298#ifdef SEEK_DATA
299"DATA",
300#endif
301#ifdef SEEK_HOLE
302"HOLE",
303#endif
304};
305static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300306
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300307static const char *fcntl_cmds[] = {
308 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
309 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
310 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
311 "F_GETOWNER_UIDS",
312};
313static DEFINE_STRARRAY(fcntl_cmds);
314
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300315static const char *rlimit_resources[] = {
316 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
317 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
318 "RTTIME",
319};
320static DEFINE_STRARRAY(rlimit_resources);
321
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300322static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
323static DEFINE_STRARRAY(sighow);
324
David Ahern4f8c1b72013-09-22 19:45:00 -0600325static const char *clockid[] = {
326 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
327 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
328};
329static DEFINE_STRARRAY(clockid);
330
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300331static const char *socket_families[] = {
332 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
333 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
334 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
335 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
336 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
337 "ALG", "NFC", "VSOCK",
338};
339static DEFINE_STRARRAY(socket_families);
340
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300341#ifndef SOCK_TYPE_MASK
342#define SOCK_TYPE_MASK 0xf
343#endif
344
345static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
346 struct syscall_arg *arg)
347{
348 size_t printed;
349 int type = arg->val,
350 flags = type & ~SOCK_TYPE_MASK;
351
352 type &= SOCK_TYPE_MASK;
353 /*
354 * Can't use a strarray, MIPS may override for ABI reasons.
355 */
356 switch (type) {
357#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
358 P_SK_TYPE(STREAM);
359 P_SK_TYPE(DGRAM);
360 P_SK_TYPE(RAW);
361 P_SK_TYPE(RDM);
362 P_SK_TYPE(SEQPACKET);
363 P_SK_TYPE(DCCP);
364 P_SK_TYPE(PACKET);
365#undef P_SK_TYPE
366 default:
367 printed = scnprintf(bf, size, "%#x", type);
368 }
369
370#define P_SK_FLAG(n) \
371 if (flags & SOCK_##n) { \
372 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
373 flags &= ~SOCK_##n; \
374 }
375
376 P_SK_FLAG(CLOEXEC);
377 P_SK_FLAG(NONBLOCK);
378#undef P_SK_FLAG
379
380 if (flags)
381 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
382
383 return printed;
384}
385
386#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
387
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300388#ifndef MSG_PROBE
389#define MSG_PROBE 0x10
390#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600391#ifndef MSG_WAITFORONE
392#define MSG_WAITFORONE 0x10000
393#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300394#ifndef MSG_SENDPAGE_NOTLAST
395#define MSG_SENDPAGE_NOTLAST 0x20000
396#endif
397#ifndef MSG_FASTOPEN
398#define MSG_FASTOPEN 0x20000000
399#endif
400
401static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
402 struct syscall_arg *arg)
403{
404 int printed = 0, flags = arg->val;
405
406 if (flags == 0)
407 return scnprintf(bf, size, "NONE");
408#define P_MSG_FLAG(n) \
409 if (flags & MSG_##n) { \
410 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
411 flags &= ~MSG_##n; \
412 }
413
414 P_MSG_FLAG(OOB);
415 P_MSG_FLAG(PEEK);
416 P_MSG_FLAG(DONTROUTE);
417 P_MSG_FLAG(TRYHARD);
418 P_MSG_FLAG(CTRUNC);
419 P_MSG_FLAG(PROBE);
420 P_MSG_FLAG(TRUNC);
421 P_MSG_FLAG(DONTWAIT);
422 P_MSG_FLAG(EOR);
423 P_MSG_FLAG(WAITALL);
424 P_MSG_FLAG(FIN);
425 P_MSG_FLAG(SYN);
426 P_MSG_FLAG(CONFIRM);
427 P_MSG_FLAG(RST);
428 P_MSG_FLAG(ERRQUEUE);
429 P_MSG_FLAG(NOSIGNAL);
430 P_MSG_FLAG(MORE);
431 P_MSG_FLAG(WAITFORONE);
432 P_MSG_FLAG(SENDPAGE_NOTLAST);
433 P_MSG_FLAG(FASTOPEN);
434 P_MSG_FLAG(CMSG_CLOEXEC);
435#undef P_MSG_FLAG
436
437 if (flags)
438 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
439
440 return printed;
441}
442
443#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
444
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300445static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
446 struct syscall_arg *arg)
447{
448 size_t printed = 0;
449 int mode = arg->val;
450
451 if (mode == F_OK) /* 0 */
452 return scnprintf(bf, size, "F");
453#define P_MODE(n) \
454 if (mode & n##_OK) { \
455 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
456 mode &= ~n##_OK; \
457 }
458
459 P_MODE(R);
460 P_MODE(W);
461 P_MODE(X);
462#undef P_MODE
463
464 if (mode)
465 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
466
467 return printed;
468}
469
470#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
471
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300472static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300473 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300474{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300475 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300476
477 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300478 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300479
480 if (flags == 0)
481 return scnprintf(bf, size, "RDONLY");
482#define P_FLAG(n) \
483 if (flags & O_##n) { \
484 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
485 flags &= ~O_##n; \
486 }
487
488 P_FLAG(APPEND);
489 P_FLAG(ASYNC);
490 P_FLAG(CLOEXEC);
491 P_FLAG(CREAT);
492 P_FLAG(DIRECT);
493 P_FLAG(DIRECTORY);
494 P_FLAG(EXCL);
495 P_FLAG(LARGEFILE);
496 P_FLAG(NOATIME);
497 P_FLAG(NOCTTY);
498#ifdef O_NONBLOCK
499 P_FLAG(NONBLOCK);
500#elif O_NDELAY
501 P_FLAG(NDELAY);
502#endif
503#ifdef O_PATH
504 P_FLAG(PATH);
505#endif
506 P_FLAG(RDWR);
507#ifdef O_DSYNC
508 if ((flags & O_SYNC) == O_SYNC)
509 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
510 else {
511 P_FLAG(DSYNC);
512 }
513#else
514 P_FLAG(SYNC);
515#endif
516 P_FLAG(TRUNC);
517 P_FLAG(WRONLY);
518#undef P_FLAG
519
520 if (flags)
521 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
522
523 return printed;
524}
525
526#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
527
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300528static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
529 struct syscall_arg *arg)
530{
531 int printed = 0, flags = arg->val;
532
533 if (flags == 0)
534 return scnprintf(bf, size, "NONE");
535#define P_FLAG(n) \
536 if (flags & EFD_##n) { \
537 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
538 flags &= ~EFD_##n; \
539 }
540
541 P_FLAG(SEMAPHORE);
542 P_FLAG(CLOEXEC);
543 P_FLAG(NONBLOCK);
544#undef P_FLAG
545
546 if (flags)
547 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
548
549 return printed;
550}
551
552#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
553
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300554static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
555 struct syscall_arg *arg)
556{
557 int printed = 0, flags = arg->val;
558
559#define P_FLAG(n) \
560 if (flags & O_##n) { \
561 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
562 flags &= ~O_##n; \
563 }
564
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_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
576
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300577static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
578{
579 int sig = arg->val;
580
581 switch (sig) {
582#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
583 P_SIGNUM(HUP);
584 P_SIGNUM(INT);
585 P_SIGNUM(QUIT);
586 P_SIGNUM(ILL);
587 P_SIGNUM(TRAP);
588 P_SIGNUM(ABRT);
589 P_SIGNUM(BUS);
590 P_SIGNUM(FPE);
591 P_SIGNUM(KILL);
592 P_SIGNUM(USR1);
593 P_SIGNUM(SEGV);
594 P_SIGNUM(USR2);
595 P_SIGNUM(PIPE);
596 P_SIGNUM(ALRM);
597 P_SIGNUM(TERM);
598 P_SIGNUM(STKFLT);
599 P_SIGNUM(CHLD);
600 P_SIGNUM(CONT);
601 P_SIGNUM(STOP);
602 P_SIGNUM(TSTP);
603 P_SIGNUM(TTIN);
604 P_SIGNUM(TTOU);
605 P_SIGNUM(URG);
606 P_SIGNUM(XCPU);
607 P_SIGNUM(XFSZ);
608 P_SIGNUM(VTALRM);
609 P_SIGNUM(PROF);
610 P_SIGNUM(WINCH);
611 P_SIGNUM(IO);
612 P_SIGNUM(PWR);
613 P_SIGNUM(SYS);
614 default: break;
615 }
616
617 return scnprintf(bf, size, "%#x", sig);
618}
619
620#define SCA_SIGNUM syscall_arg__scnprintf_signum
621
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300622#define STRARRAY(arg, name, array) \
623 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
624 .arg_parm = { [arg] = &strarray__##array, }
625
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300626static struct syscall_fmt {
627 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300628 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300629 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300630 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300631 bool errmsg;
632 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300633 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300634} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300635 { .name = "access", .errmsg = true,
636 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300637 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300638 { .name = "brk", .hexret = true,
639 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600640 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300641 { .name = "close", .errmsg = true,
642 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300643 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300644 { .name = "dup", .errmsg = true,
645 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
646 { .name = "dup2", .errmsg = true,
647 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
648 { .name = "dup3", .errmsg = true,
649 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300650 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300651 { .name = "eventfd2", .errmsg = true,
652 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300653 { .name = "faccessat", .errmsg = true,
654 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
655 { .name = "fadvise64", .errmsg = true,
656 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
657 { .name = "fallocate", .errmsg = true,
658 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
659 { .name = "fchdir", .errmsg = true,
660 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
661 { .name = "fchmod", .errmsg = true,
662 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
663 { .name = "fchmodat", .errmsg = true,
664 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
665 { .name = "fchown", .errmsg = true,
666 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
667 { .name = "fchownat", .errmsg = true,
668 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
669 { .name = "fcntl", .errmsg = true,
670 .arg_scnprintf = { [0] = SCA_FD, /* fd */
671 [1] = SCA_STRARRAY, /* cmd */ },
672 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
673 { .name = "fdatasync", .errmsg = true,
674 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300675 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300676 .arg_scnprintf = { [0] = SCA_FD, /* fd */
677 [1] = SCA_FLOCK, /* cmd */ }, },
678 { .name = "fsetxattr", .errmsg = true,
679 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
680 { .name = "fstat", .errmsg = true, .alias = "newfstat",
681 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
682 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
683 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
684 { .name = "fstatfs", .errmsg = true,
685 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
686 { .name = "fsync", .errmsg = true,
687 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
688 { .name = "ftruncate", .errmsg = true,
689 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300690 { .name = "futex", .errmsg = true,
691 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300692 { .name = "futimesat", .errmsg = true,
693 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
694 { .name = "getdents", .errmsg = true,
695 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
696 { .name = "getdents64", .errmsg = true,
697 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300698 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
699 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300700 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300701 .arg_scnprintf = { [0] = SCA_FD, /* fd */
702 [2] = SCA_HEX, /* arg */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300703 { .name = "kill", .errmsg = true,
704 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300705 { .name = "linkat", .errmsg = true,
706 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
707 { .name = "lseek", .errmsg = true,
708 .arg_scnprintf = { [0] = SCA_FD, /* fd */
709 [2] = SCA_STRARRAY, /* whence */ },
710 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300711 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300712 { .name = "madvise", .errmsg = true,
713 .arg_scnprintf = { [0] = SCA_HEX, /* start */
714 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300715 { .name = "mkdirat", .errmsg = true,
716 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
717 { .name = "mknodat", .errmsg = true,
718 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300719 { .name = "mlock", .errmsg = true,
720 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
721 { .name = "mlockall", .errmsg = true,
722 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300723 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300724 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300725 [2] = SCA_MMAP_PROT, /* prot */
726 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300727 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300728 .arg_scnprintf = { [0] = SCA_HEX, /* start */
729 [2] = SCA_MMAP_PROT, /* prot */ }, },
730 { .name = "mremap", .hexret = true,
731 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
732 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300733 { .name = "munlock", .errmsg = true,
734 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300735 { .name = "munmap", .errmsg = true,
736 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300737 { .name = "name_to_handle_at", .errmsg = true,
738 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
739 { .name = "newfstatat", .errmsg = true,
740 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300741 { .name = "open", .errmsg = true,
742 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300743 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300744 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
745 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300746 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300747 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
748 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300749 { .name = "pipe2", .errmsg = true,
750 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300751 { .name = "poll", .errmsg = true, .timeout = true, },
752 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300753 { .name = "pread", .errmsg = true, .alias = "pread64",
754 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
755 { .name = "preadv", .errmsg = true, .alias = "pread",
756 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300757 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300758 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
759 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
760 { .name = "pwritev", .errmsg = true,
761 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
762 { .name = "read", .errmsg = true,
763 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
764 { .name = "readlinkat", .errmsg = true,
765 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
766 { .name = "readv", .errmsg = true,
767 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300768 { .name = "recvfrom", .errmsg = true,
769 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
770 { .name = "recvmmsg", .errmsg = true,
771 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
772 { .name = "recvmsg", .errmsg = true,
773 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300774 { .name = "renameat", .errmsg = true,
775 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300776 { .name = "rt_sigaction", .errmsg = true,
777 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300778 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300779 { .name = "rt_sigqueueinfo", .errmsg = true,
780 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
781 { .name = "rt_tgsigqueueinfo", .errmsg = true,
782 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300783 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300784 { .name = "sendmmsg", .errmsg = true,
785 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
786 { .name = "sendmsg", .errmsg = true,
787 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
788 { .name = "sendto", .errmsg = true,
789 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300790 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
791 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300792 { .name = "shutdown", .errmsg = true,
793 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300794 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300795 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
796 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300797 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300798 { .name = "socketpair", .errmsg = true,
799 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
800 [1] = SCA_SK_TYPE, /* type */ },
801 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300802 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300803 { .name = "symlinkat", .errmsg = true,
804 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300805 { .name = "tgkill", .errmsg = true,
806 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
807 { .name = "tkill", .errmsg = true,
808 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300809 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300810 { .name = "unlinkat", .errmsg = true,
811 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
812 { .name = "utimensat", .errmsg = true,
813 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
814 { .name = "write", .errmsg = true,
815 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
816 { .name = "writev", .errmsg = true,
817 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300818};
819
820static int syscall_fmt__cmp(const void *name, const void *fmtp)
821{
822 const struct syscall_fmt *fmt = fmtp;
823 return strcmp(name, fmt->name);
824}
825
826static struct syscall_fmt *syscall_fmt__find(const char *name)
827{
828 const int nmemb = ARRAY_SIZE(syscall_fmts);
829 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
830}
831
832struct syscall {
833 struct event_format *tp_format;
834 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300835 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300836 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300837 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300838 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300839};
840
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200841static size_t fprintf_duration(unsigned long t, FILE *fp)
842{
843 double duration = (double)t / NSEC_PER_MSEC;
844 size_t printed = fprintf(fp, "(");
845
846 if (duration >= 1.0)
847 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
848 else if (duration >= 0.01)
849 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
850 else
851 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300852 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200853}
854
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300855struct thread_trace {
856 u64 entry_time;
857 u64 exit_time;
858 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300859 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300860 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300861 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300862 struct {
863 int max;
864 char **table;
865 } paths;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300866};
867
868static struct thread_trace *thread_trace__new(void)
869{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300870 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
871
872 if (ttrace)
873 ttrace->paths.max = -1;
874
875 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300876}
877
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300878static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300879{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300880 struct thread_trace *ttrace;
881
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300882 if (thread == NULL)
883 goto fail;
884
885 if (thread->priv == NULL)
886 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300887
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300888 if (thread->priv == NULL)
889 goto fail;
890
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300891 ttrace = thread->priv;
892 ++ttrace->nr_events;
893
894 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300895fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300896 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300897 "WARNING: not enough memory, dropping samples!\n");
898 return NULL;
899}
900
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300901struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300902 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300903 int audit_machine;
904 struct {
905 int max;
906 struct syscall *table;
907 } syscalls;
908 struct perf_record_opts opts;
David Ahern8fb598e2013-09-28 13:13:00 -0600909 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300910 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600911 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300912 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300913 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300914 struct strlist *ev_qualifier;
915 bool not_ev_qualifier;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300916 bool live;
David Ahernbdc89662013-08-28 22:29:53 -0600917 struct intlist *tid_list;
918 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300919 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300920 bool multiple_threads;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300921 bool show_comm;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300922 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300923 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300924};
925
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300926static int thread__read_fd_path(struct thread *thread, int fd)
927{
928 struct thread_trace *ttrace = thread->priv;
929 char linkname[PATH_MAX], pathname[PATH_MAX];
930 struct stat st;
931 int ret;
932
933 if (thread->pid_ == thread->tid) {
934 scnprintf(linkname, sizeof(linkname),
935 "/proc/%d/fd/%d", thread->pid_, fd);
936 } else {
937 scnprintf(linkname, sizeof(linkname),
938 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
939 }
940
941 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
942 return -1;
943
944 ret = readlink(linkname, pathname, sizeof(pathname));
945
946 if (ret < 0 || ret > st.st_size)
947 return -1;
948
949 pathname[ret] = '\0';
950
951 if (fd > ttrace->paths.max) {
952 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
953
954 if (npath == NULL)
955 return -1;
956
957 if (ttrace->paths.max != -1) {
958 memset(npath + ttrace->paths.max + 1, 0,
959 (fd - ttrace->paths.max) * sizeof(char *));
960 } else {
961 memset(npath, 0, (fd + 1) * sizeof(char *));
962 }
963
964 ttrace->paths.table = npath;
965 ttrace->paths.max = fd;
966 }
967
968 ttrace->paths.table[fd] = strdup(pathname);
969
970 return ttrace->paths.table[fd] != NULL ? 0 : -1;
971}
972
973static const char *thread__fd_path(struct thread *thread, int fd, bool live)
974{
975 struct thread_trace *ttrace = thread->priv;
976
977 if (ttrace == NULL)
978 return NULL;
979
980 if (fd < 0)
981 return NULL;
982
983 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL) &&
984 (!live || thread__read_fd_path(thread, fd)))
985 return NULL;
986
987 return ttrace->paths.table[fd];
988}
989
990static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
991 struct syscall_arg *arg)
992{
993 int fd = arg->val;
994 size_t printed = scnprintf(bf, size, "%d", fd);
995 const char *path = thread__fd_path(arg->thread, fd, arg->trace->live);
996
997 if (path)
998 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
999
1000 return printed;
1001}
1002
1003static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1004 struct syscall_arg *arg)
1005{
1006 int fd = arg->val;
1007 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1008 struct thread_trace *ttrace = arg->thread->priv;
1009
1010 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
1011 free(ttrace->paths.table[fd]);
1012 ttrace->paths.table[fd] = NULL;
1013 }
1014
1015 return printed;
1016}
1017
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001018static bool trace__filter_duration(struct trace *trace, double t)
1019{
1020 return t < (trace->duration_filter * NSEC_PER_MSEC);
1021}
1022
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001023static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1024{
1025 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1026
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001027 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001028}
1029
Namhyung Kimf15eb532012-10-05 14:02:16 +09001030static bool done = false;
1031
1032static void sig_handler(int sig __maybe_unused)
1033{
1034 done = true;
1035}
1036
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001037static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001038 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001039{
1040 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001041 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001042
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001043 if (trace->multiple_threads) {
1044 if (trace->show_comm)
1045 printed += fprintf(fp, "%.14s/", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001046 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001047 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001048
1049 return printed;
1050}
1051
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001052static int trace__process_event(struct trace *trace, struct machine *machine,
1053 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001054{
1055 int ret = 0;
1056
1057 switch (event->header.type) {
1058 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001059 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001060 "LOST %" PRIu64 " events!\n", event->lost.lost);
1061 ret = machine__process_lost_event(machine, event);
1062 default:
1063 ret = machine__process_event(machine, event);
1064 break;
1065 }
1066
1067 return ret;
1068}
1069
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001070static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001071 union perf_event *event,
1072 struct perf_sample *sample __maybe_unused,
1073 struct machine *machine)
1074{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001075 struct trace *trace = container_of(tool, struct trace, tool);
1076 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001077}
1078
1079static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1080{
1081 int err = symbol__init();
1082
1083 if (err)
1084 return err;
1085
David Ahern8fb598e2013-09-28 13:13:00 -06001086 trace->host = machine__new_host();
1087 if (trace->host == NULL)
1088 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001089
1090 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001091 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001092 trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001093 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001094 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001095 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001096 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001097 }
1098
1099 if (err)
1100 symbol__exit();
1101
1102 return err;
1103}
1104
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001105static int syscall__set_arg_fmts(struct syscall *sc)
1106{
1107 struct format_field *field;
1108 int idx = 0;
1109
1110 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1111 if (sc->arg_scnprintf == NULL)
1112 return -1;
1113
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001114 if (sc->fmt)
1115 sc->arg_parm = sc->fmt->arg_parm;
1116
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001117 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001118 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1119 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1120 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001121 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1122 ++idx;
1123 }
1124
1125 return 0;
1126}
1127
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001128static int trace__read_syscall_info(struct trace *trace, int id)
1129{
1130 char tp_name[128];
1131 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001132 const char *name = audit_syscall_to_name(id, trace->audit_machine);
1133
1134 if (name == NULL)
1135 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001136
1137 if (id > trace->syscalls.max) {
1138 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1139
1140 if (nsyscalls == NULL)
1141 return -1;
1142
1143 if (trace->syscalls.max != -1) {
1144 memset(nsyscalls + trace->syscalls.max + 1, 0,
1145 (id - trace->syscalls.max) * sizeof(*sc));
1146 } else {
1147 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1148 }
1149
1150 trace->syscalls.table = nsyscalls;
1151 trace->syscalls.max = id;
1152 }
1153
1154 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001155 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001156
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001157 if (trace->ev_qualifier) {
1158 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1159
1160 if (!(in ^ trace->not_ev_qualifier)) {
1161 sc->filtered = true;
1162 /*
1163 * No need to do read tracepoint information since this will be
1164 * filtered out.
1165 */
1166 return 0;
1167 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001168 }
1169
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001170 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001171
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001172 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
1173 sc->tp_format = event_format__new("syscalls", tp_name);
1174
1175 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1176 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1177 sc->tp_format = event_format__new("syscalls", tp_name);
1178 }
1179
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001180 if (sc->tp_format == NULL)
1181 return -1;
1182
1183 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001184}
1185
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001186static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001187 unsigned long *args, struct trace *trace,
1188 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001189{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001190 size_t printed = 0;
1191
1192 if (sc->tp_format != NULL) {
1193 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001194 u8 bit = 1;
1195 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001196 .idx = 0,
1197 .mask = 0,
1198 .trace = trace,
1199 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001200 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001201
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001202 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001203 field = field->next, ++arg.idx, bit <<= 1) {
1204 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001205 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001206 /*
1207 * Suppress this argument if its value is zero and
1208 * and we don't have a string associated in an
1209 * strarray for it.
1210 */
1211 if (args[arg.idx] == 0 &&
1212 !(sc->arg_scnprintf &&
1213 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1214 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001215 continue;
1216
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001217 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001218 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001219 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1220 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001221 if (sc->arg_parm)
1222 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001223 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1224 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001225 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001226 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001227 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001228 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001229 }
1230 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001231 int i = 0;
1232
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001233 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001234 printed += scnprintf(bf + printed, size - printed,
1235 "%sarg%d: %ld",
1236 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001237 ++i;
1238 }
1239 }
1240
1241 return printed;
1242}
1243
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001244typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1245 struct perf_sample *sample);
1246
1247static struct syscall *trace__syscall_info(struct trace *trace,
1248 struct perf_evsel *evsel,
1249 struct perf_sample *sample)
1250{
1251 int id = perf_evsel__intval(evsel, sample, "id");
1252
1253 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001254
1255 /*
1256 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1257 * before that, leaving at a higher verbosity level till that is
1258 * explained. Reproduced with plain ftrace with:
1259 *
1260 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1261 * grep "NR -1 " /t/trace_pipe
1262 *
1263 * After generating some load on the machine.
1264 */
1265 if (verbose > 1) {
1266 static u64 n;
1267 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1268 id, perf_evsel__name(evsel), ++n);
1269 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001270 return NULL;
1271 }
1272
1273 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1274 trace__read_syscall_info(trace, id))
1275 goto out_cant_read;
1276
1277 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1278 goto out_cant_read;
1279
1280 return &trace->syscalls.table[id];
1281
1282out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001283 if (verbose) {
1284 fprintf(trace->output, "Problems reading syscall %d", id);
1285 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1286 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1287 fputs(" information\n", trace->output);
1288 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001289 return NULL;
1290}
1291
1292static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1293 struct perf_sample *sample)
1294{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001295 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001296 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001297 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001298 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001299 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001300 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001301
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001302 if (sc == NULL)
1303 return -1;
1304
1305 if (sc->filtered)
1306 return 0;
1307
David Ahern8fb598e2013-09-28 13:13:00 -06001308 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001309 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001310 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001311 return -1;
1312
1313 args = perf_evsel__rawptr(evsel, sample, "args");
1314 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001315 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001316 return -1;
1317 }
1318
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001319 ttrace = thread->priv;
1320
1321 if (ttrace->entry_str == NULL) {
1322 ttrace->entry_str = malloc(1024);
1323 if (!ttrace->entry_str)
1324 return -1;
1325 }
1326
1327 ttrace->entry_time = sample->time;
1328 msg = ttrace->entry_str;
1329 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1330
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001331 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1332 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001333
1334 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001335 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001336 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1337 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001338 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001339 } else
1340 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001341
1342 return 0;
1343}
1344
1345static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1346 struct perf_sample *sample)
1347{
1348 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001349 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001350 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001351 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001352 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001353
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001354 if (sc == NULL)
1355 return -1;
1356
1357 if (sc->filtered)
1358 return 0;
1359
David Ahern8fb598e2013-09-28 13:13:00 -06001360 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001361 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001362 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001363 return -1;
1364
1365 ret = perf_evsel__intval(evsel, sample, "ret");
1366
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001367 ttrace = thread->priv;
1368
1369 ttrace->exit_time = sample->time;
1370
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001371 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001372 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001373 if (trace__filter_duration(trace, duration))
1374 goto out;
1375 } else if (trace->duration_filter)
1376 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001377
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001378 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001379
1380 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001381 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001382 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001383 fprintf(trace->output, " ... [");
1384 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1385 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001386 }
1387
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001388 if (sc->fmt == NULL) {
1389signed_print:
1390 fprintf(trace->output, ") = %d", ret);
1391 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001392 char bf[256];
1393 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1394 *e = audit_errno_to_name(-ret);
1395
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001396 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001397 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001398 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001399 else if (sc->fmt->hexret)
1400 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001401 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001402 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001403
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001404 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001405out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001406 ttrace->entry_pending = false;
1407
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001408 return 0;
1409}
1410
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001411static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1412 struct perf_sample *sample)
1413{
1414 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1415 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001416 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001417 sample->pid,
1418 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001419 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001420
1421 if (ttrace == NULL)
1422 goto out_dump;
1423
1424 ttrace->runtime_ms += runtime_ms;
1425 trace->runtime_ms += runtime_ms;
1426 return 0;
1427
1428out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001429 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001430 evsel->name,
1431 perf_evsel__strval(evsel, sample, "comm"),
1432 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1433 runtime,
1434 perf_evsel__intval(evsel, sample, "vruntime"));
1435 return 0;
1436}
1437
David Ahernbdc89662013-08-28 22:29:53 -06001438static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1439{
1440 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1441 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1442 return false;
1443
1444 if (trace->pid_list || trace->tid_list)
1445 return true;
1446
1447 return false;
1448}
1449
David Ahern6810fc92013-08-28 22:29:52 -06001450static int trace__process_sample(struct perf_tool *tool,
1451 union perf_event *event __maybe_unused,
1452 struct perf_sample *sample,
1453 struct perf_evsel *evsel,
1454 struct machine *machine __maybe_unused)
1455{
1456 struct trace *trace = container_of(tool, struct trace, tool);
1457 int err = 0;
1458
1459 tracepoint_handler handler = evsel->handler.func;
1460
David Ahernbdc89662013-08-28 22:29:53 -06001461 if (skip_sample(trace, sample))
1462 return 0;
1463
David Ahern4bb09192013-09-04 12:37:43 -06001464 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001465 trace->base_time = sample->time;
1466
1467 if (handler)
1468 handler(trace, evsel, sample);
1469
1470 return err;
1471}
1472
1473static bool
1474perf_session__has_tp(struct perf_session *session, const char *name)
1475{
1476 struct perf_evsel *evsel;
1477
1478 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1479
1480 return evsel != NULL;
1481}
1482
David Ahernbdc89662013-08-28 22:29:53 -06001483static int parse_target_str(struct trace *trace)
1484{
1485 if (trace->opts.target.pid) {
1486 trace->pid_list = intlist__new(trace->opts.target.pid);
1487 if (trace->pid_list == NULL) {
1488 pr_err("Error parsing process id string\n");
1489 return -EINVAL;
1490 }
1491 }
1492
1493 if (trace->opts.target.tid) {
1494 trace->tid_list = intlist__new(trace->opts.target.tid);
1495 if (trace->tid_list == NULL) {
1496 pr_err("Error parsing thread id string\n");
1497 return -EINVAL;
1498 }
1499 }
1500
1501 return 0;
1502}
1503
David Ahern5e2485b2013-09-28 13:13:01 -06001504static int trace__record(int argc, const char **argv)
1505{
1506 unsigned int rec_argc, i, j;
1507 const char **rec_argv;
1508 const char * const record_args[] = {
1509 "record",
1510 "-R",
1511 "-m", "1024",
1512 "-c", "1",
1513 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
1514 };
1515
1516 rec_argc = ARRAY_SIZE(record_args) + argc;
1517 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1518
1519 if (rec_argv == NULL)
1520 return -ENOMEM;
1521
1522 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1523 rec_argv[i] = record_args[i];
1524
1525 for (j = 0; j < (unsigned int)argc; j++, i++)
1526 rec_argv[i] = argv[j];
1527
1528 return cmd_record(i, rec_argv, NULL);
1529}
1530
Namhyung Kimf15eb532012-10-05 14:02:16 +09001531static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001532{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001533 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001534 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001535 int err = -1, i;
1536 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001537 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001538
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001539 trace->live = true;
1540
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001541 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001542 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001543 goto out;
1544 }
1545
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001546 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1547 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001548 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001549 goto out_delete_evlist;
1550 }
1551
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001552 if (trace->sched &&
1553 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1554 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001555 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001556 goto out_delete_evlist;
1557 }
1558
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001559 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1560 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001561 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001562 goto out_delete_evlist;
1563 }
1564
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001565 err = trace__symbols_init(trace, evlist);
1566 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001567 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001568 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001569 }
1570
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001571 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001572
Namhyung Kimf15eb532012-10-05 14:02:16 +09001573 signal(SIGCHLD, sig_handler);
1574 signal(SIGINT, sig_handler);
1575
1576 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001577 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001578 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001579 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001580 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001581 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001582 }
1583 }
1584
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001585 err = perf_evlist__open(evlist);
1586 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001587 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001588 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001589 }
1590
1591 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1592 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001593 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001594 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001595 }
1596
1597 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001598
1599 if (forks)
1600 perf_evlist__start_workload(evlist);
1601
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001602 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001603again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001604 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001605
1606 for (i = 0; i < evlist->nr_mmaps; i++) {
1607 union perf_event *event;
1608
1609 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1610 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001611 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001612 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001613
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001614 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001615
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001616 err = perf_evlist__parse_sample(evlist, event, &sample);
1617 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001618 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001619 continue;
1620 }
1621
David Ahern4bb09192013-09-04 12:37:43 -06001622 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001623 trace->base_time = sample.time;
1624
1625 if (type != PERF_RECORD_SAMPLE) {
David Ahern8fb598e2013-09-28 13:13:00 -06001626 trace__process_event(trace, trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001627 continue;
1628 }
1629
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001630 evsel = perf_evlist__id2evsel(evlist, sample.id);
1631 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001632 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001633 continue;
1634 }
1635
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001636 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001637 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 -03001638 perf_evsel__name(evsel), sample.tid,
1639 sample.cpu, sample.raw_size);
1640 continue;
1641 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001642
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001643 handler = evsel->handler.func;
1644 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001645
1646 if (done)
1647 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001648 }
1649 }
1650
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001651 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001652 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001653 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001654
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001655 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001656 }
1657
1658 if (done)
1659 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001660
1661 goto again;
1662
Namhyung Kim3beb0862013-03-15 14:48:50 +09001663out_unmap_evlist:
1664 perf_evlist__munmap(evlist);
1665out_close_evlist:
1666 perf_evlist__close(evlist);
1667out_delete_maps:
1668 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001669out_delete_evlist:
1670 perf_evlist__delete(evlist);
1671out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001672 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001673 return err;
1674}
1675
David Ahern6810fc92013-08-28 22:29:52 -06001676static int trace__replay(struct trace *trace)
1677{
1678 const struct perf_evsel_str_handler handlers[] = {
1679 { "raw_syscalls:sys_enter", trace__sys_enter, },
1680 { "raw_syscalls:sys_exit", trace__sys_exit, },
1681 };
1682
1683 struct perf_session *session;
1684 int err = -1;
1685
1686 trace->tool.sample = trace__process_sample;
1687 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001688 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001689 trace->tool.comm = perf_event__process_comm;
1690 trace->tool.exit = perf_event__process_exit;
1691 trace->tool.fork = perf_event__process_fork;
1692 trace->tool.attr = perf_event__process_attr;
1693 trace->tool.tracing_data = perf_event__process_tracing_data;
1694 trace->tool.build_id = perf_event__process_build_id;
1695
1696 trace->tool.ordered_samples = true;
1697 trace->tool.ordering_requires_timestamps = true;
1698
1699 /* add tid to output */
1700 trace->multiple_threads = true;
1701
1702 if (symbol__init() < 0)
1703 return -1;
1704
1705 session = perf_session__new(input_name, O_RDONLY, 0, false,
1706 &trace->tool);
1707 if (session == NULL)
1708 return -ENOMEM;
1709
David Ahern8fb598e2013-09-28 13:13:00 -06001710 trace->host = &session->machines.host;
1711
David Ahern6810fc92013-08-28 22:29:52 -06001712 err = perf_session__set_tracepoints_handlers(session, handlers);
1713 if (err)
1714 goto out;
1715
1716 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1717 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1718 goto out;
1719 }
1720
1721 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1722 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1723 goto out;
1724 }
1725
David Ahernbdc89662013-08-28 22:29:53 -06001726 err = parse_target_str(trace);
1727 if (err != 0)
1728 goto out;
1729
David Ahern6810fc92013-08-28 22:29:52 -06001730 setup_pager();
1731
1732 err = perf_session__process_events(session, &trace->tool);
1733 if (err)
1734 pr_err("Failed to process events, error %d", err);
1735
1736out:
1737 perf_session__delete(session);
1738
1739 return err;
1740}
1741
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001742static size_t trace__fprintf_threads_header(FILE *fp)
1743{
1744 size_t printed;
1745
1746 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1747 printed += fprintf(fp," __) Summary of events (__\n\n");
1748 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1749 printed += fprintf(fp," _____________________________________________________________________\n\n");
1750
1751 return printed;
1752}
1753
1754static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1755{
1756 size_t printed = trace__fprintf_threads_header(fp);
1757 struct rb_node *nd;
1758
David Ahern8fb598e2013-09-28 13:13:00 -06001759 for (nd = rb_first(&trace->host->threads); nd; nd = rb_next(nd)) {
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001760 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1761 struct thread_trace *ttrace = thread->priv;
1762 const char *color;
1763 double ratio;
1764
1765 if (ttrace == NULL)
1766 continue;
1767
1768 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1769
1770 color = PERF_COLOR_NORMAL;
1771 if (ratio > 50.0)
1772 color = PERF_COLOR_RED;
1773 else if (ratio > 25.0)
1774 color = PERF_COLOR_GREEN;
1775 else if (ratio > 5.0)
1776 color = PERF_COLOR_YELLOW;
1777
1778 printed += color_fprintf(fp, color, "%20s", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001779 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001780 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1781 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1782 }
1783
1784 return printed;
1785}
1786
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001787static int trace__set_duration(const struct option *opt, const char *str,
1788 int unset __maybe_unused)
1789{
1790 struct trace *trace = opt->value;
1791
1792 trace->duration_filter = atof(str);
1793 return 0;
1794}
1795
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001796static int trace__open_output(struct trace *trace, const char *filename)
1797{
1798 struct stat st;
1799
1800 if (!stat(filename, &st) && st.st_size) {
1801 char oldname[PATH_MAX];
1802
1803 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1804 unlink(oldname);
1805 rename(filename, oldname);
1806 }
1807
1808 trace->output = fopen(filename, "w");
1809
1810 return trace->output == NULL ? -errno : 0;
1811}
1812
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001813int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1814{
1815 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001816 "perf trace [<options>] [<command>]",
1817 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06001818 "perf trace record [<options>] [<command>]",
1819 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001820 NULL
1821 };
1822 struct trace trace = {
1823 .audit_machine = audit_detect_machine(),
1824 .syscalls = {
1825 . max = -1,
1826 },
1827 .opts = {
1828 .target = {
1829 .uid = UINT_MAX,
1830 .uses_mmap = true,
1831 },
1832 .user_freq = UINT_MAX,
1833 .user_interval = ULLONG_MAX,
1834 .no_delay = true,
1835 .mmap_pages = 1024,
1836 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001837 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001838 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001839 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001840 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001841 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001842 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001843 OPT_BOOLEAN(0, "comm", &trace.show_comm,
1844 "show the thread COMM next to its id"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001845 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1846 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001847 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001848 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001849 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1850 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001851 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001852 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001853 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001854 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001855 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001856 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001857 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001858 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02001859 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1860 "number of mmap data pages",
1861 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06001862 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001863 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001864 OPT_CALLBACK(0, "duration", &trace, "float",
1865 "show only events with duration > N.M ms",
1866 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001867 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001868 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06001869 OPT_BOOLEAN('T', "time", &trace.full_time,
1870 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001871 OPT_END()
1872 };
1873 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001874 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001875
David Ahern5e2485b2013-09-28 13:13:01 -06001876 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
1877 return trace__record(argc-2, &argv[2]);
1878
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001879 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001880
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001881 if (output_name != NULL) {
1882 err = trace__open_output(&trace, output_name);
1883 if (err < 0) {
1884 perror("failed to create output file");
1885 goto out;
1886 }
1887 }
1888
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001889 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001890 const char *s = ev_qualifier_str;
1891
1892 trace.not_ev_qualifier = *s == '!';
1893 if (trace.not_ev_qualifier)
1894 ++s;
1895 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001896 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001897 fputs("Not enough memory to parse event qualifier",
1898 trace.output);
1899 err = -ENOMEM;
1900 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001901 }
1902 }
1903
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001904 err = perf_target__validate(&trace.opts.target);
1905 if (err) {
1906 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001907 fprintf(trace.output, "%s", bf);
1908 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001909 }
1910
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001911 err = perf_target__parse_uid(&trace.opts.target);
1912 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001913 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001914 fprintf(trace.output, "%s", bf);
1915 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001916 }
1917
Namhyung Kimf15eb532012-10-05 14:02:16 +09001918 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001919 trace.opts.target.system_wide = true;
1920
David Ahern6810fc92013-08-28 22:29:52 -06001921 if (input_name)
1922 err = trace__replay(&trace);
1923 else
1924 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001925
1926 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001927 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001928
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001929out_close:
1930 if (output_name != NULL)
1931 fclose(trace.output);
1932out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001933 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001934}