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