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