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