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