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