xref: /freebsd/usr.bin/truss/syscalls.c (revision dd41de95a84d979615a2ef11df6850622bf6184e)
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/ptrace.h>
52 #include <sys/resource.h>
53 #include <sys/sched.h>
54 #include <sys/socket.h>
55 #define _WANT_FREEBSD11_STAT
56 #include <sys/stat.h>
57 #include <sys/sysctl.h>
58 #include <sys/time.h>
59 #include <sys/un.h>
60 #include <sys/wait.h>
61 #include <netinet/in.h>
62 #include <netinet/sctp.h>
63 #include <arpa/inet.h>
64 
65 #include <assert.h>
66 #include <ctype.h>
67 #include <err.h>
68 #define _WANT_KERNEL_ERRNO
69 #include <errno.h>
70 #include <fcntl.h>
71 #include <signal.h>
72 #include <stdbool.h>
73 #include <stdio.h>
74 #include <stdlib.h>
75 #include <string.h>
76 #include <sysdecode.h>
77 #include <unistd.h>
78 #include <vis.h>
79 
80 #include <contrib/cloudabi/cloudabi_types_common.h>
81 
82 #include "truss.h"
83 #include "extern.h"
84 #include "syscall.h"
85 
86 /*
87  * This should probably be in its own file, sorted alphabetically.
88  *
89  * Note: We only scan this table on the initial syscall number to calling
90  * convention lookup, i.e. once each time a new syscall is encountered. This
91  * is unlikely to be a performance issue, but if it is we could sort this array
92  * and use a binary search instead.
93  */
94 static const struct syscall_decode decoded_syscalls[] = {
95 	/* Native ABI */
96 	{ .name = "__acl_aclcheck_fd", .ret_type = 1, .nargs = 3,
97 	  .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
98 	{ .name = "__acl_aclcheck_file", .ret_type = 1, .nargs = 3,
99 	  .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
100 	{ .name = "__acl_aclcheck_link", .ret_type = 1, .nargs = 3,
101 	  .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
102 	{ .name = "__acl_delete_fd", .ret_type = 1, .nargs = 2,
103 	  .args = { { Int, 0 }, { Acltype, 1 } } },
104 	{ .name = "__acl_delete_file", .ret_type = 1, .nargs = 2,
105 	  .args = { { Name, 0 }, { Acltype, 1 } } },
106 	{ .name = "__acl_delete_link", .ret_type = 1, .nargs = 2,
107 	  .args = { { Name, 0 }, { Acltype, 1 } } },
108 	{ .name = "__acl_get_fd", .ret_type = 1, .nargs = 3,
109 	  .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
110 	{ .name = "__acl_get_file", .ret_type = 1, .nargs = 3,
111 	  .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
112 	{ .name = "__acl_get_link", .ret_type = 1, .nargs = 3,
113 	  .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
114 	{ .name = "__acl_set_fd", .ret_type = 1, .nargs = 3,
115 	  .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
116 	{ .name = "__acl_set_file", .ret_type = 1, .nargs = 3,
117 	  .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
118 	{ .name = "__acl_set_link", .ret_type = 1, .nargs = 3,
119 	  .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
120 	{ .name = "__cap_rights_get", .ret_type = 1, .nargs = 3,
121 	  .args = { { Int, 0 }, { Int, 1 }, { CapRights | OUT, 2 } } },
122 	{ .name = "__getcwd", .ret_type = 1, .nargs = 2,
123 	  .args = { { Name | OUT, 0 }, { Int, 1 } } },
124 	{ .name = "__realpathat", .ret_type = 1, .nargs = 5,
125 	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Name | OUT, 2 },
126 		    { Sizet, 3 }, { Int, 4} } },
127 	{ .name = "_umtx_op", .ret_type = 1, .nargs = 5,
128 	  .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
129 		    { Ptr, 4 } } },
130 	{ .name = "accept", .ret_type = 1, .nargs = 3,
131 	  .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
132 	{ .name = "access", .ret_type = 1, .nargs = 2,
133 	  .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
134 	{ .name = "aio_cancel", .ret_type = 1, .nargs = 2,
135 	  .args = { { Int, 0 }, { Aiocb, 1 } } },
136 	{ .name = "aio_error", .ret_type = 1, .nargs = 1,
137 	  .args = { { Aiocb, 0 } } },
138 	{ .name = "aio_fsync", .ret_type = 1, .nargs = 2,
139 	  .args = { { AiofsyncOp, 0 }, { Aiocb, 1 } } },
140 	{ .name = "aio_mlock", .ret_type = 1, .nargs = 1,
141 	  .args = { { Aiocb, 0 } } },
142 	{ .name = "aio_read", .ret_type = 1, .nargs = 1,
143 	  .args = { { Aiocb, 0 } } },
144 	{ .name = "aio_return", .ret_type = 1, .nargs = 1,
145 	  .args = { { Aiocb, 0 } } },
146 	{ .name = "aio_suspend", .ret_type = 1, .nargs = 3,
147 	  .args = { { AiocbArray, 0 }, { Int, 1 }, { Timespec, 2 } } },
148 	{ .name = "aio_waitcomplete", .ret_type = 1, .nargs = 2,
149 	  .args = { { AiocbPointer | OUT, 0 }, { Timespec, 1 } } },
150 	{ .name = "aio_write", .ret_type = 1, .nargs = 1,
151 	  .args = { { Aiocb, 0 } } },
152 	{ .name = "bind", .ret_type = 1, .nargs = 3,
153 	  .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
154 	{ .name = "bindat", .ret_type = 1, .nargs = 4,
155 	  .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
156 		    { Int, 3 } } },
157 	{ .name = "break", .ret_type = 1, .nargs = 1,
158 	  .args = { { Ptr, 0 } } },
159 	{ .name = "cap_fcntls_get", .ret_type = 1, .nargs = 2,
160 	  .args = { { Int, 0 }, { CapFcntlRights | OUT, 1 } } },
161 	{ .name = "cap_fcntls_limit", .ret_type = 1, .nargs = 2,
162 	  .args = { { Int, 0 }, { CapFcntlRights, 1 } } },
163 	{ .name = "cap_getmode", .ret_type = 1, .nargs = 1,
164 	  .args = { { PUInt | OUT, 0 } } },
165 	{ .name = "cap_rights_limit", .ret_type = 1, .nargs = 2,
166 	  .args = { { Int, 0 }, { CapRights, 1 } } },
167 	{ .name = "chdir", .ret_type = 1, .nargs = 1,
168 	  .args = { { Name, 0 } } },
169 	{ .name = "chflags", .ret_type = 1, .nargs = 2,
170 	  .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
171 	{ .name = "chflagsat", .ret_type = 1, .nargs = 4,
172 	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { FileFlags, 2 },
173 		    { Atflags, 3 } } },
174 	{ .name = "chmod", .ret_type = 1, .nargs = 2,
175 	  .args = { { Name, 0 }, { Octal, 1 } } },
176 	{ .name = "chown", .ret_type = 1, .nargs = 3,
177 	  .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
178 	{ .name = "chroot", .ret_type = 1, .nargs = 1,
179 	  .args = { { Name, 0 } } },
180 	{ .name = "clock_gettime", .ret_type = 1, .nargs = 2,
181 	  .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
182 	{ .name = "close", .ret_type = 1, .nargs = 1,
183 	  .args = { { Int, 0 } } },
184 	{ .name = "closefrom", .ret_type = 1, .nargs = 1,
185 	  .args = { { Int, 0 } } },
186 	{ .name = "compat11.fstat", .ret_type = 1, .nargs = 2,
187 	  .args = { { Int, 0 }, { Stat11 | OUT, 1 } } },
188 	{ .name = "compat11.fstatat", .ret_type = 1, .nargs = 4,
189 	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat11 | OUT, 2 },
190 		    { Atflags, 3 } } },
191 	{ .name = "compat11.kevent", .ret_type = 1, .nargs = 6,
192 	  .args = { { Int, 0 }, { Kevent11, 1 }, { Int, 2 },
193 		    { Kevent11 | OUT, 3 }, { Int, 4 }, { Timespec, 5 } } },
194 	{ .name = "compat11.lstat", .ret_type = 1, .nargs = 2,
195 	  .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } },
196 	{ .name = "compat11.mknod", .ret_type = 1, .nargs = 3,
197 	  .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
198 	{ .name = "compat11.mknodat", .ret_type = 1, .nargs = 4,
199 	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
200 	{ .name = "compat11.stat", .ret_type = 1, .nargs = 2,
201 	  .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } },
202 	{ .name = "connect", .ret_type = 1, .nargs = 3,
203 	  .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
204 	{ .name = "connectat", .ret_type = 1, .nargs = 4,
205 	  .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
206 		    { Int, 3 } } },
207 	{ .name = "dup", .ret_type = 1, .nargs = 1,
208 	  .args = { { Int, 0 } } },
209 	{ .name = "dup2", .ret_type = 1, .nargs = 2,
210 	  .args = { { Int, 0 }, { Int, 1 } } },
211 	{ .name = "eaccess", .ret_type = 1, .nargs = 2,
212 	  .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
213 	{ .name = "execve", .ret_type = 1, .nargs = 3,
214 	  .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
215 		    { ExecEnv | IN, 2 } } },
216 	{ .name = "exit", .ret_type = 0, .nargs = 1,
217 	  .args = { { Hex, 0 } } },
218 	{ .name = "extattr_delete_fd", .ret_type = 1, .nargs = 3,
219 	  .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
220 	{ .name = "extattr_delete_file", .ret_type = 1, .nargs = 3,
221 	  .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
222 	{ .name = "extattr_delete_link", .ret_type = 1, .nargs = 3,
223 	  .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
224 	{ .name = "extattr_get_fd", .ret_type = 1, .nargs = 5,
225 	  .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
226 		    { BinString | OUT, 3 }, { Sizet, 4 } } },
227 	{ .name = "extattr_get_file", .ret_type = 1, .nargs = 5,
228 	  .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
229 		    { BinString | OUT, 3 }, { Sizet, 4 } } },
230 	{ .name = "extattr_get_link", .ret_type = 1, .nargs = 5,
231 	  .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
232 		    { BinString | OUT, 3 }, { Sizet, 4 } } },
233 	{ .name = "extattr_list_fd", .ret_type = 1, .nargs = 4,
234 	  .args = { { Int, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
235 		    { Sizet, 3 } } },
236 	{ .name = "extattr_list_file", .ret_type = 1, .nargs = 4,
237 	  .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
238 		    { Sizet, 3 } } },
239 	{ .name = "extattr_list_link", .ret_type = 1, .nargs = 4,
240 	  .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
241 		    { Sizet, 3 } } },
242 	{ .name = "extattr_set_fd", .ret_type = 1, .nargs = 5,
243 	  .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
244 		    { BinString | IN, 3 }, { Sizet, 4 } } },
245 	{ .name = "extattr_set_file", .ret_type = 1, .nargs = 5,
246 	  .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
247 		    { BinString | IN, 3 }, { Sizet, 4 } } },
248 	{ .name = "extattr_set_link", .ret_type = 1, .nargs = 5,
249 	  .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
250 		    { BinString | IN, 3 }, { Sizet, 4 } } },
251 	{ .name = "extattrctl", .ret_type = 1, .nargs = 5,
252 	  .args = { { Name, 0 }, { Hex, 1 }, { Name, 2 },
253 		    { Extattrnamespace, 3 }, { Name, 4 } } },
254 	{ .name = "faccessat", .ret_type = 1, .nargs = 4,
255 	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
256 		    { Atflags, 3 } } },
257 	{ .name = "fchflags", .ret_type = 1, .nargs = 2,
258 	  .args = { { Int, 0 }, { FileFlags, 1 } } },
259 	{ .name = "fchmod", .ret_type = 1, .nargs = 2,
260 	  .args = { { Int, 0 }, { Octal, 1 } } },
261 	{ .name = "fchmodat", .ret_type = 1, .nargs = 4,
262 	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
263 	{ .name = "fchown", .ret_type = 1, .nargs = 3,
264 	  .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
265 	{ .name = "fchownat", .ret_type = 1, .nargs = 5,
266 	  .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
267 		    { Atflags, 4 } } },
268 	{ .name = "fcntl", .ret_type = 1, .nargs = 3,
269 	  .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
270 	{ .name = "fdatasync", .ret_type = 1, .nargs = 1,
271 	  .args = { { Int, 0 } } },
272 	{ .name = "flock", .ret_type = 1, .nargs = 2,
273 	  .args = { { Int, 0 }, { Flockop, 1 } } },
274 	{ .name = "fstat", .ret_type = 1, .nargs = 2,
275 	  .args = { { Int, 0 }, { Stat | OUT, 1 } } },
276 	{ .name = "fstatat", .ret_type = 1, .nargs = 4,
277 	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
278 		    { Atflags, 3 } } },
279 	{ .name = "fstatfs", .ret_type = 1, .nargs = 2,
280 	  .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
281 	{ .name = "fsync", .ret_type = 1, .nargs = 1,
282 	  .args = { { Int, 0 } } },
283 	{ .name = "ftruncate", .ret_type = 1, .nargs = 2,
284 	  .args = { { Int | IN, 0 }, { QuadHex | IN, 1 } } },
285 	{ .name = "futimens", .ret_type = 1, .nargs = 2,
286 	  .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
287 	{ .name = "futimes", .ret_type = 1, .nargs = 2,
288 	  .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
289 	{ .name = "futimesat", .ret_type = 1, .nargs = 3,
290 	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
291 	{ .name = "getdirentries", .ret_type = 1, .nargs = 4,
292 	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
293 		    { PQuadHex | OUT, 3 } } },
294 	{ .name = "getfsstat", .ret_type = 1, .nargs = 3,
295 	  .args = { { Ptr, 0 }, { Long, 1 }, { Getfsstatmode, 2 } } },
296 	{ .name = "getitimer", .ret_type = 1, .nargs = 2,
297 	  .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
298 	{ .name = "getpeername", .ret_type = 1, .nargs = 3,
299 	  .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
300 	{ .name = "getpgid", .ret_type = 1, .nargs = 1,
301 	  .args = { { Int, 0 } } },
302 	{ .name = "getpriority", .ret_type = 1, .nargs = 2,
303 	  .args = { { Priowhich, 0 }, { Int, 1 } } },
304 	{ .name = "getrandom", .ret_type = 1, .nargs = 3,
305 	  .args = { { BinString | OUT, 0 }, { Sizet, 1 }, { UInt, 2 } } },
306 	{ .name = "getrlimit", .ret_type = 1, .nargs = 2,
307 	  .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
308 	{ .name = "getrusage", .ret_type = 1, .nargs = 2,
309 	  .args = { { RusageWho, 0 }, { Rusage | OUT, 1 } } },
310 	{ .name = "getsid", .ret_type = 1, .nargs = 1,
311 	  .args = { { Int, 0 } } },
312 	{ .name = "getsockname", .ret_type = 1, .nargs = 3,
313 	  .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
314 	{ .name = "getsockopt", .ret_type = 1, .nargs = 5,
315 	  .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
316 		    { Ptr | OUT, 3 }, { Ptr | OUT, 4 } } },
317 	{ .name = "gettimeofday", .ret_type = 1, .nargs = 2,
318 	  .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
319 	{ .name = "ioctl", .ret_type = 1, .nargs = 3,
320 	  .args = { { Int, 0 }, { Ioctl, 1 }, { Ptr, 2 } } },
321 	{ .name = "kevent", .ret_type = 1, .nargs = 6,
322 	  .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
323 		    { Int, 4 }, { Timespec, 5 } } },
324 	{ .name = "kill", .ret_type = 1, .nargs = 2,
325 	  .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
326 	{ .name = "kldfind", .ret_type = 1, .nargs = 1,
327 	  .args = { { Name | IN, 0 } } },
328 	{ .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
329 	  .args = { { Int, 0 } } },
330 	{ .name = "kldload", .ret_type = 1, .nargs = 1,
331 	  .args = { { Name | IN, 0 } } },
332 	{ .name = "kldnext", .ret_type = 1, .nargs = 1,
333 	  .args = { { Int, 0 } } },
334 	{ .name = "kldstat", .ret_type = 1, .nargs = 2,
335 	  .args = { { Int, 0 }, { Ptr, 1 } } },
336 	{ .name = "kldsym", .ret_type = 1, .nargs = 3,
337 	  .args = { { Int, 0 }, { Kldsymcmd, 1 }, { Ptr, 2 } } },
338 	{ .name = "kldunload", .ret_type = 1, .nargs = 1,
339 	  .args = { { Int, 0 } } },
340 	{ .name = "kldunloadf", .ret_type = 1, .nargs = 2,
341 	  .args = { { Int, 0 }, { Kldunloadflags, 1 } } },
342 	{ .name = "kse_release", .ret_type = 0, .nargs = 1,
343 	  .args = { { Timespec, 0 } } },
344 	{ .name = "lchflags", .ret_type = 1, .nargs = 2,
345 	  .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
346 	{ .name = "lchmod", .ret_type = 1, .nargs = 2,
347 	  .args = { { Name, 0 }, { Octal, 1 } } },
348 	{ .name = "lchown", .ret_type = 1, .nargs = 3,
349 	  .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
350 	{ .name = "link", .ret_type = 1, .nargs = 2,
351 	  .args = { { Name, 0 }, { Name, 1 } } },
352 	{ .name = "linkat", .ret_type = 1, .nargs = 5,
353 	  .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
354 		    { Atflags, 4 } } },
355 	{ .name = "lio_listio", .ret_type = 1, .nargs = 4,
356 	  .args = { { LioMode, 0 }, { AiocbArray, 1 }, { Int, 2 },
357 		    { Sigevent, 3 } } },
358 	{ .name = "listen", .ret_type = 1, .nargs = 2,
359 	  .args = { { Int, 0 }, { Int, 1 } } },
360  	{ .name = "lseek", .ret_type = 2, .nargs = 3,
361 	  .args = { { Int, 0 }, { QuadHex, 1 }, { Whence, 2 } } },
362 	{ .name = "lstat", .ret_type = 1, .nargs = 2,
363 	  .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
364 	{ .name = "lutimes", .ret_type = 1, .nargs = 2,
365 	  .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
366 	{ .name = "madvise", .ret_type = 1, .nargs = 3,
367 	  .args = { { Ptr, 0 }, { Sizet, 1 }, { Madvice, 2 } } },
368 	{ .name = "minherit", .ret_type = 1, .nargs = 3,
369 	  .args = { { Ptr, 0 }, { Sizet, 1 }, { Minherit, 2 } } },
370 	{ .name = "mkdir", .ret_type = 1, .nargs = 2,
371 	  .args = { { Name, 0 }, { Octal, 1 } } },
372 	{ .name = "mkdirat", .ret_type = 1, .nargs = 3,
373 	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
374 	{ .name = "mkfifo", .ret_type = 1, .nargs = 2,
375 	  .args = { { Name, 0 }, { Octal, 1 } } },
376 	{ .name = "mkfifoat", .ret_type = 1, .nargs = 3,
377 	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
378 	{ .name = "mknod", .ret_type = 1, .nargs = 3,
379 	  .args = { { Name, 0 }, { Octal, 1 }, { Quad, 2 } } },
380 	{ .name = "mknodat", .ret_type = 1, .nargs = 4,
381 	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Quad, 3 } } },
382 	{ .name = "mlock", .ret_type = 1, .nargs = 2,
383 	  .args = { { Ptr, 0 }, { Sizet, 1 } } },
384 	{ .name = "mlockall", .ret_type = 1, .nargs = 1,
385 	  .args = { { Mlockall, 0 } } },
386 	{ .name = "mmap", .ret_type = 1, .nargs = 6,
387 	  .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
388 		    { Int, 4 }, { QuadHex, 5 } } },
389 	{ .name = "modfind", .ret_type = 1, .nargs = 1,
390 	  .args = { { Name | IN, 0 } } },
391 	{ .name = "mount", .ret_type = 1, .nargs = 4,
392 	  .args = { { Name, 0 }, { Name, 1 }, { Mountflags, 2 }, { Ptr, 3 } } },
393 	{ .name = "mprotect", .ret_type = 1, .nargs = 3,
394 	  .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 } } },
395 	{ .name = "msync", .ret_type = 1, .nargs = 3,
396 	  .args = { { Ptr, 0 }, { Sizet, 1 }, { Msync, 2 } } },
397 	{ .name = "munlock", .ret_type = 1, .nargs = 2,
398 	  .args = { { Ptr, 0 }, { Sizet, 1 } } },
399 	{ .name = "munmap", .ret_type = 1, .nargs = 2,
400 	  .args = { { Ptr, 0 }, { Sizet, 1 } } },
401 	{ .name = "nanosleep", .ret_type = 1, .nargs = 1,
402 	  .args = { { Timespec, 0 } } },
403 	{ .name = "nmount", .ret_type = 1, .nargs = 3,
404 	  .args = { { Ptr, 0 }, { UInt, 1 }, { Mountflags, 2 } } },
405 	{ .name = "open", .ret_type = 1, .nargs = 3,
406 	  .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
407 	{ .name = "openat", .ret_type = 1, .nargs = 4,
408 	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
409 		    { Octal, 3 } } },
410 	{ .name = "pathconf", .ret_type = 1, .nargs = 2,
411 	  .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
412 	{ .name = "pipe", .ret_type = 1, .nargs = 1,
413 	  .args = { { PipeFds | OUT, 0 } } },
414 	{ .name = "pipe2", .ret_type = 1, .nargs = 2,
415 	  .args = { { Ptr, 0 }, { Pipe2, 1 } } },
416 	{ .name = "poll", .ret_type = 1, .nargs = 3,
417 	  .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
418 	{ .name = "posix_fadvise", .ret_type = 1, .nargs = 4,
419 	  .args = { { Int, 0 }, { QuadHex, 1 }, { QuadHex, 2 },
420 		    { Fadvice, 3 } } },
421 	{ .name = "posix_openpt", .ret_type = 1, .nargs = 1,
422 	  .args = { { Open, 0 } } },
423 	{ .name = "pread", .ret_type = 1, .nargs = 4,
424 	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
425 		    { QuadHex, 3 } } },
426 	{ .name = "procctl", .ret_type = 1, .nargs = 4,
427 	  .args = { { Idtype, 0 }, { Quad, 1 }, { Procctl, 2 }, { Ptr, 3 } } },
428 	{ .name = "ptrace", .ret_type = 1, .nargs = 4,
429 	  .args = { { Ptraceop, 0 }, { Int, 1 }, { Ptr, 2 }, { Int, 3 } } },
430 	{ .name = "pwrite", .ret_type = 1, .nargs = 4,
431 	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
432 		    { QuadHex, 3 } } },
433 	{ .name = "quotactl", .ret_type = 1, .nargs = 4,
434 	  .args = { { Name, 0 }, { Quotactlcmd, 1 }, { Int, 2 }, { Ptr, 3 } } },
435 	{ .name = "read", .ret_type = 1, .nargs = 3,
436 	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 } } },
437 	{ .name = "readlink", .ret_type = 1, .nargs = 3,
438 	  .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Sizet, 2 } } },
439 	{ .name = "readlinkat", .ret_type = 1, .nargs = 4,
440 	  .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
441 		    { Sizet, 3 } } },
442 	{ .name = "readv", .ret_type = 1, .nargs = 3,
443 	  .args = { { Int, 0 }, { Iovec | OUT, 1 }, { Int, 2 } } },
444 	{ .name = "reboot", .ret_type = 1, .nargs = 1,
445 	  .args = { { Reboothowto, 0 } } },
446 	{ .name = "recvfrom", .ret_type = 1, .nargs = 6,
447 	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
448 	            { Msgflags, 3 }, { Sockaddr | OUT, 4 },
449 	            { Ptr | OUT, 5 } } },
450 	{ .name = "recvmsg", .ret_type = 1, .nargs = 3,
451 	  .args = { { Int, 0 }, { Msghdr | OUT, 1 }, { Msgflags, 2 } } },
452 	{ .name = "rename", .ret_type = 1, .nargs = 2,
453 	  .args = { { Name, 0 }, { Name, 1 } } },
454 	{ .name = "renameat", .ret_type = 1, .nargs = 4,
455 	  .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
456 	{ .name = "rfork", .ret_type = 1, .nargs = 1,
457 	  .args = { { Rforkflags, 0 } } },
458 	{ .name = "rmdir", .ret_type = 1, .nargs = 1,
459 	  .args = { { Name, 0 } } },
460 	{ .name = "rtprio", .ret_type = 1, .nargs = 3,
461 	  .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
462 	{ .name = "rtprio_thread", .ret_type = 1, .nargs = 3,
463 	  .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
464 	{ .name = "sched_get_priority_max", .ret_type = 1, .nargs = 1,
465 	  .args = { { Schedpolicy, 0 } } },
466 	{ .name = "sched_get_priority_min", .ret_type = 1, .nargs = 1,
467 	  .args = { { Schedpolicy, 0 } } },
468 	{ .name = "sched_getparam", .ret_type = 1, .nargs = 2,
469 	  .args = { { Int, 0 }, { Schedparam | OUT, 1 } } },
470 	{ .name = "sched_getscheduler", .ret_type = 1, .nargs = 1,
471 	  .args = { { Int, 0 } } },
472 	{ .name = "sched_rr_get_interval", .ret_type = 1, .nargs = 2,
473 	  .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
474 	{ .name = "sched_setparam", .ret_type = 1, .nargs = 2,
475 	  .args = { { Int, 0 }, { Schedparam, 1 } } },
476 	{ .name = "sched_setscheduler", .ret_type = 1, .nargs = 3,
477 	  .args = { { Int, 0 }, { Schedpolicy, 1 }, { Schedparam, 2 } } },
478 	{ .name = "sctp_generic_recvmsg", .ret_type = 1, .nargs = 7,
479 	  .args = { { Int, 0 }, { Iovec | OUT, 1 }, { Int, 2 },
480 	            { Sockaddr | OUT, 3 }, { Ptr | OUT, 4 },
481 	            { Sctpsndrcvinfo | OUT, 5 }, { Ptr | OUT, 6 } } },
482 	{ .name = "sctp_generic_sendmsg", .ret_type = 1, .nargs = 7,
483 	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
484 	            { Sockaddr | IN, 3 }, { Socklent, 4 },
485 	            { Sctpsndrcvinfo | IN, 5 }, { Msgflags, 6 } } },
486 	{ .name = "sctp_generic_sendmsg_iov", .ret_type = 1, .nargs = 7,
487 	  .args = { { Int, 0 }, { Iovec | IN, 1 }, { Int, 2 },
488 	            { Sockaddr | IN, 3 }, { Socklent, 4 },
489 	            { Sctpsndrcvinfo | IN, 5 }, { Msgflags, 6 } } },
490 	{ .name = "sendfile", .ret_type = 1, .nargs = 7,
491 	  .args = { { Int, 0 }, { Int, 1 }, { QuadHex, 2 }, { Sizet, 3 },
492 		    { Sendfilehdtr, 4 }, { QuadHex | OUT, 5 },
493 		    { Sendfileflags, 6 } } },
494 	{ .name = "select", .ret_type = 1, .nargs = 5,
495 	  .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
496 		    { Timeval, 4 } } },
497 	{ .name = "sendmsg", .ret_type = 1, .nargs = 3,
498 	  .args = { { Int, 0 }, { Msghdr | IN, 1 }, { Msgflags, 2 } } },
499 	{ .name = "sendto", .ret_type = 1, .nargs = 6,
500 	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
501 	            { Msgflags, 3 }, { Sockaddr | IN, 4 },
502 	            { Socklent | IN, 5 } } },
503 	{ .name = "setitimer", .ret_type = 1, .nargs = 3,
504 	  .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
505 	{ .name = "setpriority", .ret_type = 1, .nargs = 3,
506 	  .args = { { Priowhich, 0 }, { Int, 1 }, { Int, 2 } } },
507 	{ .name = "setrlimit", .ret_type = 1, .nargs = 2,
508 	  .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
509 	{ .name = "setsockopt", .ret_type = 1, .nargs = 5,
510 	  .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
511 		    { Ptr | IN, 3 }, { Socklent, 4 } } },
512 	{ .name = "shm_open", .ret_type = 1, .nargs = 3,
513 	  .args = { { ShmName | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
514 	{ .name = "shm_open2", .ret_type = 1, .nargs = 5,
515 	  .args = { { ShmName | IN, 0 }, { Open, 1 }, { Octal, 2 },
516 		    { ShmFlags, 3 }, { Name | IN, 4 } } },
517 	{ .name = "shm_rename", .ret_type = 1, .nargs = 3,
518 	  .args = { { Name | IN, 0 }, { Name | IN, 1 }, { Hex, 2 } } },
519 	{ .name = "shm_unlink", .ret_type = 1, .nargs = 1,
520 	  .args = { { Name | IN, 0 } } },
521 	{ .name = "shutdown", .ret_type = 1, .nargs = 2,
522 	  .args = { { Int, 0 }, { Shutdown, 1 } } },
523 	{ .name = "sigaction", .ret_type = 1, .nargs = 3,
524 	  .args = { { Signal, 0 }, { Sigaction | IN, 1 },
525 		    { Sigaction | OUT, 2 } } },
526 	{ .name = "sigpending", .ret_type = 1, .nargs = 1,
527 	  .args = { { Sigset | OUT, 0 } } },
528 	{ .name = "sigprocmask", .ret_type = 1, .nargs = 3,
529 	  .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
530 	{ .name = "sigqueue", .ret_type = 1, .nargs = 3,
531 	  .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
532 	{ .name = "sigreturn", .ret_type = 1, .nargs = 1,
533 	  .args = { { Ptr, 0 } } },
534 	{ .name = "sigsuspend", .ret_type = 1, .nargs = 1,
535 	  .args = { { Sigset | IN, 0 } } },
536 	{ .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
537 	  .args = { { Sigset | IN, 0 }, { Siginfo | OUT, 1 },
538 		    { Timespec | IN, 2 } } },
539 	{ .name = "sigwait", .ret_type = 1, .nargs = 2,
540 	  .args = { { Sigset | IN, 0 }, { PSig | OUT, 1 } } },
541 	{ .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
542 	  .args = { { Sigset | IN, 0 }, { Siginfo | OUT, 1 } } },
543 	{ .name = "socket", .ret_type = 1, .nargs = 3,
544 	  .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Sockprotocol, 2 } } },
545 	{ .name = "stat", .ret_type = 1, .nargs = 2,
546 	  .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
547 	{ .name = "statfs", .ret_type = 1, .nargs = 2,
548 	  .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } },
549 	{ .name = "symlink", .ret_type = 1, .nargs = 2,
550 	  .args = { { Name, 0 }, { Name, 1 } } },
551 	{ .name = "symlinkat", .ret_type = 1, .nargs = 3,
552 	  .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } },
553 	{ .name = "sysarch", .ret_type = 1, .nargs = 2,
554 	  .args = { { Sysarch, 0 }, { Ptr, 1 } } },
555 	{ .name = "__sysctl", .ret_type = 1, .nargs = 6,
556 	  .args = { { Sysctl, 0 }, { Sizet, 1 }, { Ptr, 2 }, { Ptr, 3 },
557 	            { Ptr, 4 }, { Sizet, 5 } } },
558 	{ .name = "__sysctlbyname", .ret_type = 1, .nargs = 6,
559 	  .args = { { Name, 0 }, { Sizet, 1 }, { Ptr, 2 }, { Ptr, 3 },
560 	            { Ptr, 4}, { Sizet, 5 } } },
561 	{ .name = "thr_kill", .ret_type = 1, .nargs = 2,
562 	  .args = { { Long, 0 }, { Signal, 1 } } },
563 	{ .name = "thr_self", .ret_type = 1, .nargs = 1,
564 	  .args = { { Ptr, 0 } } },
565 	{ .name = "thr_set_name", .ret_type = 1, .nargs = 2,
566 	  .args = { { Long, 0 }, { Name, 1 } } },
567 	{ .name = "truncate", .ret_type = 1, .nargs = 2,
568 	  .args = { { Name | IN, 0 }, { QuadHex | IN, 1 } } },
569 #if 0
570 	/* Does not exist */
571 	{ .name = "umount", .ret_type = 1, .nargs = 2,
572 	  .args = { { Name, 0 }, { Int, 2 } } },
573 #endif
574 	{ .name = "unlink", .ret_type = 1, .nargs = 1,
575 	  .args = { { Name, 0 } } },
576 	{ .name = "unlinkat", .ret_type = 1, .nargs = 3,
577 	  .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
578 	{ .name = "unmount", .ret_type = 1, .nargs = 2,
579 	  .args = { { Name, 0 }, { Mountflags, 1 } } },
580 	{ .name = "utimensat", .ret_type = 1, .nargs = 4,
581 	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
582 		    { Atflags, 3 } } },
583 	{ .name = "utimes", .ret_type = 1, .nargs = 2,
584 	  .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
585 	{ .name = "utrace", .ret_type = 1, .nargs = 1,
586 	  .args = { { Utrace, 0 } } },
587 	{ .name = "wait4", .ret_type = 1, .nargs = 4,
588 	  .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
589 		    { Rusage | OUT, 3 } } },
590 	{ .name = "wait6", .ret_type = 1, .nargs = 6,
591 	  .args = { { Idtype, 0 }, { Quad, 1 }, { ExitStatus | OUT, 2 },
592 		    { Waitoptions, 3 }, { Rusage | OUT, 4 },
593 		    { Siginfo | OUT, 5 } } },
594 	{ .name = "write", .ret_type = 1, .nargs = 3,
595 	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 } } },
596 	{ .name = "writev", .ret_type = 1, .nargs = 3,
597 	  .args = { { Int, 0 }, { Iovec | IN, 1 }, { Int, 2 } } },
598 
599 	/* Linux ABI */
600 	{ .name = "linux_access", .ret_type = 1, .nargs = 2,
601 	  .args = { { Name, 0 }, { Accessmode, 1 } } },
602 	{ .name = "linux_execve", .ret_type = 1, .nargs = 3,
603 	  .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
604 		    { ExecEnv | IN, 2 } } },
605 	{ .name = "linux_lseek", .ret_type = 2, .nargs = 3,
606 	  .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
607 	{ .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
608 	  .args = { { Name | IN, 0 }, { Int, 1 } } },
609 	{ .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
610 	  .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
611 	{ .name = "linux_newstat", .ret_type = 1, .nargs = 2,
612 	  .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
613 	{ .name = "linux_open", .ret_type = 1, .nargs = 3,
614 	  .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
615 	{ .name = "linux_readlink", .ret_type = 1, .nargs = 3,
616 	  .args = { { Name, 0 }, { Name | OUT, 1 }, { Sizet, 2 } } },
617 	{ .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
618 	  .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
619 	{ .name = "linux_stat64", .ret_type = 1, .nargs = 2,
620 	  .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
621 
622 	/* CloudABI system calls. */
623 	{ .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
624 	  .args = { { CloudABIClockID, 0 } } },
625 	{ .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
626 	  .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
627 	{ .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
628 	  .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
629 	{ .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
630 	  .args = { { Int, 0 } } },
631 	{ .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
632 	  .args = { { CloudABIFileType, 0 } } },
633 	{ .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
634 	  .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
635 	{ .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
636 	  .args = { { Int, 0 } } },
637 	{ .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
638 	  .args = { { Int, 0 } } },
639 	{ .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
640 	  .args = { { Int, 0 }, { Int, 1 } } },
641 	{ .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
642 	  .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
643 	{ .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
644 	  .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
645 	{ .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
646 	  .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
647 	            { CloudABIFDSFlags, 2 } } },
648 	{ .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
649 	  .args = { { Int, 0 } } },
650 	{ .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
651 	  .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
652 	            { CloudABIAdvice, 3 } } },
653 	{ .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
654 	  .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
655 	{ .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
656 	  .args = { { Int, 0 }, { BinString | IN, 1 },
657 	            { CloudABIFileType, 3 } } },
658 	{ .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
659 	  .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
660 	            { Int, 3 }, { BinString | IN, 4 } } },
661 	{ .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
662 	  .args = { { Int, 0 }, { BinString | IN, 1 },
663 	            { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
664 	{ .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
665 	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
666 	            { Int, 3 } } },
667 	{ .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
668 	  .args = { { Int, 0 }, { BinString | IN, 1 },
669 	            { BinString | OUT, 3 }, { Int, 4 } } },
670 	{ .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
671 	  .args = { { Int, 0 }, { BinString | IN, 1 },
672 	            { Int, 3 }, { BinString | IN, 4 } } },
673 	{ .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
674 	  .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
675 	{ .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
676 	  .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
677 	            { CloudABIFSFlags, 2 } } },
678 	{ .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
679 	  .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
680 	            { CloudABIFileStat | OUT, 3 } } },
681 	{ .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
682 	  .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
683 	            { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
684 	{ .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
685 	  .args = { { BinString | IN, 0 },
686 	            { Int, 2 }, { BinString | IN, 3 } } },
687 	{ .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
688 	  .args = { { Int, 0 }, { BinString | IN, 1 },
689 	            { CloudABIULFlags, 3 } } },
690 	{ .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
691 	  .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
692 	{ .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
693 	  .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
694 	{ .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
695 	  .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
696 	            { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
697 	{ .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
698 	  .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
699 	{ .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
700 	  .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
701 	{ .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
702 	  .args = { { Ptr, 0 }, { Int, 1 } } },
703 	{ .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
704 	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
705 	            { IntArray, 3 }, { Int, 4 } } },
706 	{ .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
707 	  .args = { { Int, 0 } } },
708 	{ .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
709 	{ .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
710 	  .args = { { CloudABISignal, 0 } } },
711 	{ .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
712 	  .args = { { BinString | OUT, 0 }, { Int, 1 } } },
713 	{ .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
714 	  .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
715 	{ .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
716 	  .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
717 	{ .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
718 };
719 static STAILQ_HEAD(, syscall) seen_syscalls;
720 
721 /* Xlat idea taken from strace */
722 struct xlat {
723 	int val;
724 	const char *str;
725 };
726 
727 #define	X(a)	{ a, #a },
728 #define	XEND	{ 0, NULL }
729 
730 static struct xlat poll_flags[] = {
731 	X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
732 	X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
733 	X(POLLWRBAND) X(POLLINIGNEOF) X(POLLRDHUP) XEND
734 };
735 
736 static struct xlat sigaction_flags[] = {
737 	X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
738 	X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
739 };
740 
741 static struct xlat linux_socketcall_ops[] = {
742 	X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
743 	X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
744 	X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
745 	X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
746 	X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
747 	XEND
748 };
749 
750 static struct xlat lio_modes[] = {
751 	X(LIO_WAIT) X(LIO_NOWAIT)
752 	XEND
753 };
754 
755 static struct xlat lio_opcodes[] = {
756 	X(LIO_WRITE) X(LIO_READ) X(LIO_NOP)
757 	XEND
758 };
759 
760 static struct xlat aio_fsync_ops[] = {
761 	X(O_SYNC)
762 	XEND
763 };
764 
765 #undef X
766 #define	X(a)	{ CLOUDABI_##a, #a },
767 
768 static struct xlat cloudabi_advice[] = {
769 	X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
770 	X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
771 	XEND
772 };
773 
774 static struct xlat cloudabi_clockid[] = {
775 	X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
776 	X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
777 	XEND
778 };
779 
780 static struct xlat cloudabi_fdflags[] = {
781 	X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
782 	X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
783 	XEND
784 };
785 
786 static struct xlat cloudabi_fdsflags[] = {
787 	X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
788 	XEND
789 };
790 
791 static struct xlat cloudabi_filetype[] = {
792 	X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
793 	X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
794 	X(FILETYPE_PROCESS) X(FILETYPE_REGULAR_FILE)
795 	X(FILETYPE_SHARED_MEMORY) X(FILETYPE_SOCKET_DGRAM)
796 	X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK)
797 	XEND
798 };
799 
800 static struct xlat cloudabi_fsflags[] = {
801 	X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
802 	X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
803 	XEND
804 };
805 
806 static struct xlat cloudabi_mflags[] = {
807 	X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
808 	XEND
809 };
810 
811 static struct xlat cloudabi_mprot[] = {
812 	X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
813 	XEND
814 };
815 
816 static struct xlat cloudabi_msflags[] = {
817 	X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
818 	XEND
819 };
820 
821 static struct xlat cloudabi_oflags[] = {
822 	X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
823 	XEND
824 };
825 
826 static struct xlat cloudabi_sdflags[] = {
827 	X(SHUT_RD) X(SHUT_WR)
828 	XEND
829 };
830 
831 static struct xlat cloudabi_signal[] = {
832 	X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
833 	X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
834 	X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
835 	X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
836 	X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
837 	XEND
838 };
839 
840 static struct xlat cloudabi_ulflags[] = {
841 	X(UNLINK_REMOVEDIR)
842 	XEND
843 };
844 
845 static struct xlat cloudabi_whence[] = {
846 	X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
847 	XEND
848 };
849 
850 #undef X
851 #undef XEND
852 
853 /*
854  * Searches an xlat array for a value, and returns it if found.  Otherwise
855  * return a string representation.
856  */
857 static const char *
858 lookup(struct xlat *xlat, int val, int base)
859 {
860 	static char tmp[16];
861 
862 	for (; xlat->str != NULL; xlat++)
863 		if (xlat->val == val)
864 			return (xlat->str);
865 	switch (base) {
866 		case 8:
867 			sprintf(tmp, "0%o", val);
868 			break;
869 		case 16:
870 			sprintf(tmp, "0x%x", val);
871 			break;
872 		case 10:
873 			sprintf(tmp, "%u", val);
874 			break;
875 		default:
876 			errx(1,"Unknown lookup base");
877 			break;
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, uintptr_t offset, void *buf, int len)
1120 {
1121 	struct ptrace_io_desc iorequest;
1122 
1123 	iorequest.piod_op = PIOD_READ_D;
1124 	iorequest.piod_offs = (void *)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, uintptr_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 - ((uintptr_t)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 *)(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  * Converts a syscall argument into a string.  Said string is
1723  * allocated via malloc(), so needs to be free()'d.  sc is
1724  * a pointer to the syscall description (see above); args is
1725  * an array of all of the system call arguments.
1726  */
1727 char *
1728 print_arg(struct syscall_arg *sc, unsigned long *args, register_t *retval,
1729     struct trussinfo *trussinfo)
1730 {
1731 	FILE *fp;
1732 	char *tmp;
1733 	size_t tmplen;
1734 	pid_t pid;
1735 
1736 	fp = open_memstream(&tmp, &tmplen);
1737 	pid = trussinfo->curthread->proc->pid;
1738 	switch (sc->type & ARG_MASK) {
1739 	case Hex:
1740 		fprintf(fp, "0x%x", (int)args[sc->offset]);
1741 		break;
1742 	case Octal:
1743 		fprintf(fp, "0%o", (int)args[sc->offset]);
1744 		break;
1745 	case Int:
1746 		fprintf(fp, "%d", (int)args[sc->offset]);
1747 		break;
1748 	case UInt:
1749 		fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1750 		break;
1751 	case PUInt: {
1752 		unsigned int val;
1753 
1754 		if (get_struct(pid, args[sc->offset], &val,
1755 		    sizeof(val)) == 0)
1756 			fprintf(fp, "{ %u }", val);
1757 		else
1758 			print_pointer(fp, args[sc->offset]);
1759 		break;
1760 	}
1761 	case LongHex:
1762 		fprintf(fp, "0x%lx", args[sc->offset]);
1763 		break;
1764 	case Long:
1765 		fprintf(fp, "%ld", args[sc->offset]);
1766 		break;
1767 	case Sizet:
1768 		fprintf(fp, "%zu", (size_t)args[sc->offset]);
1769 		break;
1770 	case ShmName:
1771 		/* Handle special SHM_ANON value. */
1772 		if ((char *)args[sc->offset] == SHM_ANON) {
1773 			fprintf(fp, "SHM_ANON");
1774 			break;
1775 		}
1776 		/* FALLTHROUGH */
1777 	case Name: {
1778 		/* NULL-terminated string. */
1779 		char *tmp2;
1780 
1781 		tmp2 = get_string(pid, args[sc->offset], 0);
1782 		fprintf(fp, "\"%s\"", tmp2);
1783 		free(tmp2);
1784 		break;
1785 	}
1786 	case BinString: {
1787 		/*
1788 		 * Binary block of data that might have printable characters.
1789 		 * XXX If type|OUT, assume that the length is the syscall's
1790 		 * return value.  Otherwise, assume that the length of the block
1791 		 * is in the next syscall argument.
1792 		 */
1793 		int max_string = trussinfo->strsize;
1794 		char tmp2[max_string + 1], *tmp3;
1795 		int len;
1796 		int truncated = 0;
1797 
1798 		if (sc->type & OUT)
1799 			len = retval[0];
1800 		else
1801 			len = args[sc->offset + 1];
1802 
1803 		/*
1804 		 * Don't print more than max_string characters, to avoid word
1805 		 * wrap.  If we have to truncate put some ... after the string.
1806 		 */
1807 		if (len > max_string) {
1808 			len = max_string;
1809 			truncated = 1;
1810 		}
1811 		if (len && get_struct(pid, args[sc->offset], &tmp2, len)
1812 		    != -1) {
1813 			tmp3 = malloc(len * 4 + 1);
1814 			while (len) {
1815 				if (strvisx(tmp3, tmp2, len,
1816 				    VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1817 					break;
1818 				len--;
1819 				truncated = 1;
1820 			}
1821 			fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1822 			    "..." : "");
1823 			free(tmp3);
1824 		} else {
1825 			print_pointer(fp, args[sc->offset]);
1826 		}
1827 		break;
1828 	}
1829 	case ExecArgs:
1830 	case ExecEnv:
1831 	case StringArray: {
1832 		uintptr_t addr;
1833 		union {
1834 			int32_t strarray32[PAGE_SIZE / sizeof(int32_t)];
1835 			int64_t strarray64[PAGE_SIZE / sizeof(int64_t)];
1836 			char buf[PAGE_SIZE];
1837 		} u;
1838 		char *string;
1839 		size_t len;
1840 		u_int first, i;
1841 		size_t pointer_size =
1842 		    trussinfo->curthread->proc->abi->pointer_size;
1843 
1844 		/*
1845 		 * Only parse argv[] and environment arrays from exec calls
1846 		 * if requested.
1847 		 */
1848 		if (((sc->type & ARG_MASK) == ExecArgs &&
1849 		    (trussinfo->flags & EXECVEARGS) == 0) ||
1850 		    ((sc->type & ARG_MASK) == ExecEnv &&
1851 		    (trussinfo->flags & EXECVEENVS) == 0)) {
1852 			print_pointer(fp, args[sc->offset]);
1853 			break;
1854 		}
1855 
1856 		/*
1857 		 * Read a page of pointers at a time.  Punt if the top-level
1858 		 * pointer is not aligned.  Note that the first read is of
1859 		 * a partial page.
1860 		 */
1861 		addr = args[sc->offset];
1862 		if (addr % pointer_size != 0) {
1863 			print_pointer(fp, args[sc->offset]);
1864 			break;
1865 		}
1866 
1867 		len = PAGE_SIZE - (addr & PAGE_MASK);
1868 		if (get_struct(pid, addr, u.buf, len) == -1) {
1869 			print_pointer(fp, args[sc->offset]);
1870 			break;
1871 		}
1872 		assert(len > 0);
1873 
1874 		fputc('[', fp);
1875 		first = 1;
1876 		i = 0;
1877 		for (;;) {
1878 			uintptr_t straddr;
1879 			if (pointer_size == 4) {
1880 				if (u.strarray32[i] == 0)
1881 					break;
1882 				/* sign-extend 32-bit pointers */
1883 				straddr = (intptr_t)u.strarray32[i];
1884 			} else if (pointer_size == 8) {
1885 				if (u.strarray64[i] == 0)
1886 					break;
1887 				straddr = (intptr_t)u.strarray64[i];
1888 			} else {
1889 				errx(1, "Unsupported pointer size: %zu",
1890 				    pointer_size);
1891 			}
1892 			string = get_string(pid, straddr, 0);
1893 			fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1894 			free(string);
1895 			first = 0;
1896 
1897 			i++;
1898 			if (i == len / pointer_size) {
1899 				addr += len;
1900 				len = PAGE_SIZE;
1901 				if (get_struct(pid, addr, u.buf, len) == -1) {
1902 					fprintf(fp, ", <inval>");
1903 					break;
1904 				}
1905 				i = 0;
1906 			}
1907 		}
1908 		fputs(" ]", fp);
1909 		break;
1910 	}
1911 #ifdef __LP64__
1912 	case Quad:
1913 		fprintf(fp, "%ld", args[sc->offset]);
1914 		break;
1915 	case QuadHex:
1916 		fprintf(fp, "0x%lx", args[sc->offset]);
1917 		break;
1918 #else
1919 	case Quad:
1920 	case QuadHex: {
1921 		unsigned long long ll;
1922 
1923 #if _BYTE_ORDER == _LITTLE_ENDIAN
1924 		ll = (unsigned long long)args[sc->offset + 1] << 32 |
1925 		    args[sc->offset];
1926 #else
1927 		ll = (unsigned long long)args[sc->offset] << 32 |
1928 		    args[sc->offset + 1];
1929 #endif
1930 		if ((sc->type & ARG_MASK) == Quad)
1931 			fprintf(fp, "%lld", ll);
1932 		else
1933 			fprintf(fp, "0x%llx", ll);
1934 		break;
1935 	}
1936 #endif
1937 	case PQuadHex: {
1938 		uint64_t val;
1939 
1940 		if (get_struct(pid, args[sc->offset], &val,
1941 		    sizeof(val)) == 0)
1942 			fprintf(fp, "{ 0x%jx }", (uintmax_t)val);
1943 		else
1944 			print_pointer(fp, args[sc->offset]);
1945 		break;
1946 	}
1947 	case Ptr:
1948 		print_pointer(fp, args[sc->offset]);
1949 		break;
1950 	case Readlinkres: {
1951 		char *tmp2;
1952 
1953 		if (retval[0] == -1)
1954 			break;
1955 		tmp2 = get_string(pid, args[sc->offset], retval[0]);
1956 		fprintf(fp, "\"%s\"", tmp2);
1957 		free(tmp2);
1958 		break;
1959 	}
1960 	case Ioctl: {
1961 		const char *temp;
1962 		unsigned long cmd;
1963 
1964 		cmd = args[sc->offset];
1965 		temp = sysdecode_ioctlname(cmd);
1966 		if (temp)
1967 			fputs(temp, fp);
1968 		else {
1969 			fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1970 			    cmd, cmd & IOC_OUT ? "R" : "",
1971 			    cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1972 			    isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1973 			    cmd & 0xFF, IOCPARM_LEN(cmd));
1974 		}
1975 		break;
1976 	}
1977 	case Timespec: {
1978 		struct timespec ts;
1979 
1980 		if (get_struct(pid, args[sc->offset], &ts, sizeof(ts)) != -1)
1981 			fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1982 			    ts.tv_nsec);
1983 		else
1984 			print_pointer(fp, args[sc->offset]);
1985 		break;
1986 	}
1987 	case Timespec2: {
1988 		struct timespec ts[2];
1989 		const char *sep;
1990 		unsigned int i;
1991 
1992 		if (get_struct(pid, args[sc->offset], &ts, sizeof(ts)) != -1) {
1993 			fputs("{ ", fp);
1994 			sep = "";
1995 			for (i = 0; i < nitems(ts); i++) {
1996 				fputs(sep, fp);
1997 				sep = ", ";
1998 				switch (ts[i].tv_nsec) {
1999 				case UTIME_NOW:
2000 					fprintf(fp, "UTIME_NOW");
2001 					break;
2002 				case UTIME_OMIT:
2003 					fprintf(fp, "UTIME_OMIT");
2004 					break;
2005 				default:
2006 					fprintf(fp, "%jd.%09ld",
2007 					    (intmax_t)ts[i].tv_sec,
2008 					    ts[i].tv_nsec);
2009 					break;
2010 				}
2011 			}
2012 			fputs(" }", fp);
2013 		} else
2014 			print_pointer(fp, args[sc->offset]);
2015 		break;
2016 	}
2017 	case Timeval: {
2018 		struct timeval tv;
2019 
2020 		if (get_struct(pid, args[sc->offset], &tv, sizeof(tv)) != -1)
2021 			fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
2022 			    tv.tv_usec);
2023 		else
2024 			print_pointer(fp, args[sc->offset]);
2025 		break;
2026 	}
2027 	case Timeval2: {
2028 		struct timeval tv[2];
2029 
2030 		if (get_struct(pid, args[sc->offset], &tv, sizeof(tv)) != -1)
2031 			fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
2032 			    (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
2033 			    (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
2034 		else
2035 			print_pointer(fp, args[sc->offset]);
2036 		break;
2037 	}
2038 	case Itimerval: {
2039 		struct itimerval itv;
2040 
2041 		if (get_struct(pid, args[sc->offset], &itv, sizeof(itv)) != -1)
2042 			fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
2043 			    (intmax_t)itv.it_interval.tv_sec,
2044 			    itv.it_interval.tv_usec,
2045 			    (intmax_t)itv.it_value.tv_sec,
2046 			    itv.it_value.tv_usec);
2047 		else
2048 			print_pointer(fp, args[sc->offset]);
2049 		break;
2050 	}
2051 	case LinuxSockArgs:
2052 	{
2053 		struct linux_socketcall_args largs;
2054 
2055 		if (get_struct(pid, args[sc->offset], (void *)&largs,
2056 		    sizeof(largs)) != -1)
2057 			fprintf(fp, "{ %s, 0x%lx }",
2058 			    lookup(linux_socketcall_ops, largs.what, 10),
2059 			    (long unsigned int)largs.args);
2060 		else
2061 			print_pointer(fp, args[sc->offset]);
2062 		break;
2063 	}
2064 	case Pollfd: {
2065 		/*
2066 		 * XXX: A Pollfd argument expects the /next/ syscall argument
2067 		 * to be the number of fds in the array. This matches the poll
2068 		 * syscall.
2069 		 */
2070 		struct pollfd *pfd;
2071 		int numfds = args[sc->offset + 1];
2072 		size_t bytes = sizeof(struct pollfd) * numfds;
2073 		int i;
2074 
2075 		if ((pfd = malloc(bytes)) == NULL)
2076 			err(1, "Cannot malloc %zu bytes for pollfd array",
2077 			    bytes);
2078 		if (get_struct(pid, args[sc->offset], pfd, bytes) != -1) {
2079 			fputs("{", fp);
2080 			for (i = 0; i < numfds; i++) {
2081 				fprintf(fp, " %d/%s", pfd[i].fd,
2082 				    xlookup_bits(poll_flags, pfd[i].events));
2083 			}
2084 			fputs(" }", fp);
2085 		} else {
2086 			print_pointer(fp, args[sc->offset]);
2087 		}
2088 		free(pfd);
2089 		break;
2090 	}
2091 	case Fd_set: {
2092 		/*
2093 		 * XXX: A Fd_set argument expects the /first/ syscall argument
2094 		 * to be the number of fds in the array.  This matches the
2095 		 * select syscall.
2096 		 */
2097 		fd_set *fds;
2098 		int numfds = args[0];
2099 		size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
2100 		int i;
2101 
2102 		if ((fds = malloc(bytes)) == NULL)
2103 			err(1, "Cannot malloc %zu bytes for fd_set array",
2104 			    bytes);
2105 		if (get_struct(pid, args[sc->offset], fds, bytes) != -1) {
2106 			fputs("{", fp);
2107 			for (i = 0; i < numfds; i++) {
2108 				if (FD_ISSET(i, fds))
2109 					fprintf(fp, " %d", i);
2110 			}
2111 			fputs(" }", fp);
2112 		} else
2113 			print_pointer(fp, args[sc->offset]);
2114 		free(fds);
2115 		break;
2116 	}
2117 	case Signal:
2118 		fputs(strsig2(args[sc->offset]), fp);
2119 		break;
2120 	case Sigset: {
2121 		long sig;
2122 		sigset_t ss;
2123 		int i, first;
2124 
2125 		sig = args[sc->offset];
2126 		if (get_struct(pid, args[sc->offset], (void *)&ss,
2127 		    sizeof(ss)) == -1) {
2128 			print_pointer(fp, args[sc->offset]);
2129 			break;
2130 		}
2131 		fputs("{ ", fp);
2132 		first = 1;
2133 		for (i = 1; i < sys_nsig; i++) {
2134 			if (sigismember(&ss, i)) {
2135 				fprintf(fp, "%s%s", !first ? "|" : "",
2136 				    strsig2(i));
2137 				first = 0;
2138 			}
2139 		}
2140 		if (!first)
2141 			fputc(' ', fp);
2142 		fputc('}', fp);
2143 		break;
2144 	}
2145 	case Sigprocmask:
2146 		print_integer_arg(sysdecode_sigprocmask_how, fp,
2147 		    args[sc->offset]);
2148 		break;
2149 	case Fcntlflag:
2150 		/* XXX: Output depends on the value of the previous argument. */
2151 		if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
2152 			sysdecode_fcntl_arg(fp, args[sc->offset - 1],
2153 			    args[sc->offset], 16);
2154 		break;
2155 	case Open:
2156 		print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
2157 		break;
2158 	case Fcntl:
2159 		print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
2160 		break;
2161 	case Mprot:
2162 		print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
2163 		break;
2164 	case Mmapflags:
2165 		print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
2166 		break;
2167 	case Whence:
2168 		print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
2169 		break;
2170 	case ShmFlags:
2171 		print_mask_arg(sysdecode_shmflags, fp, args[sc->offset]);
2172 		break;
2173 	case Sockdomain:
2174 		print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
2175 		break;
2176 	case Socktype:
2177 		print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
2178 		break;
2179 	case Shutdown:
2180 		print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
2181 		break;
2182 	case Resource:
2183 		print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
2184 		break;
2185 	case RusageWho:
2186 		print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]);
2187 		break;
2188 	case Pathconf:
2189 		print_integer_arg(sysdecode_pathconf_name, fp, args[sc->offset]);
2190 		break;
2191 	case Rforkflags:
2192 		print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
2193 		break;
2194 	case Sockaddr: {
2195 		socklen_t len;
2196 
2197 		if (args[sc->offset] == 0) {
2198 			fputs("NULL", fp);
2199 			break;
2200 		}
2201 
2202 		/*
2203 		 * Extract the address length from the next argument.  If
2204 		 * this is an output sockaddr (OUT is set), then the
2205 		 * next argument is a pointer to a socklen_t.  Otherwise
2206 		 * the next argument contains a socklen_t by value.
2207 		 */
2208 		if (sc->type & OUT) {
2209 			if (get_struct(pid, args[sc->offset + 1], &len,
2210 			    sizeof(len)) == -1) {
2211 				print_pointer(fp, args[sc->offset]);
2212 				break;
2213 			}
2214 		} else
2215 			len = args[sc->offset + 1];
2216 
2217 		print_sockaddr(fp, trussinfo, args[sc->offset], len);
2218 		break;
2219 	}
2220 	case Sigaction: {
2221 		struct sigaction sa;
2222 
2223 		if (get_struct(pid, args[sc->offset], &sa, sizeof(sa)) != -1) {
2224 			fputs("{ ", fp);
2225 			if (sa.sa_handler == SIG_DFL)
2226 				fputs("SIG_DFL", fp);
2227 			else if (sa.sa_handler == SIG_IGN)
2228 				fputs("SIG_IGN", fp);
2229 			else
2230 				fprintf(fp, "%p", sa.sa_handler);
2231 			fprintf(fp, " %s ss_t }",
2232 			    xlookup_bits(sigaction_flags, sa.sa_flags));
2233 		} else
2234 			print_pointer(fp, args[sc->offset]);
2235 		break;
2236 	}
2237 	case Sigevent: {
2238 		struct sigevent se;
2239 
2240 		if (get_struct(pid, args[sc->offset], &se, sizeof(se)) != -1)
2241 			print_sigevent(fp, &se);
2242 		else
2243 			print_pointer(fp, args[sc->offset]);
2244 		break;
2245 	}
2246 	case Kevent: {
2247 		/*
2248 		 * XXX XXX: The size of the array is determined by either the
2249 		 * next syscall argument, or by the syscall return value,
2250 		 * depending on which argument number we are.  This matches the
2251 		 * kevent syscall, but luckily that's the only syscall that uses
2252 		 * them.
2253 		 */
2254 		struct kevent *ke;
2255 		int numevents = -1;
2256 		size_t bytes;
2257 		int i;
2258 
2259 		if (sc->offset == 1)
2260 			numevents = args[sc->offset+1];
2261 		else if (sc->offset == 3 && retval[0] != -1)
2262 			numevents = retval[0];
2263 
2264 		if (numevents >= 0) {
2265 			bytes = sizeof(struct kevent) * numevents;
2266 			if ((ke = malloc(bytes)) == NULL)
2267 				err(1,
2268 				    "Cannot malloc %zu bytes for kevent array",
2269 				    bytes);
2270 		} else
2271 			ke = NULL;
2272 		if (numevents >= 0 && get_struct(pid, args[sc->offset],
2273 		    ke, bytes) != -1) {
2274 			fputc('{', fp);
2275 			for (i = 0; i < numevents; i++) {
2276 				fputc(' ', fp);
2277 				print_kevent(fp, &ke[i]);
2278 			}
2279 			fputs(" }", fp);
2280 		} else {
2281 			print_pointer(fp, args[sc->offset]);
2282 		}
2283 		free(ke);
2284 		break;
2285 	}
2286 	case Kevent11: {
2287 		struct kevent_freebsd11 *ke11;
2288 		struct kevent ke;
2289 		int numevents = -1;
2290 		size_t bytes;
2291 		int i;
2292 
2293 		if (sc->offset == 1)
2294 			numevents = args[sc->offset+1];
2295 		else if (sc->offset == 3 && retval[0] != -1)
2296 			numevents = retval[0];
2297 
2298 		if (numevents >= 0) {
2299 			bytes = sizeof(struct kevent_freebsd11) * numevents;
2300 			if ((ke11 = malloc(bytes)) == NULL)
2301 				err(1,
2302 				    "Cannot malloc %zu bytes for kevent array",
2303 				    bytes);
2304 		} else
2305 			ke11 = NULL;
2306 		memset(&ke, 0, sizeof(ke));
2307 		if (numevents >= 0 && get_struct(pid, args[sc->offset],
2308 		    ke11, bytes) != -1) {
2309 			fputc('{', fp);
2310 			for (i = 0; i < numevents; i++) {
2311 				fputc(' ', fp);
2312 				ke.ident = ke11[i].ident;
2313 				ke.filter = ke11[i].filter;
2314 				ke.flags = ke11[i].flags;
2315 				ke.fflags = ke11[i].fflags;
2316 				ke.data = ke11[i].data;
2317 				ke.udata = ke11[i].udata;
2318 				print_kevent(fp, &ke);
2319 			}
2320 			fputs(" }", fp);
2321 		} else {
2322 			print_pointer(fp, args[sc->offset]);
2323 		}
2324 		free(ke11);
2325 		break;
2326 	}
2327 	case Stat: {
2328 		struct stat st;
2329 
2330 		if (get_struct(pid, args[sc->offset], &st, sizeof(st))
2331 		    != -1) {
2332 			char mode[12];
2333 
2334 			strmode(st.st_mode, mode);
2335 			fprintf(fp,
2336 			    "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
2337 			    (uintmax_t)st.st_ino, (intmax_t)st.st_size,
2338 			    (long)st.st_blksize);
2339 		} else {
2340 			print_pointer(fp, args[sc->offset]);
2341 		}
2342 		break;
2343 	}
2344 	case Stat11: {
2345 		struct freebsd11_stat st;
2346 
2347 		if (get_struct(pid, args[sc->offset], &st, sizeof(st))
2348 		    != -1) {
2349 			char mode[12];
2350 
2351 			strmode(st.st_mode, mode);
2352 			fprintf(fp,
2353 			    "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
2354 			    (uintmax_t)st.st_ino, (intmax_t)st.st_size,
2355 			    (long)st.st_blksize);
2356 		} else {
2357 			print_pointer(fp, args[sc->offset]);
2358 		}
2359 		break;
2360 	}
2361 	case StatFs: {
2362 		unsigned int i;
2363 		struct statfs buf;
2364 
2365 		if (get_struct(pid, args[sc->offset], &buf,
2366 		    sizeof(buf)) != -1) {
2367 			char fsid[17];
2368 
2369 			bzero(fsid, sizeof(fsid));
2370 			if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
2371 			        for (i = 0; i < sizeof(buf.f_fsid); i++)
2372 					snprintf(&fsid[i*2],
2373 					    sizeof(fsid) - (i*2), "%02x",
2374 					    ((u_char *)&buf.f_fsid)[i]);
2375 			}
2376 			fprintf(fp,
2377 			    "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
2378 			    "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
2379 			    buf.f_mntfromname, fsid);
2380 		} else
2381 			print_pointer(fp, args[sc->offset]);
2382 		break;
2383 	}
2384 
2385 	case Rusage: {
2386 		struct rusage ru;
2387 
2388 		if (get_struct(pid, args[sc->offset], &ru, sizeof(ru))
2389 		    != -1) {
2390 			fprintf(fp,
2391 			    "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
2392 			    (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
2393 			    (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
2394 			    ru.ru_inblock, ru.ru_oublock);
2395 		} else
2396 			print_pointer(fp, args[sc->offset]);
2397 		break;
2398 	}
2399 	case Rlimit: {
2400 		struct rlimit rl;
2401 
2402 		if (get_struct(pid, args[sc->offset], &rl, sizeof(rl))
2403 		    != -1) {
2404 			fprintf(fp, "{ cur=%ju,max=%ju }",
2405 			    rl.rlim_cur, rl.rlim_max);
2406 		} else
2407 			print_pointer(fp, args[sc->offset]);
2408 		break;
2409 	}
2410 	case ExitStatus: {
2411 		int status;
2412 
2413 		if (get_struct(pid, args[sc->offset], &status,
2414 		    sizeof(status)) != -1) {
2415 			fputs("{ ", fp);
2416 			if (WIFCONTINUED(status))
2417 				fputs("CONTINUED", fp);
2418 			else if (WIFEXITED(status))
2419 				fprintf(fp, "EXITED,val=%d",
2420 				    WEXITSTATUS(status));
2421 			else if (WIFSIGNALED(status))
2422 				fprintf(fp, "SIGNALED,sig=%s%s",
2423 				    strsig2(WTERMSIG(status)),
2424 				    WCOREDUMP(status) ? ",cored" : "");
2425 			else
2426 				fprintf(fp, "STOPPED,sig=%s",
2427 				    strsig2(WTERMSIG(status)));
2428 			fputs(" }", fp);
2429 		} else
2430 			print_pointer(fp, args[sc->offset]);
2431 		break;
2432 	}
2433 	case Waitoptions:
2434 		print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]);
2435 		break;
2436 	case Idtype:
2437 		print_integer_arg(sysdecode_idtype, fp, args[sc->offset]);
2438 		break;
2439 	case Procctl:
2440 		print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]);
2441 		break;
2442 	case Umtxop: {
2443 		int rem;
2444 
2445 		if (print_mask_arg_part(sysdecode_umtx_op_flags, fp,
2446 		    args[sc->offset], &rem))
2447 			fprintf(fp, "|");
2448 		print_integer_arg(sysdecode_umtx_op, fp, rem);
2449 		break;
2450 	}
2451 	case Atfd:
2452 		print_integer_arg(sysdecode_atfd, fp, args[sc->offset]);
2453 		break;
2454 	case Atflags:
2455 		print_mask_arg(sysdecode_atflags, fp, args[sc->offset]);
2456 		break;
2457 	case Accessmode:
2458 		print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]);
2459 		break;
2460 	case Sysarch:
2461 		print_integer_arg(sysdecode_sysarch_number, fp,
2462 		    args[sc->offset]);
2463 		break;
2464 	case Sysctl: {
2465 		char name[BUFSIZ];
2466 		int oid[CTL_MAXNAME + 2];
2467 		size_t len;
2468 
2469 		memset(name, 0, sizeof(name));
2470 		len = args[sc->offset + 1];
2471 		if (get_struct(pid, args[sc->offset], oid,
2472 		    len * sizeof(oid[0])) != -1) {
2473 		    	fprintf(fp, "\"");
2474 			if (oid[0] == CTL_SYSCTL) {
2475 				fprintf(fp, "sysctl.");
2476 				switch (oid[1]) {
2477 				case CTL_SYSCTL_DEBUG:
2478 					fprintf(fp, "debug");
2479 					break;
2480 				case CTL_SYSCTL_NAME:
2481 					fprintf(fp, "name ");
2482 					print_sysctl_oid(fp, oid + 2, len - 2);
2483 					break;
2484 				case CTL_SYSCTL_NEXT:
2485 					fprintf(fp, "next");
2486 					break;
2487 				case CTL_SYSCTL_NAME2OID:
2488 					fprintf(fp, "name2oid %s",
2489 					    get_string(pid,
2490 					        args[sc->offset + 4],
2491 						args[sc->offset + 5]));
2492 					break;
2493 				case CTL_SYSCTL_OIDFMT:
2494 					fprintf(fp, "oidfmt ");
2495 					print_sysctl(fp, oid + 2, len - 2);
2496 					break;
2497 				case CTL_SYSCTL_OIDDESCR:
2498 					fprintf(fp, "oiddescr ");
2499 					print_sysctl(fp, oid + 2, len - 2);
2500 					break;
2501 				case CTL_SYSCTL_OIDLABEL:
2502 					fprintf(fp, "oidlabel ");
2503 					print_sysctl(fp, oid + 2, len - 2);
2504 					break;
2505 				case CTL_SYSCTL_NEXTNOSKIP:
2506 					fprintf(fp, "nextnoskip");
2507 					break;
2508 				default:
2509 					print_sysctl(fp, oid + 1, len - 1);
2510 				}
2511 			} else {
2512 				print_sysctl(fp, oid, len);
2513 			}
2514 		    	fprintf(fp, "\"");
2515 		}
2516 		break;
2517 	}
2518 	case PipeFds:
2519 		/*
2520 		 * The pipe() system call in the kernel returns its
2521 		 * two file descriptors via return values.  However,
2522 		 * the interface exposed by libc is that pipe()
2523 		 * accepts a pointer to an array of descriptors.
2524 		 * Format the output to match the libc API by printing
2525 		 * the returned file descriptors as a fake argument.
2526 		 *
2527 		 * Overwrite the first retval to signal a successful
2528 		 * return as well.
2529 		 */
2530 		fprintf(fp, "{ %d, %d }", (int)retval[0], (int)retval[1]);
2531 		retval[0] = 0;
2532 		break;
2533 	case Utrace: {
2534 		size_t len;
2535 		void *utrace_addr;
2536 
2537 		len = args[sc->offset + 1];
2538 		utrace_addr = calloc(1, len);
2539 		if (get_struct(pid, args[sc->offset],
2540 		    (void *)utrace_addr, len) != -1)
2541 			print_utrace(fp, utrace_addr, len);
2542 		else
2543 			print_pointer(fp, args[sc->offset]);
2544 		free(utrace_addr);
2545 		break;
2546 	}
2547 	case IntArray: {
2548 		int descriptors[16];
2549 		unsigned long i, ndescriptors;
2550 		bool truncated;
2551 
2552 		ndescriptors = args[sc->offset + 1];
2553 		truncated = false;
2554 		if (ndescriptors > nitems(descriptors)) {
2555 			ndescriptors = nitems(descriptors);
2556 			truncated = true;
2557 		}
2558 		if (get_struct(pid, args[sc->offset],
2559 		    descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
2560 			fprintf(fp, "{");
2561 			for (i = 0; i < ndescriptors; i++)
2562 				fprintf(fp, i == 0 ? " %d" : ", %d",
2563 				    descriptors[i]);
2564 			fprintf(fp, truncated ? ", ... }" : " }");
2565 		} else
2566 			print_pointer(fp, args[sc->offset]);
2567 		break;
2568 	}
2569 	case Pipe2:
2570 		print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]);
2571 		break;
2572 	case CapFcntlRights: {
2573 		uint32_t rights;
2574 
2575 		if (sc->type & OUT) {
2576 			if (get_struct(pid, args[sc->offset], &rights,
2577 			    sizeof(rights)) == -1) {
2578 				print_pointer(fp, args[sc->offset]);
2579 				break;
2580 			}
2581 		} else
2582 			rights = args[sc->offset];
2583 		print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights);
2584 		break;
2585 	}
2586 	case Fadvice:
2587 		print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]);
2588 		break;
2589 	case FileFlags: {
2590 		fflags_t rem;
2591 
2592 		if (!sysdecode_fileflags(fp, args[sc->offset], &rem))
2593 			fprintf(fp, "0x%x", rem);
2594 		else if (rem != 0)
2595 			fprintf(fp, "|0x%x", rem);
2596 		break;
2597 	}
2598 	case Flockop:
2599 		print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]);
2600 		break;
2601 	case Getfsstatmode:
2602 		print_integer_arg(sysdecode_getfsstat_mode, fp,
2603 		    args[sc->offset]);
2604 		break;
2605 	case Kldsymcmd:
2606 		print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]);
2607 		break;
2608 	case Kldunloadflags:
2609 		print_integer_arg(sysdecode_kldunload_flags, fp,
2610 		    args[sc->offset]);
2611 		break;
2612 	case AiofsyncOp:
2613 		fputs(xlookup(aio_fsync_ops, args[sc->offset]), fp);
2614 		break;
2615 	case LioMode:
2616 		fputs(xlookup(lio_modes, args[sc->offset]), fp);
2617 		break;
2618 	case Madvice:
2619 		print_integer_arg(sysdecode_madvice, fp, args[sc->offset]);
2620 		break;
2621 	case Socklent:
2622 		fprintf(fp, "%u", (socklen_t)args[sc->offset]);
2623 		break;
2624 	case Sockprotocol: {
2625 		const char *temp;
2626 		int domain, protocol;
2627 
2628 		domain = args[sc->offset - 2];
2629 		protocol = args[sc->offset];
2630 		if (protocol == 0) {
2631 			fputs("0", fp);
2632 		} else {
2633 			temp = sysdecode_socket_protocol(domain, protocol);
2634 			if (temp) {
2635 				fputs(temp, fp);
2636 			} else {
2637 				fprintf(fp, "%d", protocol);
2638 			}
2639 		}
2640 		break;
2641 	}
2642 	case Sockoptlevel:
2643 		print_integer_arg(sysdecode_sockopt_level, fp,
2644 		    args[sc->offset]);
2645 		break;
2646 	case Sockoptname: {
2647 		const char *temp;
2648 		int level, name;
2649 
2650 		level = args[sc->offset - 1];
2651 		name = args[sc->offset];
2652 		temp = sysdecode_sockopt_name(level, name);
2653 		if (temp) {
2654 			fputs(temp, fp);
2655 		} else {
2656 			fprintf(fp, "%d", name);
2657 		}
2658 		break;
2659 	}
2660 	case Msgflags:
2661 		print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]);
2662 		break;
2663 	case CapRights: {
2664 		cap_rights_t rights;
2665 
2666 		if (get_struct(pid, args[sc->offset], &rights,
2667 		    sizeof(rights)) != -1) {
2668 			fputs("{ ", fp);
2669 			sysdecode_cap_rights(fp, &rights);
2670 			fputs(" }", fp);
2671 		} else
2672 			print_pointer(fp, args[sc->offset]);
2673 		break;
2674 	}
2675 	case Acltype:
2676 		print_integer_arg(sysdecode_acltype, fp, args[sc->offset]);
2677 		break;
2678 	case Extattrnamespace:
2679 		print_integer_arg(sysdecode_extattrnamespace, fp,
2680 		    args[sc->offset]);
2681 		break;
2682 	case Minherit:
2683 		print_integer_arg(sysdecode_minherit_inherit, fp,
2684 		    args[sc->offset]);
2685 		break;
2686 	case Mlockall:
2687 		print_mask_arg(sysdecode_mlockall_flags, fp, args[sc->offset]);
2688 		break;
2689 	case Mountflags:
2690 		print_mask_arg(sysdecode_mount_flags, fp, args[sc->offset]);
2691 		break;
2692 	case Msync:
2693 		print_mask_arg(sysdecode_msync_flags, fp, args[sc->offset]);
2694 		break;
2695 	case Priowhich:
2696 		print_integer_arg(sysdecode_prio_which, fp, args[sc->offset]);
2697 		break;
2698 	case Ptraceop:
2699 		print_integer_arg(sysdecode_ptrace_request, fp,
2700 		    args[sc->offset]);
2701 		break;
2702 	case Sendfileflags:
2703 		print_mask_arg(sysdecode_sendfile_flags, fp, args[sc->offset]);
2704 		break;
2705 	case Sendfilehdtr: {
2706 		struct sf_hdtr hdtr;
2707 
2708 		if (get_struct(pid, args[sc->offset], &hdtr, sizeof(hdtr)) !=
2709 		    -1) {
2710 			fprintf(fp, "{");
2711 			print_iovec(fp, trussinfo, (uintptr_t)hdtr.headers,
2712 			    hdtr.hdr_cnt);
2713 			print_iovec(fp, trussinfo, (uintptr_t)hdtr.trailers,
2714 			    hdtr.trl_cnt);
2715 			fprintf(fp, "}");
2716 		} else
2717 			print_pointer(fp, args[sc->offset]);
2718 		break;
2719 	}
2720 	case Quotactlcmd:
2721 		if (!sysdecode_quotactl_cmd(fp, args[sc->offset]))
2722 			fprintf(fp, "%#x", (int)args[sc->offset]);
2723 		break;
2724 	case Reboothowto:
2725 		print_mask_arg(sysdecode_reboot_howto, fp, args[sc->offset]);
2726 		break;
2727 	case Rtpriofunc:
2728 		print_integer_arg(sysdecode_rtprio_function, fp,
2729 		    args[sc->offset]);
2730 		break;
2731 	case Schedpolicy:
2732 		print_integer_arg(sysdecode_scheduler_policy, fp,
2733 		    args[sc->offset]);
2734 		break;
2735 	case Schedparam: {
2736 		struct sched_param sp;
2737 
2738 		if (get_struct(pid, args[sc->offset], &sp, sizeof(sp)) != -1)
2739 			fprintf(fp, "{ %d }", sp.sched_priority);
2740 		else
2741 			print_pointer(fp, args[sc->offset]);
2742 		break;
2743 	}
2744 	case PSig: {
2745 		int sig;
2746 
2747 		if (get_struct(pid, args[sc->offset], &sig, sizeof(sig)) == 0)
2748 			fprintf(fp, "{ %s }", strsig2(sig));
2749 		else
2750 			print_pointer(fp, args[sc->offset]);
2751 		break;
2752 	}
2753 	case Siginfo: {
2754 		siginfo_t si;
2755 
2756 		if (get_struct(pid, args[sc->offset], &si, sizeof(si)) != -1) {
2757 			fprintf(fp, "{ signo=%s", strsig2(si.si_signo));
2758 			decode_siginfo(fp, &si);
2759 			fprintf(fp, " }");
2760 		} else
2761 			print_pointer(fp, args[sc->offset]);
2762 		break;
2763 	}
2764 	case Iovec:
2765 		/*
2766 		 * Print argument as an array of struct iovec, where the next
2767 		 * syscall argument is the number of elements of the array.
2768 		 */
2769 
2770 		print_iovec(fp, trussinfo, args[sc->offset],
2771 		    (int)args[sc->offset + 1]);
2772 		break;
2773 	case Aiocb: {
2774 		struct aiocb cb;
2775 
2776 		if (get_struct(pid, args[sc->offset], &cb, sizeof(cb)) != -1)
2777 			print_aiocb(fp, &cb);
2778 		else
2779 			print_pointer(fp, args[sc->offset]);
2780 		break;
2781 	}
2782 	case AiocbArray: {
2783 		/*
2784 		 * Print argment as an array of pointers to struct aiocb, where
2785 		 * the next syscall argument is the number of elements.
2786 		 */
2787 		uintptr_t cbs[16];
2788 		unsigned int nent;
2789 		bool truncated;
2790 
2791 		nent = args[sc->offset + 1];
2792 		truncated = false;
2793 		if (nent > nitems(cbs)) {
2794 			nent = nitems(cbs);
2795 			truncated = true;
2796 		}
2797 
2798 		if (get_struct(pid, args[sc->offset], cbs, sizeof(uintptr_t) * nent) != -1) {
2799 			unsigned int i;
2800 			fputs("[", fp);
2801 			for (i = 0; i < nent; ++i) {
2802 				struct aiocb cb;
2803 				if (i > 0)
2804 					fputc(',', fp);
2805 				if (get_struct(pid, cbs[i], &cb, sizeof(cb)) != -1)
2806 					print_aiocb(fp, &cb);
2807 				else
2808 					print_pointer(fp, cbs[i]);
2809 			}
2810 			if (truncated)
2811 				fputs(",...", fp);
2812 			fputs("]", fp);
2813 		} else
2814 			print_pointer(fp, args[sc->offset]);
2815 		break;
2816 	}
2817 	case AiocbPointer: {
2818 		/*
2819 		 * aio_waitcomplete(2) assigns a pointer to a pointer to struct
2820 		 * aiocb, so we need to handle the extra layer of indirection.
2821 		 */
2822 		uintptr_t cbp;
2823 		struct aiocb cb;
2824 
2825 		if (get_struct(pid, args[sc->offset], &cbp, sizeof(cbp)) != -1) {
2826 			if (get_struct(pid, cbp, &cb, sizeof(cb)) != -1)
2827 				print_aiocb(fp, &cb);
2828 			else
2829 				print_pointer(fp, cbp);
2830 		} else
2831 			print_pointer(fp, args[sc->offset]);
2832 		break;
2833 	}
2834 	case Sctpsndrcvinfo: {
2835 		struct sctp_sndrcvinfo info;
2836 
2837 		if (get_struct(pid, args[sc->offset],
2838 		    &info, sizeof(struct sctp_sndrcvinfo)) == -1) {
2839 			print_pointer(fp, args[sc->offset]);
2840 			break;
2841 		}
2842 		print_sctp_sndrcvinfo(fp, sc->type & OUT, &info);
2843 		break;
2844 	}
2845 	case Msghdr: {
2846 		struct msghdr msghdr;
2847 
2848 		if (get_struct(pid, args[sc->offset],
2849 		    &msghdr, sizeof(struct msghdr)) == -1) {
2850 			print_pointer(fp, args[sc->offset]);
2851 			break;
2852 		}
2853 		fputs("{", fp);
2854 		print_sockaddr(fp, trussinfo, (uintptr_t)msghdr.msg_name, msghdr.msg_namelen);
2855 		fprintf(fp, ",%d,", msghdr.msg_namelen);
2856 		print_iovec(fp, trussinfo, (uintptr_t)msghdr.msg_iov, msghdr.msg_iovlen);
2857 		fprintf(fp, ",%d,", msghdr.msg_iovlen);
2858 		print_cmsgs(fp, pid, sc->type & OUT, &msghdr);
2859 		fprintf(fp, ",%u,", msghdr.msg_controllen);
2860 		print_mask_arg(sysdecode_msg_flags, fp, msghdr.msg_flags);
2861 		fputs("}", fp);
2862 		break;
2863 	}
2864 
2865 	case CloudABIAdvice:
2866 		fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
2867 		break;
2868 	case CloudABIClockID:
2869 		fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2870 		break;
2871 	case CloudABIFDSFlags:
2872 		fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2873 		break;
2874 	case CloudABIFDStat: {
2875 		cloudabi_fdstat_t fds;
2876 		if (get_struct(pid, args[sc->offset], &fds, sizeof(fds))
2877 		    != -1) {
2878 			fprintf(fp, "{ %s, ",
2879 			    xlookup(cloudabi_filetype, fds.fs_filetype));
2880 			fprintf(fp, "%s, ... }",
2881 			    xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2882 		} else
2883 			print_pointer(fp, args[sc->offset]);
2884 		break;
2885 	}
2886 	case CloudABIFileStat: {
2887 		cloudabi_filestat_t fsb;
2888 		if (get_struct(pid, args[sc->offset], &fsb, sizeof(fsb))
2889 		    != -1)
2890 			fprintf(fp, "{ %s, %ju }",
2891 			    xlookup(cloudabi_filetype, fsb.st_filetype),
2892 			    (uintmax_t)fsb.st_size);
2893 		else
2894 			print_pointer(fp, args[sc->offset]);
2895 		break;
2896 	}
2897 	case CloudABIFileType:
2898 		fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2899 		break;
2900 	case CloudABIFSFlags:
2901 		fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2902 		break;
2903 	case CloudABILookup:
2904 		if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2905 			fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2906 			    (int)args[sc->offset]);
2907 		else
2908 			fprintf(fp, "%d", (int)args[sc->offset]);
2909 		break;
2910 	case CloudABIMFlags:
2911 		fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2912 		break;
2913 	case CloudABIMProt:
2914 		fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2915 		break;
2916 	case CloudABIMSFlags:
2917 		fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2918 		break;
2919 	case CloudABIOFlags:
2920 		fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2921 		break;
2922 	case CloudABISDFlags:
2923 		fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2924 		break;
2925 	case CloudABISignal:
2926 		fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2927 		break;
2928 	case CloudABITimestamp:
2929 		fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2930 		    args[sc->offset] % 1000000000);
2931 		break;
2932 	case CloudABIULFlags:
2933 		fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2934 		break;
2935 	case CloudABIWhence:
2936 		fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2937 		break;
2938 
2939 	default:
2940 		errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2941 	}
2942 	fclose(fp);
2943 	return (tmp);
2944 }
2945 
2946 /*
2947  * Print (to outfile) the system call and its arguments.
2948  */
2949 void
2950 print_syscall(struct trussinfo *trussinfo)
2951 {
2952 	struct threadinfo *t;
2953 	const char *name;
2954 	char **s_args;
2955 	int i, len, nargs;
2956 
2957 	t = trussinfo->curthread;
2958 
2959 	name = t->cs.sc->name;
2960 	nargs = t->cs.nargs;
2961 	s_args = t->cs.s_args;
2962 
2963 	len = print_line_prefix(trussinfo);
2964 	len += fprintf(trussinfo->outfile, "%s(", name);
2965 
2966 	for (i = 0; i < nargs; i++) {
2967 		if (s_args[i] != NULL)
2968 			len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2969 		else
2970 			len += fprintf(trussinfo->outfile,
2971 			    "<missing argument>");
2972 		len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2973 		    "," : "");
2974 	}
2975 	len += fprintf(trussinfo->outfile, ")");
2976 	for (i = 0; i < 6 - (len / 8); i++)
2977 		fprintf(trussinfo->outfile, "\t");
2978 }
2979 
2980 void
2981 print_syscall_ret(struct trussinfo *trussinfo, int error, register_t *retval)
2982 {
2983 	struct timespec timediff;
2984 	struct threadinfo *t;
2985 	struct syscall *sc;
2986 
2987 	t = trussinfo->curthread;
2988 	sc = t->cs.sc;
2989 	if (trussinfo->flags & COUNTONLY) {
2990 		timespecsub(&t->after, &t->before, &timediff);
2991 		timespecadd(&sc->time, &timediff, &sc->time);
2992 		sc->ncalls++;
2993 		if (error != 0)
2994 			sc->nerror++;
2995 		return;
2996 	}
2997 
2998 	print_syscall(trussinfo);
2999 	fflush(trussinfo->outfile);
3000 
3001 	if (retval == NULL) {
3002 		/*
3003 		 * This system call resulted in the current thread's exit,
3004 		 * so there is no return value or error to display.
3005 		 */
3006 		fprintf(trussinfo->outfile, "\n");
3007 		return;
3008 	}
3009 
3010 	if (error == ERESTART)
3011 		fprintf(trussinfo->outfile, " ERESTART\n");
3012 	else if (error == EJUSTRETURN)
3013 		fprintf(trussinfo->outfile, " EJUSTRETURN\n");
3014 	else if (error != 0) {
3015 		fprintf(trussinfo->outfile, " ERR#%d '%s'\n",
3016 		    sysdecode_freebsd_to_abi_errno(t->proc->abi->abi, error),
3017 		    strerror(error));
3018 	}
3019 #ifndef __LP64__
3020 	else if (sc->decode.ret_type == 2) {
3021 		off_t off;
3022 
3023 #if _BYTE_ORDER == _LITTLE_ENDIAN
3024 		off = (off_t)retval[1] << 32 | retval[0];
3025 #else
3026 		off = (off_t)retval[0] << 32 | retval[1];
3027 #endif
3028 		fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
3029 		    (intmax_t)off);
3030 	}
3031 #endif
3032 	else
3033 		fprintf(trussinfo->outfile, " = %jd (0x%jx)\n",
3034 		    (intmax_t)retval[0], (intmax_t)retval[0]);
3035 }
3036 
3037 void
3038 print_summary(struct trussinfo *trussinfo)
3039 {
3040 	struct timespec total = {0, 0};
3041 	struct syscall *sc;
3042 	int ncall, nerror;
3043 
3044 	fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
3045 	    "syscall", "seconds", "calls", "errors");
3046 	ncall = nerror = 0;
3047 	STAILQ_FOREACH(sc, &seen_syscalls, entries) {
3048 		if (sc->ncalls) {
3049 			fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
3050 			    sc->name, (intmax_t)sc->time.tv_sec,
3051 			    sc->time.tv_nsec, sc->ncalls, sc->nerror);
3052 			timespecadd(&total, &sc->time, &total);
3053 			ncall += sc->ncalls;
3054 			nerror += sc->nerror;
3055 		}
3056 	}
3057 	fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
3058 	    "", "-------------", "-------", "-------");
3059 	fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
3060 	    "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);
3061 }
3062