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