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