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