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