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