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