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