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