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