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