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