]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/truss/syscalls.c
Update llvm to trunk r290819 and resolve conflicts.
[FreeBSD/FreeBSD.git] / usr.bin / truss / syscalls.c
1 /*
2  * Copyright 1997 Sean Eric Fagan
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. All advertising materials mentioning features or use of this software
13  *    must display the following acknowledgement:
14  *      This product includes software developed by Sean Eric Fagan
15  * 4. Neither the name of the author may be used to endorse or promote
16  *    products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 /*
36  * This file has routines used to print out system calls and their
37  * arguments.
38  */
39
40 #include <sys/types.h>
41 #include <sys/event.h>
42 #include <sys/ioccom.h>
43 #include <sys/mount.h>
44 #include <sys/ptrace.h>
45 #include <sys/resource.h>
46 #include <sys/socket.h>
47 #include <sys/stat.h>
48 #include <sys/un.h>
49 #include <sys/wait.h>
50 #include <machine/sysarch.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53
54 #include <assert.h>
55 #include <ctype.h>
56 #include <err.h>
57 #include <fcntl.h>
58 #include <poll.h>
59 #include <signal.h>
60 #include <stdbool.h>
61 #include <stdio.h>
62 #include <stdlib.h>
63 #include <string.h>
64 #include <sysdecode.h>
65 #include <unistd.h>
66 #include <vis.h>
67
68 #include <contrib/cloudabi/cloudabi_types_common.h>
69
70 #include "truss.h"
71 #include "extern.h"
72 #include "syscall.h"
73
74 /* 64-bit alignment on 32-bit platforms. */
75 #if !defined(__LP64__) && defined(__powerpc__)
76 #define QUAD_ALIGN      1
77 #else
78 #define QUAD_ALIGN      0
79 #endif
80
81 /* Number of slots needed for a 64-bit argument. */
82 #ifdef __LP64__
83 #define QUAD_SLOTS      1
84 #else
85 #define QUAD_SLOTS      2
86 #endif
87
88 /*
89  * This should probably be in its own file, sorted alphabetically.
90  */
91 static struct syscall decoded_syscalls[] = {
92         /* Native ABI */
93         { .name = "__getcwd", .ret_type = 1, .nargs = 2,
94           .args = { { Name | OUT, 0 }, { Int, 1 } } },
95         { .name = "_umtx_op", .ret_type = 1, .nargs = 5,
96           .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
97                     { Ptr, 4 } } },
98         { .name = "accept", .ret_type = 1, .nargs = 3,
99           .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
100         { .name = "access", .ret_type = 1, .nargs = 2,
101           .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
102         { .name = "bind", .ret_type = 1, .nargs = 3,
103           .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
104         { .name = "bindat", .ret_type = 1, .nargs = 4,
105           .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
106                     { Int, 3 } } },
107         { .name = "break", .ret_type = 1, .nargs = 1,
108           .args = { { Ptr, 0 } } },
109         { .name = "chdir", .ret_type = 1, .nargs = 1,
110           .args = { { Name, 0 } } },
111         { .name = "chflags", .ret_type = 1, .nargs = 2,
112           .args = { { Name | IN, 0 }, { Hex, 1 } } },
113         { .name = "chmod", .ret_type = 1, .nargs = 2,
114           .args = { { Name, 0 }, { Octal, 1 } } },
115         { .name = "chown", .ret_type = 1, .nargs = 3,
116           .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
117         { .name = "chroot", .ret_type = 1, .nargs = 1,
118           .args = { { Name, 0 } } },
119         { .name = "clock_gettime", .ret_type = 1, .nargs = 2,
120           .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
121         { .name = "close", .ret_type = 1, .nargs = 1,
122           .args = { { Int, 0 } } },
123         { .name = "connect", .ret_type = 1, .nargs = 3,
124           .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
125         { .name = "connectat", .ret_type = 1, .nargs = 4,
126           .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
127                     { Int, 3 } } },
128         { .name = "eaccess", .ret_type = 1, .nargs = 2,
129           .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
130         { .name = "execve", .ret_type = 1, .nargs = 3,
131           .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
132                     { ExecEnv | IN, 2 } } },
133         { .name = "exit", .ret_type = 0, .nargs = 1,
134           .args = { { Hex, 0 } } },
135         { .name = "faccessat", .ret_type = 1, .nargs = 4,
136           .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
137                     { Atflags, 3 } } },
138         { .name = "fchmod", .ret_type = 1, .nargs = 2,
139           .args = { { Int, 0 }, { Octal, 1 } } },
140         { .name = "fchmodat", .ret_type = 1, .nargs = 4,
141           .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
142         { .name = "fchown", .ret_type = 1, .nargs = 3,
143           .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
144         { .name = "fchownat", .ret_type = 1, .nargs = 5,
145           .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
146                     { Atflags, 4 } } },
147         { .name = "fcntl", .ret_type = 1, .nargs = 3,
148           .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
149         { .name = "fstat", .ret_type = 1, .nargs = 2,
150           .args = { { Int, 0 }, { Stat | OUT, 1 } } },
151         { .name = "fstatat", .ret_type = 1, .nargs = 4,
152           .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
153                     { Atflags, 3 } } },
154         { .name = "fstatfs", .ret_type = 1, .nargs = 2,
155           .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
156         { .name = "ftruncate", .ret_type = 1, .nargs = 2,
157           .args = { { Int | IN, 0 }, { QuadHex | IN, 1 + QUAD_ALIGN } } },
158         { .name = "futimens", .ret_type = 1, .nargs = 2,
159           .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
160         { .name = "futimes", .ret_type = 1, .nargs = 2,
161           .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
162         { .name = "futimesat", .ret_type = 1, .nargs = 3,
163           .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
164         { .name = "getitimer", .ret_type = 1, .nargs = 2,
165           .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
166         { .name = "getpeername", .ret_type = 1, .nargs = 3,
167           .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
168         { .name = "getpgid", .ret_type = 1, .nargs = 1,
169           .args = { { Int, 0 } } },
170         { .name = "getrlimit", .ret_type = 1, .nargs = 2,
171           .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
172         { .name = "getrusage", .ret_type = 1, .nargs = 2,
173           .args = { { Int, 0 }, { Rusage | OUT, 1 } } },
174         { .name = "getsid", .ret_type = 1, .nargs = 1,
175           .args = { { Int, 0 } } },
176         { .name = "getsockname", .ret_type = 1, .nargs = 3,
177           .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
178         { .name = "gettimeofday", .ret_type = 1, .nargs = 2,
179           .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
180         { .name = "ioctl", .ret_type = 1, .nargs = 3,
181           .args = { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 } } },
182         { .name = "kevent", .ret_type = 1, .nargs = 6,
183           .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
184                     { Int, 4 }, { Timespec, 5 } } },
185         { .name = "kill", .ret_type = 1, .nargs = 2,
186           .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
187         { .name = "kldfind", .ret_type = 1, .nargs = 1,
188           .args = { { Name | IN, 0 } } },
189         { .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
190           .args = { { Int, 0 } } },
191         { .name = "kldload", .ret_type = 1, .nargs = 1,
192           .args = { { Name | IN, 0 } } },
193         { .name = "kldnext", .ret_type = 1, .nargs = 1,
194           .args = { { Int, 0 } } },
195         { .name = "kldstat", .ret_type = 1, .nargs = 2,
196           .args = { { Int, 0 }, { Ptr, 1 } } },
197         { .name = "kldunload", .ret_type = 1, .nargs = 1,
198           .args = { { Int, 0 } } },
199         { .name = "kse_release", .ret_type = 0, .nargs = 1,
200           .args = { { Timespec, 0 } } },
201         { .name = "lchflags", .ret_type = 1, .nargs = 2,
202           .args = { { Name | IN, 0 }, { Hex, 1 } } },
203         { .name = "lchmod", .ret_type = 1, .nargs = 2,
204           .args = { { Name, 0 }, { Octal, 1 } } },
205         { .name = "lchown", .ret_type = 1, .nargs = 3,
206           .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
207         { .name = "link", .ret_type = 1, .nargs = 2,
208           .args = { { Name, 0 }, { Name, 1 } } },
209         { .name = "linkat", .ret_type = 1, .nargs = 5,
210           .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
211                     { Atflags, 4 } } },
212         { .name = "lseek", .ret_type = 2, .nargs = 3,
213           .args = { { Int, 0 }, { QuadHex, 1 + QUAD_ALIGN },
214                     { Whence, 1 + QUAD_SLOTS + QUAD_ALIGN } } },
215         { .name = "lstat", .ret_type = 1, .nargs = 2,
216           .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
217         { .name = "lutimes", .ret_type = 1, .nargs = 2,
218           .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
219         { .name = "mkdir", .ret_type = 1, .nargs = 2,
220           .args = { { Name, 0 }, { Octal, 1 } } },
221         { .name = "mkdirat", .ret_type = 1, .nargs = 3,
222           .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
223         { .name = "mkfifo", .ret_type = 1, .nargs = 2,
224           .args = { { Name, 0 }, { Octal, 1 } } },
225         { .name = "mkfifoat", .ret_type = 1, .nargs = 3,
226           .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
227         { .name = "mknod", .ret_type = 1, .nargs = 3,
228           .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
229         { .name = "mknodat", .ret_type = 1, .nargs = 4,
230           .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
231         { .name = "mmap", .ret_type = 1, .nargs = 6,
232           .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
233                     { Int, 4 }, { QuadHex, 5 + QUAD_ALIGN } } },
234         { .name = "modfind", .ret_type = 1, .nargs = 1,
235           .args = { { Name | IN, 0 } } },
236         { .name = "mount", .ret_type = 1, .nargs = 4,
237           .args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } },
238         { .name = "mprotect", .ret_type = 1, .nargs = 3,
239           .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 } } },
240         { .name = "munmap", .ret_type = 1, .nargs = 2,
241           .args = { { Ptr, 0 }, { Int, 1 } } },
242         { .name = "nanosleep", .ret_type = 1, .nargs = 1,
243           .args = { { Timespec, 0 } } },
244         { .name = "open", .ret_type = 1, .nargs = 3,
245           .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
246         { .name = "openat", .ret_type = 1, .nargs = 4,
247           .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
248                     { Octal, 3 } } },
249         { .name = "pathconf", .ret_type = 1, .nargs = 2,
250           .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
251         { .name = "pipe", .ret_type = 1, .nargs = 1,
252           .args = { { PipeFds | OUT, 0 } } },
253         { .name = "pipe2", .ret_type = 1, .nargs = 2,
254           .args = { { Ptr, 0 }, { Pipe2, 1 } } },
255         { .name = "poll", .ret_type = 1, .nargs = 3,
256           .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
257         { .name = "posix_openpt", .ret_type = 1, .nargs = 1,
258           .args = { { Open, 0 } } },
259         { .name = "procctl", .ret_type = 1, .nargs = 4,
260           .args = { { Idtype, 0 }, { Quad, 1 + QUAD_ALIGN },
261                     { Procctl, 1 + QUAD_ALIGN + QUAD_SLOTS },
262                     { Ptr, 2 + QUAD_ALIGN + QUAD_SLOTS } } },
263         { .name = "read", .ret_type = 1, .nargs = 3,
264           .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 } } },
265         { .name = "readlink", .ret_type = 1, .nargs = 3,
266           .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Int, 2 } } },
267         { .name = "readlinkat", .ret_type = 1, .nargs = 4,
268           .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
269                     { Int, 3 } } },
270         { .name = "recvfrom", .ret_type = 1, .nargs = 6,
271           .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Hex, 3 },
272                     { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } },
273         { .name = "rename", .ret_type = 1, .nargs = 2,
274           .args = { { Name, 0 }, { Name, 1 } } },
275         { .name = "renameat", .ret_type = 1, .nargs = 4,
276           .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
277         { .name = "rfork", .ret_type = 1, .nargs = 1,
278           .args = { { Rforkflags, 0 } } },
279         { .name = "rmdir", .ret_type = 1, .nargs = 1,
280           .args = { { Name, 0 } } },
281         { .name = "select", .ret_type = 1, .nargs = 5,
282           .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
283                     { Timeval, 4 } } },
284         { .name = "sendto", .ret_type = 1, .nargs = 6,
285           .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Hex, 3 },
286                     { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } },
287         { .name = "setitimer", .ret_type = 1, .nargs = 3,
288           .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
289         { .name = "setrlimit", .ret_type = 1, .nargs = 2,
290           .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
291         { .name = "shutdown", .ret_type = 1, .nargs = 2,
292           .args = { { Int, 0 }, { Shutdown, 1 } } },
293         { .name = "sigaction", .ret_type = 1, .nargs = 3,
294           .args = { { Signal, 0 }, { Sigaction | IN, 1 },
295                     { Sigaction | OUT, 2 } } },
296         { .name = "sigpending", .ret_type = 1, .nargs = 1,
297           .args = { { Sigset | OUT, 0 } } },
298         { .name = "sigprocmask", .ret_type = 1, .nargs = 3,
299           .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
300         { .name = "sigqueue", .ret_type = 1, .nargs = 3,
301           .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
302         { .name = "sigreturn", .ret_type = 1, .nargs = 1,
303           .args = { { Ptr, 0 } } },
304         { .name = "sigsuspend", .ret_type = 1, .nargs = 1,
305           .args = { { Sigset | IN, 0 } } },
306         { .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
307           .args = { { Sigset | IN, 0 }, { Ptr, 1 }, { Timespec | IN, 2 } } },
308         { .name = "sigwait", .ret_type = 1, .nargs = 2,
309           .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
310         { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
311           .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
312         { .name = "socket", .ret_type = 1, .nargs = 3,
313           .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Int, 2 } } },
314         { .name = "stat", .ret_type = 1, .nargs = 2,
315           .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
316         { .name = "statfs", .ret_type = 1, .nargs = 2,
317           .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } },
318         { .name = "symlink", .ret_type = 1, .nargs = 2,
319           .args = { { Name, 0 }, { Name, 1 } } },
320         { .name = "symlinkat", .ret_type = 1, .nargs = 3,
321           .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } },
322         { .name = "sysarch", .ret_type = 1, .nargs = 2,
323           .args = { { Sysarch, 0 }, { Ptr, 1 } } },
324         { .name = "thr_kill", .ret_type = 1, .nargs = 2,
325           .args = { { Long, 0 }, { Signal, 1 } } },
326         { .name = "thr_self", .ret_type = 1, .nargs = 1,
327           .args = { { Ptr, 0 } } },
328         { .name = "truncate", .ret_type = 1, .nargs = 2,
329           .args = { { Name | IN, 0 }, { QuadHex | IN, 1 + QUAD_ALIGN } } },
330 #if 0
331         /* Does not exist */
332         { .name = "umount", .ret_type = 1, .nargs = 2,
333           .args = { { Name, 0 }, { Int, 2 } } },
334 #endif
335         { .name = "unlink", .ret_type = 1, .nargs = 1,
336           .args = { { Name, 0 } } },
337         { .name = "unlinkat", .ret_type = 1, .nargs = 3,
338           .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
339         { .name = "unmount", .ret_type = 1, .nargs = 2,
340           .args = { { Name, 0 }, { Int, 1 } } },
341         { .name = "utimensat", .ret_type = 1, .nargs = 4,
342           .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
343                     { Atflags, 3 } } },
344         { .name = "utimes", .ret_type = 1, .nargs = 2,
345           .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
346         { .name = "utrace", .ret_type = 1, .nargs = 1,
347           .args = { { Utrace, 0 } } },
348         { .name = "wait4", .ret_type = 1, .nargs = 4,
349           .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
350                     { Rusage | OUT, 3 } } },
351         { .name = "wait6", .ret_type = 1, .nargs = 6,
352           .args = { { Idtype, 0 }, { Quad, 1 + QUAD_ALIGN },
353                     { ExitStatus | OUT, 1 + QUAD_ALIGN + QUAD_SLOTS },
354                     { Waitoptions, 2 + QUAD_ALIGN + QUAD_SLOTS },
355                     { Rusage | OUT, 3 + QUAD_ALIGN + QUAD_SLOTS },
356                     { Ptr, 4 + QUAD_ALIGN + QUAD_SLOTS } } },
357         { .name = "write", .ret_type = 1, .nargs = 3,
358           .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 } } },
359
360         /* Linux ABI */
361         { .name = "linux_access", .ret_type = 1, .nargs = 2,
362           .args = { { Name, 0 }, { Accessmode, 1 } } },
363         { .name = "linux_execve", .ret_type = 1, .nargs = 3,
364           .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
365                     { ExecEnv | IN, 2 } } },
366         { .name = "linux_lseek", .ret_type = 2, .nargs = 3,
367           .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
368         { .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
369           .args = { { Name | IN, 0 }, { Int, 1 } } },
370         { .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
371           .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
372         { .name = "linux_newstat", .ret_type = 1, .nargs = 2,
373           .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
374         { .name = "linux_open", .ret_type = 1, .nargs = 3,
375           .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
376         { .name = "linux_readlink", .ret_type = 1, .nargs = 3,
377           .args = { { Name, 0 }, { Name | OUT, 1 }, { Int, 2 } } },
378         { .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
379           .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
380         { .name = "linux_stat64", .ret_type = 1, .nargs = 3,
381           .args = { { Name | IN, 0 }, { Ptr | OUT, 1 }, { Ptr | IN, 1 } } },
382
383         /* CloudABI system calls. */
384         { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
385           .args = { { CloudABIClockID, 0 } } },
386         { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
387           .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
388         { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
389           .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
390         { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
391           .args = { { Int, 0 } } },
392         { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
393           .args = { { CloudABIFileType, 0 } } },
394         { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
395           .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
396         { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
397           .args = { { Int, 0 } } },
398         { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
399           .args = { { Int, 0 } } },
400         { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
401           .args = { { Int, 0 }, { Int, 1 } } },
402         { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
403           .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
404         { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
405           .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
406         { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
407           .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
408                     { ClouduABIFDSFlags, 2 } } },
409         { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
410           .args = { { Int, 0 } } },
411         { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
412           .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
413                     { CloudABIAdvice, 3 } } },
414         { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
415           .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
416         { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
417           .args = { { Int, 0 }, { BinString | IN, 1 },
418                     { CloudABIFileType, 3 } } },
419         { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
420           .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
421                     { Int, 3 }, { BinString | IN, 4 } } },
422         { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
423           .args = { { Int, 0 }, { BinString | IN, 1 },
424                     { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
425         { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
426           .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
427                     { Int, 3 } } },
428         { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
429           .args = { { Int, 0 }, { BinString | IN, 1 },
430                     { BinString | OUT, 3 }, { Int, 4 } } },
431         { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
432           .args = { { Int, 0 }, { BinString | IN, 1 },
433                     { Int, 3 }, { BinString | IN, 4 } } },
434         { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
435           .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
436         { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
437           .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
438                     { CloudABIFSFlags, 2 } } },
439         { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
440           .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
441                     { CloudABIFileStat | OUT, 3 } } },
442         { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
443           .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
444                     { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
445         { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
446           .args = { { BinString | IN, 0 },
447                     { Int, 2 }, { BinString | IN, 3 } } },
448         { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
449           .args = { { Int, 0 }, { BinString | IN, 1 },
450                     { CloudABIULFlags, 3 } } },
451         { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
452           .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
453         { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
454           .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
455         { .name = "cloudabi_sys_mem_lock", .ret_type = 1, .nargs = 2,
456           .args = { { Ptr, 0 }, { Int, 1 } } },
457         { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
458           .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
459                     { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
460         { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
461           .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
462         { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
463           .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
464         { .name = "cloudabi_sys_mem_unlock", .ret_type = 1, .nargs = 2,
465           .args = { { Ptr, 0 }, { Int, 1 } } },
466         { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
467           .args = { { Ptr, 0 }, { Int, 1 } } },
468         { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
469           .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
470                     { IntArray, 3 }, { Int, 4 } } },
471         { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
472           .args = { { Int, 0 } } },
473         { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
474         { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
475           .args = { { CloudABISignal, 0 } } },
476         { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
477           .args = { { BinString | OUT, 0 }, { Int, 1 } } },
478         { .name = "cloudabi_sys_sock_accept", .ret_type = 1, .nargs = 2,
479           .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 } } },
480         { .name = "cloudabi_sys_sock_bind", .ret_type = 1, .nargs = 3,
481           .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
482         { .name = "cloudabi_sys_sock_connect", .ret_type = 1, .nargs = 3,
483           .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
484         { .name = "cloudabi_sys_sock_listen", .ret_type = 1, .nargs = 2,
485           .args = { { Int, 0 }, { Int, 1 } } },
486         { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
487           .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
488         { .name = "cloudabi_sys_sock_stat_get", .ret_type = 1, .nargs = 3,
489           .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 },
490                     { CloudABISSFlags, 2 } } },
491         { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
492           .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
493         { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
494
495         { .name = 0 },
496 };
497 static STAILQ_HEAD(, syscall) syscalls;
498
499 /* Xlat idea taken from strace */
500 struct xlat {
501         int val;
502         const char *str;
503 };
504
505 #define X(a)    { a, #a },
506 #define XEND    { 0, NULL }
507
508 static struct xlat kevent_filters[] = {
509         X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
510         X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
511         X(EVFILT_PROCDESC) X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER)
512         X(EVFILT_SENDFILE) XEND
513 };
514
515 static struct xlat kevent_flags[] = {
516         X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
517         X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH) X(EV_FORCEONESHOT)
518         X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
519 };
520
521 static struct xlat kevent_user_ffctrl[] = {
522         X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
523         XEND
524 };
525
526 static struct xlat kevent_rdwr_fflags[] = {
527         X(NOTE_LOWAT) X(NOTE_FILE_POLL) XEND
528 };
529
530 static struct xlat kevent_vnode_fflags[] = {
531         X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB)
532         X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND
533 };
534
535 static struct xlat kevent_proc_fflags[] = {
536         X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR)
537         X(NOTE_CHILD) XEND
538 };
539
540 static struct xlat kevent_timer_fflags[] = {
541         X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS)
542         XEND
543 };
544
545 static struct xlat poll_flags[] = {
546         X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
547         X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
548         X(POLLWRBAND) X(POLLINIGNEOF) XEND
549 };
550
551 static struct xlat sigaction_flags[] = {
552         X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
553         X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
554 };
555
556 static struct xlat pathconf_arg[] = {
557         X(_PC_LINK_MAX)  X(_PC_MAX_CANON)  X(_PC_MAX_INPUT)
558         X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF)
559         X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE)
560         X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO)
561         X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS)
562         X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE)
563         X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
564         X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
565         X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
566         X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND
567 };
568
569 static struct xlat at_flags[] = {
570         X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW)
571         X(AT_REMOVEDIR) XEND
572 };
573
574 static struct xlat sysarch_ops[] = {
575 #if defined(__i386__) || defined(__amd64__)
576         X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM)
577         X(I386_VM86) X(I386_GET_FSBASE) X(I386_SET_FSBASE) X(I386_GET_GSBASE)
578         X(I386_SET_GSBASE) X(I386_GET_XFPUSTATE) X(AMD64_GET_FSBASE)
579         X(AMD64_SET_FSBASE) X(AMD64_GET_GSBASE) X(AMD64_SET_GSBASE)
580         X(AMD64_GET_XFPUSTATE)
581 #endif
582         XEND
583 };
584
585 static struct xlat linux_socketcall_ops[] = {
586         X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
587         X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
588         X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
589         X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
590         X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
591         XEND
592 };
593
594 #undef X
595 #define X(a)    { CLOUDABI_##a, #a },
596
597 static struct xlat cloudabi_advice[] = {
598         X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
599         X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
600         XEND
601 };
602
603 static struct xlat cloudabi_clockid[] = {
604         X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
605         X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
606         XEND
607 };
608
609 static struct xlat cloudabi_errno[] = {
610         X(E2BIG) X(EACCES) X(EADDRINUSE) X(EADDRNOTAVAIL)
611         X(EAFNOSUPPORT) X(EAGAIN) X(EALREADY) X(EBADF) X(EBADMSG)
612         X(EBUSY) X(ECANCELED) X(ECHILD) X(ECONNABORTED) X(ECONNREFUSED)
613         X(ECONNRESET) X(EDEADLK) X(EDESTADDRREQ) X(EDOM) X(EDQUOT)
614         X(EEXIST) X(EFAULT) X(EFBIG) X(EHOSTUNREACH) X(EIDRM) X(EILSEQ)
615         X(EINPROGRESS) X(EINTR) X(EINVAL) X(EIO) X(EISCONN) X(EISDIR)
616         X(ELOOP) X(EMFILE) X(EMLINK) X(EMSGSIZE) X(EMULTIHOP)
617         X(ENAMETOOLONG) X(ENETDOWN) X(ENETRESET) X(ENETUNREACH)
618         X(ENFILE) X(ENOBUFS) X(ENODEV) X(ENOENT) X(ENOEXEC) X(ENOLCK)
619         X(ENOLINK) X(ENOMEM) X(ENOMSG) X(ENOPROTOOPT) X(ENOSPC)
620         X(ENOSYS) X(ENOTCONN) X(ENOTDIR) X(ENOTEMPTY) X(ENOTRECOVERABLE)
621         X(ENOTSOCK) X(ENOTSUP) X(ENOTTY) X(ENXIO) X(EOVERFLOW)
622         X(EOWNERDEAD) X(EPERM) X(EPIPE) X(EPROTO) X(EPROTONOSUPPORT)
623         X(EPROTOTYPE) X(ERANGE) X(EROFS) X(ESPIPE) X(ESRCH) X(ESTALE)
624         X(ETIMEDOUT) X(ETXTBSY) X(EXDEV) X(ENOTCAPABLE)
625         XEND
626 };
627
628 static struct xlat cloudabi_fdflags[] = {
629         X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
630         X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
631         XEND
632 };
633
634 static struct xlat cloudabi_fdsflags[] = {
635         X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
636         XEND
637 };
638
639 static struct xlat cloudabi_filetype[] = {
640         X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
641         X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
642         X(FILETYPE_FIFO) X(FILETYPE_POLL) X(FILETYPE_PROCESS)
643         X(FILETYPE_REGULAR_FILE) X(FILETYPE_SHARED_MEMORY)
644         X(FILETYPE_SOCKET_DGRAM) X(FILETYPE_SOCKET_SEQPACKET)
645         X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK)
646         XEND
647 };
648
649 static struct xlat cloudabi_fsflags[] = {
650         X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
651         X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
652         XEND
653 };
654
655 static struct xlat cloudabi_mflags[] = {
656         X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
657         XEND
658 };
659
660 static struct xlat cloudabi_mprot[] = {
661         X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
662         XEND
663 };
664
665 static struct xlat cloudabi_msflags[] = {
666         X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
667         XEND
668 };
669
670 static struct xlat cloudabi_oflags[] = {
671         X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
672         XEND
673 };
674
675 static struct xlat cloudabi_sa_family[] = {
676         X(AF_UNSPEC) X(AF_INET) X(AF_INET6) X(AF_UNIX)
677         XEND
678 };
679
680 static struct xlat cloudabi_sdflags[] = {
681         X(SHUT_RD) X(SHUT_WR)
682         XEND
683 };
684
685 static struct xlat cloudabi_signal[] = {
686         X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
687         X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
688         X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
689         X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
690         X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
691         XEND
692 };
693
694 static struct xlat cloudabi_ssflags[] = {
695         X(SOCKSTAT_CLEAR_ERROR)
696         XEND
697 };
698
699 static struct xlat cloudabi_ssstate[] = {
700         X(SOCKSTATE_ACCEPTCONN)
701         XEND
702 };
703
704 static struct xlat cloudabi_ulflags[] = {
705         X(UNLINK_REMOVEDIR)
706         XEND
707 };
708
709 static struct xlat cloudabi_whence[] = {
710         X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
711         XEND
712 };
713
714 #undef X
715 #undef XEND
716
717 /*
718  * Searches an xlat array for a value, and returns it if found.  Otherwise
719  * return a string representation.
720  */
721 static const char *
722 lookup(struct xlat *xlat, int val, int base)
723 {
724         static char tmp[16];
725
726         for (; xlat->str != NULL; xlat++)
727                 if (xlat->val == val)
728                         return (xlat->str);
729         switch (base) {
730                 case 8:
731                         sprintf(tmp, "0%o", val);
732                         break;
733                 case 16:
734                         sprintf(tmp, "0x%x", val);
735                         break;
736                 case 10:
737                         sprintf(tmp, "%u", val);
738                         break;
739                 default:
740                         errx(1,"Unknown lookup base");
741                         break;
742         }
743         return (tmp);
744 }
745
746 static const char *
747 xlookup(struct xlat *xlat, int val)
748 {
749
750         return (lookup(xlat, val, 16));
751 }
752
753 /*
754  * Searches an xlat array containing bitfield values.  Remaining bits
755  * set after removing the known ones are printed at the end:
756  * IN|0x400.
757  */
758 static char *
759 xlookup_bits(struct xlat *xlat, int val)
760 {
761         int len, rem;
762         static char str[512];
763
764         len = 0;
765         rem = val;
766         for (; xlat->str != NULL; xlat++) {
767                 if ((xlat->val & rem) == xlat->val) {
768                         /*
769                          * Don't print the "all-bits-zero" string unless all
770                          * bits are really zero.
771                          */
772                         if (xlat->val == 0 && val != 0)
773                                 continue;
774                         len += sprintf(str + len, "%s|", xlat->str);
775                         rem &= ~(xlat->val);
776                 }
777         }
778
779         /*
780          * If we have leftover bits or didn't match anything, print
781          * the remainder.
782          */
783         if (rem || len == 0)
784                 len += sprintf(str + len, "0x%x", rem);
785         if (len && str[len - 1] == '|')
786                 len--;
787         str[len] = 0;
788         return (str);
789 }
790
791 static void
792 print_integer_arg(const char *(*decoder)(int), FILE *fp, int value)
793 {
794         const char *str;
795
796         str = decoder(value);
797         if (str != NULL)
798                 fputs(str, fp);
799         else
800                 fprintf(fp, "%d", value);
801 }
802
803 static void
804 print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value)
805 {
806         int rem;
807
808         if (!decoder(fp, value, &rem))
809                 fprintf(fp, "0x%x", rem);
810         else if (rem != 0)
811                 fprintf(fp, "|0x%x", rem);
812 }
813
814 void
815 init_syscalls(void)
816 {
817         struct syscall *sc;
818
819         STAILQ_INIT(&syscalls);
820         for (sc = decoded_syscalls; sc->name != NULL; sc++)
821                 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
822 }
823
824 static struct syscall *
825 find_syscall(struct procabi *abi, u_int number)
826 {
827         struct extra_syscall *es;
828
829         if (number < nitems(abi->syscalls))
830                 return (abi->syscalls[number]);
831         STAILQ_FOREACH(es, &abi->extra_syscalls, entries) {
832                 if (es->number == number)
833                         return (es->sc);
834         }
835         return (NULL);
836 }
837
838 static void
839 add_syscall(struct procabi *abi, u_int number, struct syscall *sc)
840 {
841         struct extra_syscall *es;
842
843         if (number < nitems(abi->syscalls)) {
844                 assert(abi->syscalls[number] == NULL);
845                 abi->syscalls[number] = sc;
846         } else {
847                 es = malloc(sizeof(*es));
848                 es->sc = sc;
849                 es->number = number;
850                 STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries);
851         }
852 }
853
854 /*
855  * If/when the list gets big, it might be desirable to do it
856  * as a hash table or binary search.
857  */
858 struct syscall *
859 get_syscall(struct threadinfo *t, u_int number, u_int nargs)
860 {
861         struct syscall *sc;
862         const char *name;
863         char *new_name;
864         u_int i;
865
866         sc = find_syscall(t->proc->abi, number);
867         if (sc != NULL)
868                 return (sc);
869
870         name = sysdecode_syscallname(t->proc->abi->abi, number);
871         if (name == NULL) {
872                 asprintf(&new_name, "#%d", number);
873                 name = new_name;
874         } else
875                 new_name = NULL;
876         STAILQ_FOREACH(sc, &syscalls, entries) {
877                 if (strcmp(name, sc->name) == 0) {
878                         add_syscall(t->proc->abi, number, sc);
879                         free(new_name);
880                         return (sc);
881                 }
882         }
883
884         /* It is unknown.  Add it into the list. */
885 #if DEBUG
886         fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
887             nargs);
888 #endif
889
890         sc = calloc(1, sizeof(struct syscall));
891         sc->name = name;
892         if (new_name != NULL)
893                 sc->unknown = true;
894         sc->ret_type = 1;
895         sc->nargs = nargs;
896         for (i = 0; i < nargs; i++) {
897                 sc->args[i].offset = i;
898                 /* Treat all unknown arguments as LongHex. */
899                 sc->args[i].type = LongHex;
900         }
901         STAILQ_INSERT_HEAD(&syscalls, sc, entries);
902         add_syscall(t->proc->abi, number, sc);
903
904         return (sc);
905 }
906
907 /*
908  * Copy a fixed amount of bytes from the process.
909  */
910 static int
911 get_struct(pid_t pid, void *offset, void *buf, int len)
912 {
913         struct ptrace_io_desc iorequest;
914
915         iorequest.piod_op = PIOD_READ_D;
916         iorequest.piod_offs = offset;
917         iorequest.piod_addr = buf;
918         iorequest.piod_len = len;
919         if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
920                 return (-1);
921         return (0);
922 }
923
924 #define MAXSIZE         4096
925
926 /*
927  * Copy a string from the process.  Note that it is
928  * expected to be a C string, but if max is set, it will
929  * only get that much.
930  */
931 static char *
932 get_string(pid_t pid, void *addr, int max)
933 {
934         struct ptrace_io_desc iorequest;
935         char *buf, *nbuf;
936         size_t offset, size, totalsize;
937
938         offset = 0;
939         if (max)
940                 size = max + 1;
941         else {
942                 /* Read up to the end of the current page. */
943                 size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE);
944                 if (size > MAXSIZE)
945                         size = MAXSIZE;
946         }
947         totalsize = size;
948         buf = malloc(totalsize);
949         if (buf == NULL)
950                 return (NULL);
951         for (;;) {
952                 iorequest.piod_op = PIOD_READ_D;
953                 iorequest.piod_offs = (char *)addr + offset;
954                 iorequest.piod_addr = buf + offset;
955                 iorequest.piod_len = size;
956                 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
957                         free(buf);
958                         return (NULL);
959                 }
960                 if (memchr(buf + offset, '\0', size) != NULL)
961                         return (buf);
962                 offset += size;
963                 if (totalsize < MAXSIZE && max == 0) {
964                         size = MAXSIZE - totalsize;
965                         if (size > PAGE_SIZE)
966                                 size = PAGE_SIZE;
967                         nbuf = realloc(buf, totalsize + size);
968                         if (nbuf == NULL) {
969                                 buf[totalsize - 1] = '\0';
970                                 return (buf);
971                         }
972                         buf = nbuf;
973                         totalsize += size;
974                 } else {
975                         buf[totalsize - 1] = '\0';
976                         return (buf);
977                 }
978         }
979 }
980
981 static const char *
982 strsig2(int sig)
983 {
984         static char tmp[32];
985         const char *signame;
986
987         signame = sysdecode_signal(sig);
988         if (signame == NULL) {
989                 snprintf(tmp, sizeof(tmp), "%d", sig);
990                 signame = tmp;
991         }
992         return (signame);
993 }
994
995 static void
996 print_kevent(FILE *fp, struct kevent *ke, int input)
997 {
998
999         switch (ke->filter) {
1000         case EVFILT_READ:
1001         case EVFILT_WRITE:
1002         case EVFILT_VNODE:
1003         case EVFILT_PROC:
1004         case EVFILT_TIMER:
1005         case EVFILT_PROCDESC:
1006                 fprintf(fp, "%ju", (uintmax_t)ke->ident);
1007                 break;
1008         case EVFILT_SIGNAL:
1009                 fputs(strsig2(ke->ident), fp);
1010                 break;
1011         default:
1012                 fprintf(fp, "%p", (void *)ke->ident);
1013         }
1014         fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter),
1015             xlookup_bits(kevent_flags, ke->flags));
1016         switch (ke->filter) {
1017         case EVFILT_READ:
1018         case EVFILT_WRITE:
1019                 fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp);
1020                 break;
1021         case EVFILT_VNODE:
1022                 fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp);
1023                 break;
1024         case EVFILT_PROC:
1025         case EVFILT_PROCDESC:
1026                 fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp);
1027                 break;
1028         case EVFILT_TIMER:
1029                 fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp);
1030                 break;
1031         case EVFILT_USER: {
1032                 int ctrl, data;
1033
1034                 ctrl = ke->fflags & NOTE_FFCTRLMASK;
1035                 data = ke->fflags & NOTE_FFLAGSMASK;
1036                 if (input) {
1037                         fputs(xlookup(kevent_user_ffctrl, ctrl), fp);
1038                         if (ke->fflags & NOTE_TRIGGER)
1039                                 fputs("|NOTE_TRIGGER", fp);
1040                         if (data != 0)
1041                                 fprintf(fp, "|%#x", data);
1042                 } else {
1043                         fprintf(fp, "%#x", data);
1044                 }
1045                 break;
1046         }
1047         default:
1048                 fprintf(fp, "%#x", ke->fflags);
1049         }
1050         fprintf(fp, ",%p,%p", (void *)ke->data, (void *)ke->udata);
1051 }
1052
1053 static void
1054 print_utrace(FILE *fp, void *utrace_addr, size_t len)
1055 {
1056         unsigned char *utrace_buffer;
1057
1058         fprintf(fp, "{ ");
1059         if (sysdecode_utrace(fp, utrace_addr, len)) {
1060                 fprintf(fp, " }");
1061                 return;
1062         }
1063
1064         utrace_buffer = utrace_addr;
1065         fprintf(fp, "%zu:", len);
1066         while (len--)
1067                 fprintf(fp, " %02x", *utrace_buffer++);
1068         fprintf(fp, " }");
1069 }
1070
1071 /*
1072  * Converts a syscall argument into a string.  Said string is
1073  * allocated via malloc(), so needs to be free()'d.  sc is
1074  * a pointer to the syscall description (see above); args is
1075  * an array of all of the system call arguments.
1076  */
1077 char *
1078 print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
1079     struct trussinfo *trussinfo)
1080 {
1081         FILE *fp;
1082         char *tmp;
1083         size_t tmplen;
1084         pid_t pid;
1085
1086         fp = open_memstream(&tmp, &tmplen);
1087         pid = trussinfo->curthread->proc->pid;
1088         switch (sc->type & ARG_MASK) {
1089         case Hex:
1090                 fprintf(fp, "0x%x", (int)args[sc->offset]);
1091                 break;
1092         case Octal:
1093                 fprintf(fp, "0%o", (int)args[sc->offset]);
1094                 break;
1095         case Int:
1096                 fprintf(fp, "%d", (int)args[sc->offset]);
1097                 break;
1098         case UInt:
1099                 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1100                 break;
1101         case LongHex:
1102                 fprintf(fp, "0x%lx", args[sc->offset]);
1103                 break;
1104         case Long:
1105                 fprintf(fp, "%ld", args[sc->offset]);
1106                 break;
1107         case Name: {
1108                 /* NULL-terminated string. */
1109                 char *tmp2;
1110
1111                 tmp2 = get_string(pid, (void*)args[sc->offset], 0);
1112                 fprintf(fp, "\"%s\"", tmp2);
1113                 free(tmp2);
1114                 break;
1115         }
1116         case BinString: {
1117                 /*
1118                  * Binary block of data that might have printable characters.
1119                  * XXX If type|OUT, assume that the length is the syscall's
1120                  * return value.  Otherwise, assume that the length of the block
1121                  * is in the next syscall argument.
1122                  */
1123                 int max_string = trussinfo->strsize;
1124                 char tmp2[max_string + 1], *tmp3;
1125                 int len;
1126                 int truncated = 0;
1127
1128                 if (sc->type & OUT)
1129                         len = retval[0];
1130                 else
1131                         len = args[sc->offset + 1];
1132
1133                 /*
1134                  * Don't print more than max_string characters, to avoid word
1135                  * wrap.  If we have to truncate put some ... after the string.
1136                  */
1137                 if (len > max_string) {
1138                         len = max_string;
1139                         truncated = 1;
1140                 }
1141                 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
1142                     != -1) {
1143                         tmp3 = malloc(len * 4 + 1);
1144                         while (len) {
1145                                 if (strvisx(tmp3, tmp2, len,
1146                                     VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1147                                         break;
1148                                 len--;
1149                                 truncated = 1;
1150                         }
1151                         fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1152                             "..." : "");
1153                         free(tmp3);
1154                 } else {
1155                         fprintf(fp, "0x%lx", args[sc->offset]);
1156                 }
1157                 break;
1158         }
1159         case ExecArgs:
1160         case ExecEnv:
1161         case StringArray: {
1162                 uintptr_t addr;
1163                 union {
1164                         char *strarray[0];
1165                         char buf[PAGE_SIZE];
1166                 } u;
1167                 char *string;
1168                 size_t len;
1169                 u_int first, i;
1170
1171                 /*
1172                  * Only parse argv[] and environment arrays from exec calls
1173                  * if requested.
1174                  */
1175                 if (((sc->type & ARG_MASK) == ExecArgs &&
1176                     (trussinfo->flags & EXECVEARGS) == 0) ||
1177                     ((sc->type & ARG_MASK) == ExecEnv &&
1178                     (trussinfo->flags & EXECVEENVS) == 0)) {
1179                         fprintf(fp, "0x%lx", args[sc->offset]);
1180                         break;
1181                 }
1182
1183                 /*
1184                  * Read a page of pointers at a time.  Punt if the top-level
1185                  * pointer is not aligned.  Note that the first read is of
1186                  * a partial page.
1187                  */
1188                 addr = args[sc->offset];
1189                 if (addr % sizeof(char *) != 0) {
1190                         fprintf(fp, "0x%lx", args[sc->offset]);
1191                         break;
1192                 }
1193
1194                 len = PAGE_SIZE - (addr & PAGE_MASK);
1195                 if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
1196                         fprintf(fp, "0x%lx", args[sc->offset]);
1197                         break;
1198                 }
1199
1200                 fputc('[', fp);
1201                 first = 1;
1202                 i = 0;
1203                 while (u.strarray[i] != NULL) {
1204                         string = get_string(pid, u.strarray[i], 0);
1205                         fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1206                         free(string);
1207                         first = 0;
1208
1209                         i++;
1210                         if (i == len / sizeof(char *)) {
1211                                 addr += len;
1212                                 len = PAGE_SIZE;
1213                                 if (get_struct(pid, (void *)addr, u.buf, len) ==
1214                                     -1) {
1215                                         fprintf(fp, ", <inval>");
1216                                         break;
1217                                 }
1218                                 i = 0;
1219                         }
1220                 }
1221                 fputs(" ]", fp);
1222                 break;
1223         }
1224 #ifdef __LP64__
1225         case Quad:
1226                 fprintf(fp, "%ld", args[sc->offset]);
1227                 break;
1228         case QuadHex:
1229                 fprintf(fp, "0x%lx", args[sc->offset]);
1230                 break;
1231 #else
1232         case Quad:
1233         case QuadHex: {
1234                 unsigned long long ll;
1235
1236 #if _BYTE_ORDER == _LITTLE_ENDIAN
1237                 ll = (unsigned long long)args[sc->offset + 1] << 32 |
1238                     args[sc->offset];
1239 #else
1240                 ll = (unsigned long long)args[sc->offset] << 32 |
1241                     args[sc->offset + 1];
1242 #endif
1243                 if ((sc->type & ARG_MASK) == Quad)
1244                         fprintf(fp, "%lld", ll);
1245                 else
1246                         fprintf(fp, "0x%llx", ll);
1247                 break;
1248         }
1249 #endif
1250         case Ptr:
1251                 fprintf(fp, "0x%lx", args[sc->offset]);
1252                 break;
1253         case Readlinkres: {
1254                 char *tmp2;
1255
1256                 if (retval[0] == -1)
1257                         break;
1258                 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
1259                 fprintf(fp, "\"%s\"", tmp2);
1260                 free(tmp2);
1261                 break;
1262         }
1263         case Ioctl: {
1264                 const char *temp;
1265                 unsigned long cmd;
1266
1267                 cmd = args[sc->offset];
1268                 temp = sysdecode_ioctlname(cmd);
1269                 if (temp)
1270                         fputs(temp, fp);
1271                 else {
1272                         fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1273                             cmd, cmd & IOC_OUT ? "R" : "",
1274                             cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1275                             isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1276                             cmd & 0xFF, IOCPARM_LEN(cmd));
1277                 }
1278                 break;
1279         }
1280         case Timespec: {
1281                 struct timespec ts;
1282
1283                 if (get_struct(pid, (void *)args[sc->offset], &ts,
1284                     sizeof(ts)) != -1)
1285                         fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1286                             ts.tv_nsec);
1287                 else
1288                         fprintf(fp, "0x%lx", args[sc->offset]);
1289                 break;
1290         }
1291         case Timespec2: {
1292                 struct timespec ts[2];
1293                 const char *sep;
1294                 unsigned int i;
1295
1296                 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
1297                     != -1) {
1298                         fputs("{ ", fp);
1299                         sep = "";
1300                         for (i = 0; i < nitems(ts); i++) {
1301                                 fputs(sep, fp);
1302                                 sep = ", ";
1303                                 switch (ts[i].tv_nsec) {
1304                                 case UTIME_NOW:
1305                                         fprintf(fp, "UTIME_NOW");
1306                                         break;
1307                                 case UTIME_OMIT:
1308                                         fprintf(fp, "UTIME_OMIT");
1309                                         break;
1310                                 default:
1311                                         fprintf(fp, "%jd.%09ld",
1312                                             (intmax_t)ts[i].tv_sec,
1313                                             ts[i].tv_nsec);
1314                                         break;
1315                                 }
1316                         }
1317                         fputs(" }", fp);
1318                 } else
1319                         fprintf(fp, "0x%lx", args[sc->offset]);
1320                 break;
1321         }
1322         case Timeval: {
1323                 struct timeval tv;
1324
1325                 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1326                     != -1)
1327                         fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1328                             tv.tv_usec);
1329                 else
1330                         fprintf(fp, "0x%lx", args[sc->offset]);
1331                 break;
1332         }
1333         case Timeval2: {
1334                 struct timeval tv[2];
1335
1336                 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1337                     != -1)
1338                         fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1339                             (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1340                             (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1341                 else
1342                         fprintf(fp, "0x%lx", args[sc->offset]);
1343                 break;
1344         }
1345         case Itimerval: {
1346                 struct itimerval itv;
1347
1348                 if (get_struct(pid, (void *)args[sc->offset], &itv,
1349                     sizeof(itv)) != -1)
1350                         fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1351                             (intmax_t)itv.it_interval.tv_sec,
1352                             itv.it_interval.tv_usec,
1353                             (intmax_t)itv.it_value.tv_sec,
1354                             itv.it_value.tv_usec);
1355                 else
1356                         fprintf(fp, "0x%lx", args[sc->offset]);
1357                 break;
1358         }
1359         case LinuxSockArgs:
1360         {
1361                 struct linux_socketcall_args largs;
1362
1363                 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
1364                     sizeof(largs)) != -1)
1365                         fprintf(fp, "{ %s, 0x%lx }",
1366                             lookup(linux_socketcall_ops, largs.what, 10),
1367                             (long unsigned int)largs.args);
1368                 else
1369                         fprintf(fp, "0x%lx", args[sc->offset]);
1370                 break;
1371         }
1372         case Pollfd: {
1373                 /*
1374                  * XXX: A Pollfd argument expects the /next/ syscall argument
1375                  * to be the number of fds in the array. This matches the poll
1376                  * syscall.
1377                  */
1378                 struct pollfd *pfd;
1379                 int numfds = args[sc->offset + 1];
1380                 size_t bytes = sizeof(struct pollfd) * numfds;
1381                 int i;
1382
1383                 if ((pfd = malloc(bytes)) == NULL)
1384                         err(1, "Cannot malloc %zu bytes for pollfd array",
1385                             bytes);
1386                 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
1387                     != -1) {
1388                         fputs("{", fp);
1389                         for (i = 0; i < numfds; i++) {
1390                                 fprintf(fp, " %d/%s", pfd[i].fd,
1391                                     xlookup_bits(poll_flags, pfd[i].events));
1392                         }
1393                         fputs(" }", fp);
1394                 } else {
1395                         fprintf(fp, "0x%lx", args[sc->offset]);
1396                 }
1397                 free(pfd);
1398                 break;
1399         }
1400         case Fd_set: {
1401                 /*
1402                  * XXX: A Fd_set argument expects the /first/ syscall argument
1403                  * to be the number of fds in the array.  This matches the
1404                  * select syscall.
1405                  */
1406                 fd_set *fds;
1407                 int numfds = args[0];
1408                 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1409                 int i;
1410
1411                 if ((fds = malloc(bytes)) == NULL)
1412                         err(1, "Cannot malloc %zu bytes for fd_set array",
1413                             bytes);
1414                 if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
1415                     != -1) {
1416                         fputs("{", fp);
1417                         for (i = 0; i < numfds; i++) {
1418                                 if (FD_ISSET(i, fds))
1419                                         fprintf(fp, " %d", i);
1420                         }
1421                         fputs(" }", fp);
1422                 } else
1423                         fprintf(fp, "0x%lx", args[sc->offset]);
1424                 free(fds);
1425                 break;
1426         }
1427         case Signal:
1428                 fputs(strsig2(args[sc->offset]), fp);
1429                 break;
1430         case Sigset: {
1431                 long sig;
1432                 sigset_t ss;
1433                 int i, first;
1434
1435                 sig = args[sc->offset];
1436                 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
1437                     sizeof(ss)) == -1) {
1438                         fprintf(fp, "0x%lx", args[sc->offset]);
1439                         break;
1440                 }
1441                 fputs("{ ", fp);
1442                 first = 1;
1443                 for (i = 1; i < sys_nsig; i++) {
1444                         if (sigismember(&ss, i)) {
1445                                 fprintf(fp, "%s%s", !first ? "|" : "",
1446                                     strsig2(i));
1447                                 first = 0;
1448                         }
1449                 }
1450                 if (!first)
1451                         fputc(' ', fp);
1452                 fputc('}', fp);
1453                 break;
1454         }
1455         case Sigprocmask:
1456                 print_integer_arg(sysdecode_sigprocmask_how, fp,
1457                     args[sc->offset]);
1458                 break;
1459         case Fcntlflag:
1460                 /* XXX: Output depends on the value of the previous argument. */
1461                 if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
1462                         sysdecode_fcntl_arg(fp, args[sc->offset - 1],
1463                             args[sc->offset], 16);
1464                 break;
1465         case Open:
1466                 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
1467                 break;
1468         case Fcntl:
1469                 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
1470                 break;
1471         case Mprot:
1472                 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
1473                 break;
1474         case Mmapflags:
1475                 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
1476                 break;
1477         case Whence:
1478                 print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
1479                 break;
1480         case Sockdomain:
1481                 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
1482                 break;
1483         case Socktype:
1484                 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
1485                 break;
1486         case Shutdown:
1487                 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
1488                 break;
1489         case Resource:
1490                 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
1491                 break;
1492         case Pathconf:
1493                 fputs(xlookup(pathconf_arg, args[sc->offset]), fp);
1494                 break;
1495         case Rforkflags:
1496                 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
1497                 break;
1498         case Sockaddr: {
1499                 char addr[64];
1500                 struct sockaddr_in *lsin;
1501                 struct sockaddr_in6 *lsin6;
1502                 struct sockaddr_un *sun;
1503                 struct sockaddr *sa;
1504                 socklen_t len;
1505                 u_char *q;
1506
1507                 if (args[sc->offset] == 0) {
1508                         fputs("NULL", fp);
1509                         break;
1510                 }
1511
1512                 /*
1513                  * Extract the address length from the next argument.  If
1514                  * this is an output sockaddr (OUT is set), then the
1515                  * next argument is a pointer to a socklen_t.  Otherwise
1516                  * the next argument contains a socklen_t by value.
1517                  */
1518                 if (sc->type & OUT) {
1519                         if (get_struct(pid, (void *)args[sc->offset + 1],
1520                             &len, sizeof(len)) == -1) {
1521                                 fprintf(fp, "0x%lx", args[sc->offset]);
1522                                 break;
1523                         }
1524                 } else
1525                         len = args[sc->offset + 1];
1526
1527                 /* If the length is too small, just bail. */
1528                 if (len < sizeof(*sa)) {
1529                         fprintf(fp, "0x%lx", args[sc->offset]);
1530                         break;
1531                 }
1532
1533                 sa = calloc(1, len);
1534                 if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) {
1535                         free(sa);
1536                         fprintf(fp, "0x%lx", args[sc->offset]);
1537                         break;
1538                 }
1539
1540                 switch (sa->sa_family) {
1541                 case AF_INET:
1542                         if (len < sizeof(*lsin))
1543                                 goto sockaddr_short;
1544                         lsin = (struct sockaddr_in *)(void *)sa;
1545                         inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1546                         fprintf(fp, "{ AF_INET %s:%d }", addr,
1547                             htons(lsin->sin_port));
1548                         break;
1549                 case AF_INET6:
1550                         if (len < sizeof(*lsin6))
1551                                 goto sockaddr_short;
1552                         lsin6 = (struct sockaddr_in6 *)(void *)sa;
1553                         inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1554                             sizeof(addr));
1555                         fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1556                             htons(lsin6->sin6_port));
1557                         break;
1558                 case AF_UNIX:
1559                         sun = (struct sockaddr_un *)sa;
1560                         fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1561                             (int)(len - offsetof(struct sockaddr_un, sun_path)),
1562                             sun->sun_path);
1563                         break;
1564                 default:
1565                 sockaddr_short:
1566                         fprintf(fp,
1567                             "{ sa_len = %d, sa_family = %d, sa_data = {",
1568                             (int)sa->sa_len, (int)sa->sa_family);
1569                         for (q = (u_char *)sa->sa_data;
1570                              q < (u_char *)sa + len; q++)
1571                                 fprintf(fp, "%s 0x%02x",
1572                                     q == (u_char *)sa->sa_data ? "" : ",",
1573                                     *q);
1574                         fputs(" } }", fp);
1575                 }
1576                 free(sa);
1577                 break;
1578         }
1579         case Sigaction: {
1580                 struct sigaction sa;
1581
1582                 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
1583                     != -1) {
1584                         fputs("{ ", fp);
1585                         if (sa.sa_handler == SIG_DFL)
1586                                 fputs("SIG_DFL", fp);
1587                         else if (sa.sa_handler == SIG_IGN)
1588                                 fputs("SIG_IGN", fp);
1589                         else
1590                                 fprintf(fp, "%p", sa.sa_handler);
1591                         fprintf(fp, " %s ss_t }",
1592                             xlookup_bits(sigaction_flags, sa.sa_flags));
1593                 } else
1594                         fprintf(fp, "0x%lx", args[sc->offset]);
1595                 break;
1596         }
1597         case Kevent: {
1598                 /*
1599                  * XXX XXX: The size of the array is determined by either the
1600                  * next syscall argument, or by the syscall return value,
1601                  * depending on which argument number we are.  This matches the
1602                  * kevent syscall, but luckily that's the only syscall that uses
1603                  * them.
1604                  */
1605                 struct kevent *ke;
1606                 int numevents = -1;
1607                 size_t bytes;
1608                 int i;
1609
1610                 if (sc->offset == 1)
1611                         numevents = args[sc->offset+1];
1612                 else if (sc->offset == 3 && retval[0] != -1)
1613                         numevents = retval[0];
1614
1615                 if (numevents >= 0) {
1616                         bytes = sizeof(struct kevent) * numevents;
1617                         if ((ke = malloc(bytes)) == NULL)
1618                                 err(1,
1619                                     "Cannot malloc %zu bytes for kevent array",
1620                                     bytes);
1621                 } else
1622                         ke = NULL;
1623                 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
1624                     ke, bytes) != -1) {
1625                         fputc('{', fp);
1626                         for (i = 0; i < numevents; i++) {
1627                                 fputc(' ', fp);
1628                                 print_kevent(fp, &ke[i], sc->offset == 1);
1629                         }
1630                         fputs(" }", fp);
1631                 } else {
1632                         fprintf(fp, "0x%lx", args[sc->offset]);
1633                 }
1634                 free(ke);
1635                 break;
1636         }
1637         case Stat: {
1638                 struct stat st;
1639
1640                 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1641                     != -1) {
1642                         char mode[12];
1643
1644                         strmode(st.st_mode, mode);
1645                         fprintf(fp,
1646                             "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1647                             (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1648                             (long)st.st_blksize);
1649                 } else {
1650                         fprintf(fp, "0x%lx", args[sc->offset]);
1651                 }
1652                 break;
1653         }
1654         case StatFs: {
1655                 unsigned int i;
1656                 struct statfs buf;
1657
1658                 if (get_struct(pid, (void *)args[sc->offset], &buf,
1659                     sizeof(buf)) != -1) {
1660                         char fsid[17];
1661
1662                         bzero(fsid, sizeof(fsid));
1663                         if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
1664                                 for (i = 0; i < sizeof(buf.f_fsid); i++)
1665                                         snprintf(&fsid[i*2],
1666                                             sizeof(fsid) - (i*2), "%02x",
1667                                             ((u_char *)&buf.f_fsid)[i]);
1668                         }
1669                         fprintf(fp,
1670                             "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
1671                             "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
1672                             buf.f_mntfromname, fsid);
1673                 } else
1674                         fprintf(fp, "0x%lx", args[sc->offset]);
1675                 break;
1676         }
1677
1678         case Rusage: {
1679                 struct rusage ru;
1680
1681                 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
1682                     != -1) {
1683                         fprintf(fp,
1684                             "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
1685                             (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
1686                             (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
1687                             ru.ru_inblock, ru.ru_oublock);
1688                 } else
1689                         fprintf(fp, "0x%lx", args[sc->offset]);
1690                 break;
1691         }
1692         case Rlimit: {
1693                 struct rlimit rl;
1694
1695                 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
1696                     != -1) {
1697                         fprintf(fp, "{ cur=%ju,max=%ju }",
1698                             rl.rlim_cur, rl.rlim_max);
1699                 } else
1700                         fprintf(fp, "0x%lx", args[sc->offset]);
1701                 break;
1702         }
1703         case ExitStatus: {
1704                 int status;
1705
1706                 if (get_struct(pid, (void *)args[sc->offset], &status,
1707                     sizeof(status)) != -1) {
1708                         fputs("{ ", fp);
1709                         if (WIFCONTINUED(status))
1710                                 fputs("CONTINUED", fp);
1711                         else if (WIFEXITED(status))
1712                                 fprintf(fp, "EXITED,val=%d",
1713                                     WEXITSTATUS(status));
1714                         else if (WIFSIGNALED(status))
1715                                 fprintf(fp, "SIGNALED,sig=%s%s",
1716                                     strsig2(WTERMSIG(status)),
1717                                     WCOREDUMP(status) ? ",cored" : "");
1718                         else
1719                                 fprintf(fp, "STOPPED,sig=%s",
1720                                     strsig2(WTERMSIG(status)));
1721                         fputs(" }", fp);
1722                 } else
1723                         fprintf(fp, "0x%lx", args[sc->offset]);
1724                 break;
1725         }
1726         case Waitoptions:
1727                 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]);
1728                 break;
1729         case Idtype:
1730                 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]);
1731                 break;
1732         case Procctl:
1733                 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]);
1734                 break;
1735         case Umtxop:
1736                 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]);
1737                 break;
1738         case Atfd:
1739                 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]);
1740                 break;
1741         case Atflags:
1742                 fputs(xlookup_bits(at_flags, args[sc->offset]), fp);
1743                 break;
1744         case Accessmode:
1745                 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]);
1746                 break;
1747         case Sysarch:
1748                 fputs(xlookup(sysarch_ops, args[sc->offset]), fp);
1749                 break;
1750         case PipeFds:
1751                 /*
1752                  * The pipe() system call in the kernel returns its
1753                  * two file descriptors via return values.  However,
1754                  * the interface exposed by libc is that pipe()
1755                  * accepts a pointer to an array of descriptors.
1756                  * Format the output to match the libc API by printing
1757                  * the returned file descriptors as a fake argument.
1758                  *
1759                  * Overwrite the first retval to signal a successful
1760                  * return as well.
1761                  */
1762                 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
1763                 retval[0] = 0;
1764                 break;
1765         case Utrace: {
1766                 size_t len;
1767                 void *utrace_addr;
1768
1769                 len = args[sc->offset + 1];
1770                 utrace_addr = calloc(1, len);
1771                 if (get_struct(pid, (void *)args[sc->offset],
1772                     (void *)utrace_addr, len) != -1)
1773                         print_utrace(fp, utrace_addr, len);
1774                 else
1775                         fprintf(fp, "0x%lx", args[sc->offset]);
1776                 free(utrace_addr);
1777                 break;
1778         }
1779         case IntArray: {
1780                 int descriptors[16];
1781                 unsigned long i, ndescriptors;
1782                 bool truncated;
1783
1784                 ndescriptors = args[sc->offset + 1];
1785                 truncated = false;
1786                 if (ndescriptors > nitems(descriptors)) {
1787                         ndescriptors = nitems(descriptors);
1788                         truncated = true;
1789                 }
1790                 if (get_struct(pid, (void *)args[sc->offset],
1791                     descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
1792                         fprintf(fp, "{");
1793                         for (i = 0; i < ndescriptors; i++)
1794                                 fprintf(fp, i == 0 ? " %d" : ", %d",
1795                                     descriptors[i]);
1796                         fprintf(fp, truncated ? ", ... }" : " }");
1797                 } else
1798                         fprintf(fp, "0x%lx", args[sc->offset]);
1799                 break;
1800         }
1801         case Pipe2:
1802                 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]);
1803                 break;
1804
1805         case CloudABIAdvice:
1806                 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
1807                 break;
1808         case CloudABIClockID:
1809                 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
1810                 break;
1811         case ClouduABIFDSFlags:
1812                 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
1813                 break;
1814         case CloudABIFDStat: {
1815                 cloudabi_fdstat_t fds;
1816                 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds))
1817                     != -1) {
1818                         fprintf(fp, "{ %s, ",
1819                             xlookup(cloudabi_filetype, fds.fs_filetype));
1820                         fprintf(fp, "%s, ... }",
1821                             xlookup_bits(cloudabi_fdflags, fds.fs_flags));
1822                 } else
1823                         fprintf(fp, "0x%lx", args[sc->offset]);
1824                 break;
1825         }
1826         case CloudABIFileStat: {
1827                 cloudabi_filestat_t fsb;
1828                 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb))
1829                     != -1)
1830                         fprintf(fp, "{ %s, %ju }",
1831                             xlookup(cloudabi_filetype, fsb.st_filetype),
1832                             (uintmax_t)fsb.st_size);
1833                 else
1834                         fprintf(fp, "0x%lx", args[sc->offset]);
1835                 break;
1836         }
1837         case CloudABIFileType:
1838                 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
1839                 break;
1840         case CloudABIFSFlags:
1841                 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
1842                 break;
1843         case CloudABILookup:
1844                 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
1845                         fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
1846                             (int)args[sc->offset]);
1847                 else
1848                         fprintf(fp, "%d", (int)args[sc->offset]);
1849                 break;
1850         case CloudABIMFlags:
1851                 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
1852                 break;
1853         case CloudABIMProt:
1854                 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
1855                 break;
1856         case CloudABIMSFlags:
1857                 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
1858                 break;
1859         case CloudABIOFlags:
1860                 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
1861                 break;
1862         case CloudABISDFlags:
1863                 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
1864                 break;
1865         case CloudABISignal:
1866                 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
1867                 break;
1868         case CloudABISockStat: {
1869                 cloudabi_sockstat_t ss;
1870                 if (get_struct(pid, (void *)args[sc->offset], &ss, sizeof(ss))
1871                     != -1) {
1872                         fprintf(fp, "{ %s, ", xlookup(
1873                             cloudabi_sa_family, ss.ss_sockname.sa_family));
1874                         fprintf(fp, "%s, ", xlookup(
1875                             cloudabi_sa_family, ss.ss_peername.sa_family));
1876                         fprintf(fp, "%s, ", xlookup(
1877                             cloudabi_errno, ss.ss_error));
1878                         fprintf(fp, "%s }", xlookup_bits(
1879                             cloudabi_ssstate, ss.ss_state));
1880                 } else
1881                         fprintf(fp, "0x%lx", args[sc->offset]);
1882                 break;
1883         }
1884         case CloudABISSFlags:
1885                 fputs(xlookup_bits(cloudabi_ssflags, args[sc->offset]), fp);
1886                 break;
1887         case CloudABITimestamp:
1888                 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
1889                     args[sc->offset] % 1000000000);
1890                 break;
1891         case CloudABIULFlags:
1892                 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
1893                 break;
1894         case CloudABIWhence:
1895                 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
1896                 break;
1897
1898         default:
1899                 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
1900         }
1901         fclose(fp);
1902         return (tmp);
1903 }
1904
1905 /*
1906  * Print (to outfile) the system call and its arguments.
1907  */
1908 void
1909 print_syscall(struct trussinfo *trussinfo)
1910 {
1911         struct threadinfo *t;
1912         const char *name;
1913         char **s_args;
1914         int i, len, nargs;
1915
1916         t = trussinfo->curthread;
1917
1918         name = t->cs.sc->name;
1919         nargs = t->cs.nargs;
1920         s_args = t->cs.s_args;
1921
1922         len = print_line_prefix(trussinfo);
1923         len += fprintf(trussinfo->outfile, "%s(", name);
1924
1925         for (i = 0; i < nargs; i++) {
1926                 if (s_args[i] != NULL)
1927                         len += fprintf(trussinfo->outfile, "%s", s_args[i]);
1928                 else
1929                         len += fprintf(trussinfo->outfile,
1930                             "<missing argument>");
1931                 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
1932                     "," : "");
1933         }
1934         len += fprintf(trussinfo->outfile, ")");
1935         for (i = 0; i < 6 - (len / 8); i++)
1936                 fprintf(trussinfo->outfile, "\t");
1937 }
1938
1939 void
1940 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
1941 {
1942         struct timespec timediff;
1943         struct threadinfo *t;
1944         struct syscall *sc;
1945         int error;
1946
1947         t = trussinfo->curthread;
1948         sc = t->cs.sc;
1949         if (trussinfo->flags & COUNTONLY) {
1950                 timespecsubt(&t->after, &t->before, &timediff);
1951                 timespecadd(&sc->time, &timediff, &sc->time);
1952                 sc->ncalls++;
1953                 if (errorp)
1954                         sc->nerror++;
1955                 return;
1956         }
1957
1958         print_syscall(trussinfo);
1959         fflush(trussinfo->outfile);
1960
1961         if (retval == NULL) {
1962                 /*
1963                  * This system call resulted in the current thread's exit,
1964                  * so there is no return value or error to display.
1965                  */
1966                 fprintf(trussinfo->outfile, "\n");
1967                 return;
1968         }
1969
1970         if (errorp) {
1971                 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi,
1972                     retval[0]);
1973                 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
1974                     error == INT_MAX ? "Unknown error" : strerror(error));
1975         }
1976 #ifndef __LP64__
1977         else if (sc->ret_type == 2) {
1978                 off_t off;
1979
1980 #if _BYTE_ORDER == _LITTLE_ENDIAN
1981                 off = (off_t)retval[1] << 32 | retval[0];
1982 #else
1983                 off = (off_t)retval[0] << 32 | retval[1];
1984 #endif
1985                 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
1986                     (intmax_t)off);
1987         }
1988 #endif
1989         else
1990                 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
1991                     retval[0]);
1992 }
1993
1994 void
1995 print_summary(struct trussinfo *trussinfo)
1996 {
1997         struct timespec total = {0, 0};
1998         struct syscall *sc;
1999         int ncall, nerror;
2000
2001         fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2002             "syscall", "seconds", "calls", "errors");
2003         ncall = nerror = 0;
2004         STAILQ_FOREACH(sc, &syscalls, entries)
2005                 if (sc->ncalls) {
2006                         fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2007                             sc->name, (intmax_t)sc->time.tv_sec,
2008                             sc->time.tv_nsec, sc->ncalls, sc->nerror);
2009                         timespecadd(&total, &sc->time, &total);
2010                         ncall += sc->ncalls;
2011                         nerror += sc->nerror;
2012                 }
2013         fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2014             "", "-------------", "-------", "-------");
2015         fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2016             "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);
2017 }