xref: /freebsd/usr.bin/truss/syscalls.c (revision 8b238f4126d32df3e70056bc32536b7248ebffa0)
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, uintptr_t offset, void *buf, int len)
1055 {
1056 	struct ptrace_io_desc iorequest;
1057 
1058 	iorequest.piod_op = PIOD_READ_D;
1059 	iorequest.piod_offs = (void *)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, uintptr_t 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 = (void *)(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_pointer(FILE *fp, uintptr_t arg)
1187 {
1188 
1189 	fprintf(fp, "%p", (void *)arg);
1190 }
1191 
1192 static void
1193 print_sockaddr(FILE *fp, struct trussinfo *trussinfo, uintptr_t arg,
1194     socklen_t len)
1195 {
1196 	char addr[64];
1197 	struct sockaddr_in *lsin;
1198 	struct sockaddr_in6 *lsin6;
1199 	struct sockaddr_un *sun;
1200 	struct sockaddr *sa;
1201 	u_char *q;
1202 	pid_t pid = trussinfo->curthread->proc->pid;
1203 
1204 	if (arg == 0) {
1205 		fputs("NULL", fp);
1206 		return;
1207 	}
1208 	/* If the length is too small, just bail. */
1209 	if (len < sizeof(*sa)) {
1210 		print_pointer(fp, arg);
1211 		return;
1212 	}
1213 
1214 	sa = calloc(1, len);
1215 	if (get_struct(pid, arg, sa, len) == -1) {
1216 		free(sa);
1217 		print_pointer(fp, arg);
1218 		return;
1219 	}
1220 
1221 	switch (sa->sa_family) {
1222 	case AF_INET:
1223 		if (len < sizeof(*lsin))
1224 			goto sockaddr_short;
1225 		lsin = (struct sockaddr_in *)(void *)sa;
1226 		inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1227 		fprintf(fp, "{ AF_INET %s:%d }", addr,
1228 		    htons(lsin->sin_port));
1229 		break;
1230 	case AF_INET6:
1231 		if (len < sizeof(*lsin6))
1232 			goto sockaddr_short;
1233 		lsin6 = (struct sockaddr_in6 *)(void *)sa;
1234 		inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1235 		    sizeof(addr));
1236 		fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1237 		    htons(lsin6->sin6_port));
1238 		break;
1239 	case AF_UNIX:
1240 		sun = (struct sockaddr_un *)sa;
1241 		fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1242 		    (int)(len - offsetof(struct sockaddr_un, sun_path)),
1243 		    sun->sun_path);
1244 		break;
1245 	default:
1246 	sockaddr_short:
1247 		fprintf(fp,
1248 		    "{ sa_len = %d, sa_family = %d, sa_data = {",
1249 		    (int)sa->sa_len, (int)sa->sa_family);
1250 		for (q = (u_char *)sa->sa_data;
1251 		     q < (u_char *)sa + len; q++)
1252 			fprintf(fp, "%s 0x%02x",
1253 			    q == (u_char *)sa->sa_data ? "" : ",",
1254 			    *q);
1255 		fputs(" } }", fp);
1256 	}
1257 	free(sa);
1258 }
1259 
1260 #define IOV_LIMIT 16
1261 
1262 static void
1263 print_iovec(FILE *fp, struct trussinfo *trussinfo, uintptr_t arg, int iovcnt)
1264 {
1265 	struct iovec iov[IOV_LIMIT];
1266 	size_t max_string = trussinfo->strsize;
1267 	char tmp2[max_string + 1], *tmp3;
1268 	size_t len;
1269 	pid_t pid = trussinfo->curthread->proc->pid;
1270 	int i;
1271 	bool buf_truncated, iov_truncated;
1272 
1273 	if (iovcnt <= 0) {
1274 		print_pointer(fp, arg);
1275 		return;
1276 	}
1277 	if (iovcnt > IOV_LIMIT) {
1278 		iovcnt = IOV_LIMIT;
1279 		iov_truncated = true;
1280 	} else {
1281 		iov_truncated = false;
1282 	}
1283 	if (get_struct(pid, arg, &iov, iovcnt * sizeof(struct iovec)) == -1) {
1284 		print_pointer(fp, arg);
1285 		return;
1286 	}
1287 
1288 	fputs("[", fp);
1289 	for (i = 0; i < iovcnt; i++) {
1290 		len = iov[i].iov_len;
1291 		if (len > max_string) {
1292 			len = max_string;
1293 			buf_truncated = true;
1294 		} else {
1295 			buf_truncated = false;
1296 		}
1297 		fprintf(fp, "%s{", (i > 0) ? "," : "");
1298 		if (len && get_struct(pid, (uintptr_t)iov[i].iov_base, &tmp2, len) != -1) {
1299 			tmp3 = malloc(len * 4 + 1);
1300 			while (len) {
1301 				if (strvisx(tmp3, tmp2, len,
1302 				    VIS_CSTYLE|VIS_TAB|VIS_NL) <=
1303 				    (int)max_string)
1304 					break;
1305 				len--;
1306 				buf_truncated = true;
1307 			}
1308 			fprintf(fp, "\"%s\"%s", tmp3,
1309 			    buf_truncated ? "..." : "");
1310 			free(tmp3);
1311 		} else {
1312 			print_pointer(fp, (uintptr_t)iov[i].iov_base);
1313 		}
1314 		fprintf(fp, ",%zu}", iov[i].iov_len);
1315 	}
1316 	fprintf(fp, "%s%s", iov_truncated ? ",..." : "", "]");
1317 }
1318 
1319 static void
1320 print_gen_cmsg(FILE *fp, struct cmsghdr *cmsghdr)
1321 {
1322 	u_char *q;
1323 
1324 	fputs("{", fp);
1325 	for (q = CMSG_DATA(cmsghdr);
1326 	     q < (u_char *)cmsghdr + cmsghdr->cmsg_len; q++) {
1327 		fprintf(fp, "%s0x%02x", q == CMSG_DATA(cmsghdr) ? "" : ",", *q);
1328 	}
1329 	fputs("}", fp);
1330 }
1331 
1332 static void
1333 print_sctp_initmsg(FILE *fp, struct sctp_initmsg *init)
1334 {
1335 	fprintf(fp, "{out=%u,", init->sinit_num_ostreams);
1336 	fprintf(fp, "in=%u,", init->sinit_max_instreams);
1337 	fprintf(fp, "max_rtx=%u,", init->sinit_max_attempts);
1338 	fprintf(fp, "max_rto=%u}", init->sinit_max_init_timeo);
1339 }
1340 
1341 static void
1342 print_sctp_sndrcvinfo(FILE *fp, bool receive, struct sctp_sndrcvinfo *info)
1343 {
1344 	fprintf(fp, "{sid=%u,", info->sinfo_stream);
1345 	if (receive) {
1346 		fprintf(fp, "ssn=%u,", info->sinfo_ssn);
1347 	}
1348 	fputs("flgs=", fp);
1349 	sysdecode_sctp_sinfo_flags(fp, info->sinfo_flags);
1350 	fprintf(fp, ",ppid=%u,", ntohl(info->sinfo_ppid));
1351 	if (!receive) {
1352 		fprintf(fp, "ctx=%u,", info->sinfo_context);
1353 		fprintf(fp, "ttl=%u,", info->sinfo_timetolive);
1354 	}
1355 	if (receive) {
1356 		fprintf(fp, "tsn=%u,", info->sinfo_tsn);
1357 		fprintf(fp, "cumtsn=%u,", info->sinfo_cumtsn);
1358 	}
1359 	fprintf(fp, "id=%u}", info->sinfo_assoc_id);
1360 }
1361 
1362 static void
1363 print_sctp_sndinfo(FILE *fp, struct sctp_sndinfo *info)
1364 {
1365 	fprintf(fp, "{sid=%u,", info->snd_sid);
1366 	fputs("flgs=", fp);
1367 	print_mask_arg(sysdecode_sctp_snd_flags, fp, info->snd_flags);
1368 	fprintf(fp, ",ppid=%u,", ntohl(info->snd_ppid));
1369 	fprintf(fp, "ctx=%u,", info->snd_context);
1370 	fprintf(fp, "id=%u}", info->snd_assoc_id);
1371 }
1372 
1373 static void
1374 print_sctp_rcvinfo(FILE *fp, struct sctp_rcvinfo *info)
1375 {
1376 	fprintf(fp, "{sid=%u,", info->rcv_sid);
1377 	fprintf(fp, "ssn=%u,", info->rcv_ssn);
1378 	fputs("flgs=", fp);
1379 	print_mask_arg(sysdecode_sctp_rcv_flags, fp, info->rcv_flags);
1380 	fprintf(fp, ",ppid=%u,", ntohl(info->rcv_ppid));
1381 	fprintf(fp, "tsn=%u,", info->rcv_tsn);
1382 	fprintf(fp, "cumtsn=%u,", info->rcv_cumtsn);
1383 	fprintf(fp, "ctx=%u,", info->rcv_context);
1384 	fprintf(fp, "id=%u}", info->rcv_assoc_id);
1385 }
1386 
1387 static void
1388 print_sctp_nxtinfo(FILE *fp, struct sctp_nxtinfo *info)
1389 {
1390 	fprintf(fp, "{sid=%u,", info->nxt_sid);
1391 	fputs("flgs=", fp);
1392 	print_mask_arg(sysdecode_sctp_nxt_flags, fp, info->nxt_flags);
1393 	fprintf(fp, ",ppid=%u,", ntohl(info->nxt_ppid));
1394 	fprintf(fp, "len=%u,", info->nxt_length);
1395 	fprintf(fp, "id=%u}", info->nxt_assoc_id);
1396 }
1397 
1398 static void
1399 print_sctp_prinfo(FILE *fp, struct sctp_prinfo *info)
1400 {
1401 	fputs("{pol=", fp);
1402 	print_integer_arg(sysdecode_sctp_pr_policy, fp, info->pr_policy);
1403 	fprintf(fp, ",val=%u}", info->pr_value);
1404 }
1405 
1406 static void
1407 print_sctp_authinfo(FILE *fp, struct sctp_authinfo *info)
1408 {
1409 	fprintf(fp, "{num=%u}", info->auth_keynumber);
1410 }
1411 
1412 static void
1413 print_sctp_ipv4_addr(FILE *fp, struct in_addr *addr)
1414 {
1415 	char buf[INET_ADDRSTRLEN];
1416 	const char *s;
1417 
1418 	s = inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN);
1419 	if (s != NULL)
1420 		fprintf(fp, "{addr=%s}", s);
1421 	else
1422 		fputs("{addr=???}", fp);
1423 }
1424 
1425 static void
1426 print_sctp_ipv6_addr(FILE *fp, struct in6_addr *addr)
1427 {
1428 	char buf[INET6_ADDRSTRLEN];
1429 	const char *s;
1430 
1431 	s = inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN);
1432 	if (s != NULL)
1433 		fprintf(fp, "{addr=%s}", s);
1434 	else
1435 		fputs("{addr=???}", fp);
1436 }
1437 
1438 static void
1439 print_sctp_cmsg(FILE *fp, bool receive, struct cmsghdr *cmsghdr)
1440 {
1441 	void *data;
1442 	socklen_t len;
1443 
1444 	len = cmsghdr->cmsg_len;
1445 	data = CMSG_DATA(cmsghdr);
1446 	switch (cmsghdr->cmsg_type) {
1447 	case SCTP_INIT:
1448 		if (len == CMSG_LEN(sizeof(struct sctp_initmsg)))
1449 			print_sctp_initmsg(fp, (struct sctp_initmsg *)data);
1450 		else
1451 			print_gen_cmsg(fp, cmsghdr);
1452 		break;
1453 	case SCTP_SNDRCV:
1454 		if (len == CMSG_LEN(sizeof(struct sctp_sndrcvinfo)))
1455 			print_sctp_sndrcvinfo(fp, receive,
1456 			    (struct sctp_sndrcvinfo *)data);
1457 		else
1458 			print_gen_cmsg(fp, cmsghdr);
1459 		break;
1460 #if 0
1461 	case SCTP_EXTRCV:
1462 		if (len == CMSG_LEN(sizeof(struct sctp_extrcvinfo)))
1463 			print_sctp_extrcvinfo(fp,
1464 			    (struct sctp_extrcvinfo *)data);
1465 		else
1466 			print_gen_cmsg(fp, cmsghdr);
1467 		break;
1468 #endif
1469 	case SCTP_SNDINFO:
1470 		if (len == CMSG_LEN(sizeof(struct sctp_sndinfo)))
1471 			print_sctp_sndinfo(fp, (struct sctp_sndinfo *)data);
1472 		else
1473 			print_gen_cmsg(fp, cmsghdr);
1474 		break;
1475 	case SCTP_RCVINFO:
1476 		if (len == CMSG_LEN(sizeof(struct sctp_rcvinfo)))
1477 			print_sctp_rcvinfo(fp, (struct sctp_rcvinfo *)data);
1478 		else
1479 			print_gen_cmsg(fp, cmsghdr);
1480 		break;
1481 	case SCTP_NXTINFO:
1482 		if (len == CMSG_LEN(sizeof(struct sctp_nxtinfo)))
1483 			print_sctp_nxtinfo(fp, (struct sctp_nxtinfo *)data);
1484 		else
1485 			print_gen_cmsg(fp, cmsghdr);
1486 		break;
1487 	case SCTP_PRINFO:
1488 		if (len == CMSG_LEN(sizeof(struct sctp_prinfo)))
1489 			print_sctp_prinfo(fp, (struct sctp_prinfo *)data);
1490 		else
1491 			print_gen_cmsg(fp, cmsghdr);
1492 		break;
1493 	case SCTP_AUTHINFO:
1494 		if (len == CMSG_LEN(sizeof(struct sctp_authinfo)))
1495 			print_sctp_authinfo(fp, (struct sctp_authinfo *)data);
1496 		else
1497 			print_gen_cmsg(fp, cmsghdr);
1498 		break;
1499 	case SCTP_DSTADDRV4:
1500 		if (len == CMSG_LEN(sizeof(struct in_addr)))
1501 			print_sctp_ipv4_addr(fp, (struct in_addr *)data);
1502 		else
1503 			print_gen_cmsg(fp, cmsghdr);
1504 		break;
1505 	case SCTP_DSTADDRV6:
1506 		if (len == CMSG_LEN(sizeof(struct in6_addr)))
1507 			print_sctp_ipv6_addr(fp, (struct in6_addr *)data);
1508 		else
1509 			print_gen_cmsg(fp, cmsghdr);
1510 		break;
1511 	default:
1512 		print_gen_cmsg(fp, cmsghdr);
1513 	}
1514 }
1515 
1516 static void
1517 print_cmsgs(FILE *fp, pid_t pid, bool receive, struct msghdr *msghdr)
1518 {
1519 	struct cmsghdr *cmsghdr;
1520 	char *cmsgbuf;
1521 	const char *temp;
1522 	socklen_t len;
1523 	int level, type;
1524 	bool first;
1525 
1526 	len = msghdr->msg_controllen;
1527 	if (len == 0) {
1528 		fputs("{}", fp);
1529 		return;
1530 	}
1531 	cmsgbuf = calloc(1, len);
1532 	if (get_struct(pid, (uintptr_t)msghdr->msg_control, cmsgbuf, len) == -1) {
1533 		print_pointer(fp, (uintptr_t)msghdr->msg_control);
1534 		free(cmsgbuf);
1535 		return;
1536 	}
1537 	msghdr->msg_control = cmsgbuf;
1538 	first = true;
1539 	fputs("{", fp);
1540 	for (cmsghdr = CMSG_FIRSTHDR(msghdr);
1541 	   cmsghdr != NULL;
1542 	   cmsghdr = CMSG_NXTHDR(msghdr, cmsghdr)) {
1543 		level = cmsghdr->cmsg_level;
1544 		type = cmsghdr->cmsg_type;
1545 		len = cmsghdr->cmsg_len;
1546 		fprintf(fp, "%s{level=", first ? "" : ",");
1547 		print_integer_arg(sysdecode_sockopt_level, fp, level);
1548 		fputs(",type=", fp);
1549 		temp = sysdecode_cmsg_type(level, type);
1550 		if (temp) {
1551 			fputs(temp, fp);
1552 		} else {
1553 			fprintf(fp, "%d", type);
1554 		}
1555 		fputs(",data=", fp);
1556 		switch (level) {
1557 		case IPPROTO_SCTP:
1558 			print_sctp_cmsg(fp, receive, cmsghdr);
1559 			break;
1560 		default:
1561 			print_gen_cmsg(fp, cmsghdr);
1562 			break;
1563 		}
1564 		fputs("}", fp);
1565 		first = false;
1566 	}
1567 	fputs("}", fp);
1568 	free(cmsgbuf);
1569 }
1570 
1571 static void
1572 print_sysctl_oid(FILE *fp, int *oid, int len)
1573 {
1574 	int i;
1575 
1576 	for (i = 0; i < len; i++)
1577 		fprintf(fp, ".%d", oid[i]);
1578 }
1579 
1580 /*
1581  * Converts a syscall argument into a string.  Said string is
1582  * allocated via malloc(), so needs to be free()'d.  sc is
1583  * a pointer to the syscall description (see above); args is
1584  * an array of all of the system call arguments.
1585  */
1586 char *
1587 print_arg(struct syscall_args *sc, unsigned long *args, register_t *retval,
1588     struct trussinfo *trussinfo)
1589 {
1590 	FILE *fp;
1591 	char *tmp;
1592 	size_t tmplen;
1593 	pid_t pid;
1594 
1595 	fp = open_memstream(&tmp, &tmplen);
1596 	pid = trussinfo->curthread->proc->pid;
1597 	switch (sc->type & ARG_MASK) {
1598 	case Hex:
1599 		fprintf(fp, "0x%x", (int)args[sc->offset]);
1600 		break;
1601 	case Octal:
1602 		fprintf(fp, "0%o", (int)args[sc->offset]);
1603 		break;
1604 	case Int:
1605 		fprintf(fp, "%d", (int)args[sc->offset]);
1606 		break;
1607 	case UInt:
1608 		fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1609 		break;
1610 	case PUInt: {
1611 		unsigned int val;
1612 
1613 		if (get_struct(pid, args[sc->offset], &val,
1614 		    sizeof(val)) == 0)
1615 			fprintf(fp, "{ %u }", val);
1616 		else
1617 			print_pointer(fp, args[sc->offset]);
1618 		break;
1619 	}
1620 	case LongHex:
1621 		fprintf(fp, "0x%lx", args[sc->offset]);
1622 		break;
1623 	case Long:
1624 		fprintf(fp, "%ld", args[sc->offset]);
1625 		break;
1626 	case Sizet:
1627 		fprintf(fp, "%zu", (size_t)args[sc->offset]);
1628 		break;
1629 	case ShmName:
1630 		/* Handle special SHM_ANON value. */
1631 		if ((char *)args[sc->offset] == SHM_ANON) {
1632 			fprintf(fp, "SHM_ANON");
1633 			break;
1634 		}
1635 		/* FALLTHROUGH */
1636 	case Name: {
1637 		/* NULL-terminated string. */
1638 		char *tmp2;
1639 
1640 		tmp2 = get_string(pid, args[sc->offset], 0);
1641 		fprintf(fp, "\"%s\"", tmp2);
1642 		free(tmp2);
1643 		break;
1644 	}
1645 	case BinString: {
1646 		/*
1647 		 * Binary block of data that might have printable characters.
1648 		 * XXX If type|OUT, assume that the length is the syscall's
1649 		 * return value.  Otherwise, assume that the length of the block
1650 		 * is in the next syscall argument.
1651 		 */
1652 		int max_string = trussinfo->strsize;
1653 		char tmp2[max_string + 1], *tmp3;
1654 		int len;
1655 		int truncated = 0;
1656 
1657 		if (sc->type & OUT)
1658 			len = retval[0];
1659 		else
1660 			len = args[sc->offset + 1];
1661 
1662 		/*
1663 		 * Don't print more than max_string characters, to avoid word
1664 		 * wrap.  If we have to truncate put some ... after the string.
1665 		 */
1666 		if (len > max_string) {
1667 			len = max_string;
1668 			truncated = 1;
1669 		}
1670 		if (len && get_struct(pid, args[sc->offset], &tmp2, len)
1671 		    != -1) {
1672 			tmp3 = malloc(len * 4 + 1);
1673 			while (len) {
1674 				if (strvisx(tmp3, tmp2, len,
1675 				    VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1676 					break;
1677 				len--;
1678 				truncated = 1;
1679 			}
1680 			fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1681 			    "..." : "");
1682 			free(tmp3);
1683 		} else {
1684 			print_pointer(fp, args[sc->offset]);
1685 		}
1686 		break;
1687 	}
1688 	case ExecArgs:
1689 	case ExecEnv:
1690 	case StringArray: {
1691 		uintptr_t addr;
1692 		union {
1693 			char *strarray[0];
1694 			char buf[PAGE_SIZE];
1695 		} u;
1696 		char *string;
1697 		size_t len;
1698 		u_int first, i;
1699 
1700 		/*
1701 		 * Only parse argv[] and environment arrays from exec calls
1702 		 * if requested.
1703 		 */
1704 		if (((sc->type & ARG_MASK) == ExecArgs &&
1705 		    (trussinfo->flags & EXECVEARGS) == 0) ||
1706 		    ((sc->type & ARG_MASK) == ExecEnv &&
1707 		    (trussinfo->flags & EXECVEENVS) == 0)) {
1708 			print_pointer(fp, args[sc->offset]);
1709 			break;
1710 		}
1711 
1712 		/*
1713 		 * Read a page of pointers at a time.  Punt if the top-level
1714 		 * pointer is not aligned.  Note that the first read is of
1715 		 * a partial page.
1716 		 */
1717 		addr = args[sc->offset];
1718 		if (addr % sizeof(char *) != 0) {
1719 			print_pointer(fp, args[sc->offset]);
1720 			break;
1721 		}
1722 
1723 		len = PAGE_SIZE - (addr & PAGE_MASK);
1724 		if (get_struct(pid, addr, u.buf, len) == -1) {
1725 			print_pointer(fp, args[sc->offset]);
1726 			break;
1727 		}
1728 
1729 		fputc('[', fp);
1730 		first = 1;
1731 		i = 0;
1732 		while (u.strarray[i] != NULL) {
1733 			string = get_string(pid, (uintptr_t)u.strarray[i], 0);
1734 			fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1735 			free(string);
1736 			first = 0;
1737 
1738 			i++;
1739 			if (i == len / sizeof(char *)) {
1740 				addr += len;
1741 				len = PAGE_SIZE;
1742 				if (get_struct(pid, addr, u.buf, len) ==
1743 				    -1) {
1744 					fprintf(fp, ", <inval>");
1745 					break;
1746 				}
1747 				i = 0;
1748 			}
1749 		}
1750 		fputs(" ]", fp);
1751 		break;
1752 	}
1753 #ifdef __LP64__
1754 	case Quad:
1755 		fprintf(fp, "%ld", args[sc->offset]);
1756 		break;
1757 	case QuadHex:
1758 		fprintf(fp, "0x%lx", args[sc->offset]);
1759 		break;
1760 #else
1761 	case Quad:
1762 	case QuadHex: {
1763 		unsigned long long ll;
1764 
1765 #if _BYTE_ORDER == _LITTLE_ENDIAN
1766 		ll = (unsigned long long)args[sc->offset + 1] << 32 |
1767 		    args[sc->offset];
1768 #else
1769 		ll = (unsigned long long)args[sc->offset] << 32 |
1770 		    args[sc->offset + 1];
1771 #endif
1772 		if ((sc->type & ARG_MASK) == Quad)
1773 			fprintf(fp, "%lld", ll);
1774 		else
1775 			fprintf(fp, "0x%llx", ll);
1776 		break;
1777 	}
1778 #endif
1779 	case PQuadHex: {
1780 		uint64_t val;
1781 
1782 		if (get_struct(pid, args[sc->offset], &val,
1783 		    sizeof(val)) == 0)
1784 			fprintf(fp, "{ 0x%jx }", (uintmax_t)val);
1785 		else
1786 			print_pointer(fp, args[sc->offset]);
1787 		break;
1788 	}
1789 	case Ptr:
1790 		print_pointer(fp, args[sc->offset]);
1791 		break;
1792 	case Readlinkres: {
1793 		char *tmp2;
1794 
1795 		if (retval[0] == -1)
1796 			break;
1797 		tmp2 = get_string(pid, args[sc->offset], retval[0]);
1798 		fprintf(fp, "\"%s\"", tmp2);
1799 		free(tmp2);
1800 		break;
1801 	}
1802 	case Ioctl: {
1803 		const char *temp;
1804 		unsigned long cmd;
1805 
1806 		cmd = args[sc->offset];
1807 		temp = sysdecode_ioctlname(cmd);
1808 		if (temp)
1809 			fputs(temp, fp);
1810 		else {
1811 			fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1812 			    cmd, cmd & IOC_OUT ? "R" : "",
1813 			    cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1814 			    isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1815 			    cmd & 0xFF, IOCPARM_LEN(cmd));
1816 		}
1817 		break;
1818 	}
1819 	case Timespec: {
1820 		struct timespec ts;
1821 
1822 		if (get_struct(pid, args[sc->offset], &ts, sizeof(ts)) != -1)
1823 			fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1824 			    ts.tv_nsec);
1825 		else
1826 			print_pointer(fp, args[sc->offset]);
1827 		break;
1828 	}
1829 	case Timespec2: {
1830 		struct timespec ts[2];
1831 		const char *sep;
1832 		unsigned int i;
1833 
1834 		if (get_struct(pid, args[sc->offset], &ts, sizeof(ts)) != -1) {
1835 			fputs("{ ", fp);
1836 			sep = "";
1837 			for (i = 0; i < nitems(ts); i++) {
1838 				fputs(sep, fp);
1839 				sep = ", ";
1840 				switch (ts[i].tv_nsec) {
1841 				case UTIME_NOW:
1842 					fprintf(fp, "UTIME_NOW");
1843 					break;
1844 				case UTIME_OMIT:
1845 					fprintf(fp, "UTIME_OMIT");
1846 					break;
1847 				default:
1848 					fprintf(fp, "%jd.%09ld",
1849 					    (intmax_t)ts[i].tv_sec,
1850 					    ts[i].tv_nsec);
1851 					break;
1852 				}
1853 			}
1854 			fputs(" }", fp);
1855 		} else
1856 			print_pointer(fp, args[sc->offset]);
1857 		break;
1858 	}
1859 	case Timeval: {
1860 		struct timeval tv;
1861 
1862 		if (get_struct(pid, args[sc->offset], &tv, sizeof(tv)) != -1)
1863 			fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1864 			    tv.tv_usec);
1865 		else
1866 			print_pointer(fp, args[sc->offset]);
1867 		break;
1868 	}
1869 	case Timeval2: {
1870 		struct timeval tv[2];
1871 
1872 		if (get_struct(pid, args[sc->offset], &tv, sizeof(tv)) != -1)
1873 			fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1874 			    (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1875 			    (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1876 		else
1877 			print_pointer(fp, args[sc->offset]);
1878 		break;
1879 	}
1880 	case Itimerval: {
1881 		struct itimerval itv;
1882 
1883 		if (get_struct(pid, args[sc->offset], &itv, sizeof(itv)) != -1)
1884 			fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1885 			    (intmax_t)itv.it_interval.tv_sec,
1886 			    itv.it_interval.tv_usec,
1887 			    (intmax_t)itv.it_value.tv_sec,
1888 			    itv.it_value.tv_usec);
1889 		else
1890 			print_pointer(fp, args[sc->offset]);
1891 		break;
1892 	}
1893 	case LinuxSockArgs:
1894 	{
1895 		struct linux_socketcall_args largs;
1896 
1897 		if (get_struct(pid, args[sc->offset], (void *)&largs,
1898 		    sizeof(largs)) != -1)
1899 			fprintf(fp, "{ %s, 0x%lx }",
1900 			    lookup(linux_socketcall_ops, largs.what, 10),
1901 			    (long unsigned int)largs.args);
1902 		else
1903 			print_pointer(fp, args[sc->offset]);
1904 		break;
1905 	}
1906 	case Pollfd: {
1907 		/*
1908 		 * XXX: A Pollfd argument expects the /next/ syscall argument
1909 		 * to be the number of fds in the array. This matches the poll
1910 		 * syscall.
1911 		 */
1912 		struct pollfd *pfd;
1913 		int numfds = args[sc->offset + 1];
1914 		size_t bytes = sizeof(struct pollfd) * numfds;
1915 		int i;
1916 
1917 		if ((pfd = malloc(bytes)) == NULL)
1918 			err(1, "Cannot malloc %zu bytes for pollfd array",
1919 			    bytes);
1920 		if (get_struct(pid, args[sc->offset], pfd, bytes) != -1) {
1921 			fputs("{", fp);
1922 			for (i = 0; i < numfds; i++) {
1923 				fprintf(fp, " %d/%s", pfd[i].fd,
1924 				    xlookup_bits(poll_flags, pfd[i].events));
1925 			}
1926 			fputs(" }", fp);
1927 		} else {
1928 			print_pointer(fp, args[sc->offset]);
1929 		}
1930 		free(pfd);
1931 		break;
1932 	}
1933 	case Fd_set: {
1934 		/*
1935 		 * XXX: A Fd_set argument expects the /first/ syscall argument
1936 		 * to be the number of fds in the array.  This matches the
1937 		 * select syscall.
1938 		 */
1939 		fd_set *fds;
1940 		int numfds = args[0];
1941 		size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1942 		int i;
1943 
1944 		if ((fds = malloc(bytes)) == NULL)
1945 			err(1, "Cannot malloc %zu bytes for fd_set array",
1946 			    bytes);
1947 		if (get_struct(pid, args[sc->offset], fds, bytes) != -1) {
1948 			fputs("{", fp);
1949 			for (i = 0; i < numfds; i++) {
1950 				if (FD_ISSET(i, fds))
1951 					fprintf(fp, " %d", i);
1952 			}
1953 			fputs(" }", fp);
1954 		} else
1955 			print_pointer(fp, args[sc->offset]);
1956 		free(fds);
1957 		break;
1958 	}
1959 	case Signal:
1960 		fputs(strsig2(args[sc->offset]), fp);
1961 		break;
1962 	case Sigset: {
1963 		long sig;
1964 		sigset_t ss;
1965 		int i, first;
1966 
1967 		sig = args[sc->offset];
1968 		if (get_struct(pid, args[sc->offset], (void *)&ss,
1969 		    sizeof(ss)) == -1) {
1970 			print_pointer(fp, args[sc->offset]);
1971 			break;
1972 		}
1973 		fputs("{ ", fp);
1974 		first = 1;
1975 		for (i = 1; i < sys_nsig; i++) {
1976 			if (sigismember(&ss, i)) {
1977 				fprintf(fp, "%s%s", !first ? "|" : "",
1978 				    strsig2(i));
1979 				first = 0;
1980 			}
1981 		}
1982 		if (!first)
1983 			fputc(' ', fp);
1984 		fputc('}', fp);
1985 		break;
1986 	}
1987 	case Sigprocmask:
1988 		print_integer_arg(sysdecode_sigprocmask_how, fp,
1989 		    args[sc->offset]);
1990 		break;
1991 	case Fcntlflag:
1992 		/* XXX: Output depends on the value of the previous argument. */
1993 		if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
1994 			sysdecode_fcntl_arg(fp, args[sc->offset - 1],
1995 			    args[sc->offset], 16);
1996 		break;
1997 	case Open:
1998 		print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
1999 		break;
2000 	case Fcntl:
2001 		print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
2002 		break;
2003 	case Mprot:
2004 		print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
2005 		break;
2006 	case Mmapflags:
2007 		print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
2008 		break;
2009 	case Whence:
2010 		print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
2011 		break;
2012 	case Sockdomain:
2013 		print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
2014 		break;
2015 	case Socktype:
2016 		print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
2017 		break;
2018 	case Shutdown:
2019 		print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
2020 		break;
2021 	case Resource:
2022 		print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
2023 		break;
2024 	case RusageWho:
2025 		print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]);
2026 		break;
2027 	case Pathconf:
2028 		print_integer_arg(sysdecode_pathconf_name, fp, args[sc->offset]);
2029 		break;
2030 	case Rforkflags:
2031 		print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
2032 		break;
2033 	case Sockaddr: {
2034 		socklen_t len;
2035 
2036 		if (args[sc->offset] == 0) {
2037 			fputs("NULL", fp);
2038 			break;
2039 		}
2040 
2041 		/*
2042 		 * Extract the address length from the next argument.  If
2043 		 * this is an output sockaddr (OUT is set), then the
2044 		 * next argument is a pointer to a socklen_t.  Otherwise
2045 		 * the next argument contains a socklen_t by value.
2046 		 */
2047 		if (sc->type & OUT) {
2048 			if (get_struct(pid, args[sc->offset + 1], &len,
2049 			    sizeof(len)) == -1) {
2050 				print_pointer(fp, args[sc->offset]);
2051 				break;
2052 			}
2053 		} else
2054 			len = args[sc->offset + 1];
2055 
2056 		print_sockaddr(fp, trussinfo, args[sc->offset], len);
2057 		break;
2058 	}
2059 	case Sigaction: {
2060 		struct sigaction sa;
2061 
2062 		if (get_struct(pid, args[sc->offset], &sa, sizeof(sa)) != -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 			print_pointer(fp, 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, 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 			print_pointer(fp, 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, 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 			print_pointer(fp, args[sc->offset]);
2153 		}
2154 		free(ke11);
2155 		break;
2156 	}
2157 	case Stat: {
2158 		struct stat st;
2159 
2160 		if (get_struct(pid, 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 			print_pointer(fp, args[sc->offset]);
2171 		}
2172 		break;
2173 	}
2174 	case Stat11: {
2175 		struct freebsd11_stat st;
2176 
2177 		if (get_struct(pid, 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 			print_pointer(fp, args[sc->offset]);
2188 		}
2189 		break;
2190 	}
2191 	case StatFs: {
2192 		unsigned int i;
2193 		struct statfs buf;
2194 
2195 		if (get_struct(pid, 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 			print_pointer(fp, args[sc->offset]);
2212 		break;
2213 	}
2214 
2215 	case Rusage: {
2216 		struct rusage ru;
2217 
2218 		if (get_struct(pid, 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 			print_pointer(fp, args[sc->offset]);
2227 		break;
2228 	}
2229 	case Rlimit: {
2230 		struct rlimit rl;
2231 
2232 		if (get_struct(pid, 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 			print_pointer(fp, args[sc->offset]);
2238 		break;
2239 	}
2240 	case ExitStatus: {
2241 		int status;
2242 
2243 		if (get_struct(pid, 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 			print_pointer(fp, 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, 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, args[sc->offset],
2366 		    (void *)utrace_addr, len) != -1)
2367 			print_utrace(fp, utrace_addr, len);
2368 		else
2369 			print_pointer(fp, 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, 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 			print_pointer(fp, 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, args[sc->offset], &rights,
2403 			    sizeof(rights)) == -1) {
2404 				print_pointer(fp, 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, args[sc->offset], &rights,
2487 		    sizeof(rights)) != -1) {
2488 			fputs("{ ", fp);
2489 			sysdecode_cap_rights(fp, &rights);
2490 			fputs(" }", fp);
2491 		} else
2492 			print_pointer(fp, 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, args[sc->offset], &sp, sizeof(sp)) != -1)
2541 			fprintf(fp, "{ %d }", sp.sched_priority);
2542 		else
2543 			print_pointer(fp, args[sc->offset]);
2544 		break;
2545 	}
2546 	case PSig: {
2547 		int sig;
2548 
2549 		if (get_struct(pid, args[sc->offset], &sig, sizeof(sig)) == 0)
2550 			fprintf(fp, "{ %s }", strsig2(sig));
2551 		else
2552 			print_pointer(fp, args[sc->offset]);
2553 		break;
2554 	}
2555 	case Siginfo: {
2556 		siginfo_t si;
2557 
2558 		if (get_struct(pid, args[sc->offset], &si, sizeof(si)) != -1) {
2559 			fprintf(fp, "{ signo=%s", strsig2(si.si_signo));
2560 			decode_siginfo(fp, &si);
2561 			fprintf(fp, " }");
2562 		} else
2563 			print_pointer(fp, args[sc->offset]);
2564 		break;
2565 	}
2566 	case Iovec:
2567 		/*
2568 		 * Print argument as an array of struct iovec, where the next
2569 		 * syscall argument is the number of elements of the array.
2570 		 */
2571 
2572 		print_iovec(fp, trussinfo, args[sc->offset],
2573 		    (int)args[sc->offset + 1]);
2574 		break;
2575 	case Sctpsndrcvinfo: {
2576 		struct sctp_sndrcvinfo info;
2577 
2578 		if (get_struct(pid, args[sc->offset],
2579 		    &info, sizeof(struct sctp_sndrcvinfo)) == -1) {
2580 			print_pointer(fp, args[sc->offset]);
2581 			break;
2582 		}
2583 		print_sctp_sndrcvinfo(fp, sc->type & OUT, &info);
2584 		break;
2585 	}
2586 	case Msghdr: {
2587 		struct msghdr msghdr;
2588 
2589 		if (get_struct(pid, args[sc->offset],
2590 		    &msghdr, sizeof(struct msghdr)) == -1) {
2591 			print_pointer(fp, args[sc->offset]);
2592 			break;
2593 		}
2594 		fputs("{", fp);
2595 		print_sockaddr(fp, trussinfo, (uintptr_t)msghdr.msg_name, msghdr.msg_namelen);
2596 		fprintf(fp, ",%d,", msghdr.msg_namelen);
2597 		print_iovec(fp, trussinfo, (uintptr_t)msghdr.msg_iov, msghdr.msg_iovlen);
2598 		fprintf(fp, ",%d,", msghdr.msg_iovlen);
2599 		print_cmsgs(fp, pid, sc->type & OUT, &msghdr);
2600 		fprintf(fp, ",%u,", msghdr.msg_controllen);
2601 		print_mask_arg(sysdecode_msg_flags, fp, msghdr.msg_flags);
2602 		fputs("}", fp);
2603 		break;
2604 	}
2605 
2606 	case CloudABIAdvice:
2607 		fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
2608 		break;
2609 	case CloudABIClockID:
2610 		fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2611 		break;
2612 	case CloudABIFDSFlags:
2613 		fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2614 		break;
2615 	case CloudABIFDStat: {
2616 		cloudabi_fdstat_t fds;
2617 		if (get_struct(pid, args[sc->offset], &fds, sizeof(fds))
2618 		    != -1) {
2619 			fprintf(fp, "{ %s, ",
2620 			    xlookup(cloudabi_filetype, fds.fs_filetype));
2621 			fprintf(fp, "%s, ... }",
2622 			    xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2623 		} else
2624 			print_pointer(fp, args[sc->offset]);
2625 		break;
2626 	}
2627 	case CloudABIFileStat: {
2628 		cloudabi_filestat_t fsb;
2629 		if (get_struct(pid, args[sc->offset], &fsb, sizeof(fsb))
2630 		    != -1)
2631 			fprintf(fp, "{ %s, %ju }",
2632 			    xlookup(cloudabi_filetype, fsb.st_filetype),
2633 			    (uintmax_t)fsb.st_size);
2634 		else
2635 			print_pointer(fp, args[sc->offset]);
2636 		break;
2637 	}
2638 	case CloudABIFileType:
2639 		fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2640 		break;
2641 	case CloudABIFSFlags:
2642 		fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2643 		break;
2644 	case CloudABILookup:
2645 		if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2646 			fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2647 			    (int)args[sc->offset]);
2648 		else
2649 			fprintf(fp, "%d", (int)args[sc->offset]);
2650 		break;
2651 	case CloudABIMFlags:
2652 		fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2653 		break;
2654 	case CloudABIMProt:
2655 		fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2656 		break;
2657 	case CloudABIMSFlags:
2658 		fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2659 		break;
2660 	case CloudABIOFlags:
2661 		fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2662 		break;
2663 	case CloudABISDFlags:
2664 		fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2665 		break;
2666 	case CloudABISignal:
2667 		fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2668 		break;
2669 	case CloudABITimestamp:
2670 		fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2671 		    args[sc->offset] % 1000000000);
2672 		break;
2673 	case CloudABIULFlags:
2674 		fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2675 		break;
2676 	case CloudABIWhence:
2677 		fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2678 		break;
2679 
2680 	default:
2681 		errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2682 	}
2683 	fclose(fp);
2684 	return (tmp);
2685 }
2686 
2687 /*
2688  * Print (to outfile) the system call and its arguments.
2689  */
2690 void
2691 print_syscall(struct trussinfo *trussinfo)
2692 {
2693 	struct threadinfo *t;
2694 	const char *name;
2695 	char **s_args;
2696 	int i, len, nargs;
2697 
2698 	t = trussinfo->curthread;
2699 
2700 	name = t->cs.sc->name;
2701 	nargs = t->cs.nargs;
2702 	s_args = t->cs.s_args;
2703 
2704 	len = print_line_prefix(trussinfo);
2705 	len += fprintf(trussinfo->outfile, "%s(", name);
2706 
2707 	for (i = 0; i < nargs; i++) {
2708 		if (s_args[i] != NULL)
2709 			len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2710 		else
2711 			len += fprintf(trussinfo->outfile,
2712 			    "<missing argument>");
2713 		len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2714 		    "," : "");
2715 	}
2716 	len += fprintf(trussinfo->outfile, ")");
2717 	for (i = 0; i < 6 - (len / 8); i++)
2718 		fprintf(trussinfo->outfile, "\t");
2719 }
2720 
2721 void
2722 print_syscall_ret(struct trussinfo *trussinfo, int error, register_t *retval)
2723 {
2724 	struct timespec timediff;
2725 	struct threadinfo *t;
2726 	struct syscall *sc;
2727 
2728 	t = trussinfo->curthread;
2729 	sc = t->cs.sc;
2730 	if (trussinfo->flags & COUNTONLY) {
2731 		timespecsub(&t->after, &t->before, &timediff);
2732 		timespecadd(&sc->time, &timediff, &sc->time);
2733 		sc->ncalls++;
2734 		if (error != 0)
2735 			sc->nerror++;
2736 		return;
2737 	}
2738 
2739 	print_syscall(trussinfo);
2740 	fflush(trussinfo->outfile);
2741 
2742 	if (retval == NULL) {
2743 		/*
2744 		 * This system call resulted in the current thread's exit,
2745 		 * so there is no return value or error to display.
2746 		 */
2747 		fprintf(trussinfo->outfile, "\n");
2748 		return;
2749 	}
2750 
2751 	if (error == ERESTART)
2752 		fprintf(trussinfo->outfile, " ERESTART\n");
2753 	else if (error == EJUSTRETURN)
2754 		fprintf(trussinfo->outfile, " EJUSTRETURN\n");
2755 	else if (error != 0) {
2756 		fprintf(trussinfo->outfile, " ERR#%d '%s'\n",
2757 		    sysdecode_freebsd_to_abi_errno(t->proc->abi->abi, error),
2758 		    strerror(error));
2759 	}
2760 #ifndef __LP64__
2761 	else if (sc->ret_type == 2) {
2762 		off_t off;
2763 
2764 #if _BYTE_ORDER == _LITTLE_ENDIAN
2765 		off = (off_t)retval[1] << 32 | retval[0];
2766 #else
2767 		off = (off_t)retval[0] << 32 | retval[1];
2768 #endif
2769 		fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2770 		    (intmax_t)off);
2771 	}
2772 #endif
2773 	else
2774 		fprintf(trussinfo->outfile, " = %jd (0x%jx)\n",
2775 		    (intmax_t)retval[0], (intmax_t)retval[0]);
2776 }
2777 
2778 void
2779 print_summary(struct trussinfo *trussinfo)
2780 {
2781 	struct timespec total = {0, 0};
2782 	struct syscall *sc;
2783 	int ncall, nerror;
2784 
2785 	fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2786 	    "syscall", "seconds", "calls", "errors");
2787 	ncall = nerror = 0;
2788 	STAILQ_FOREACH(sc, &syscalls, entries)
2789 		if (sc->ncalls) {
2790 			fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2791 			    sc->name, (intmax_t)sc->time.tv_sec,
2792 			    sc->time.tv_nsec, sc->ncalls, sc->nerror);
2793 			timespecadd(&total, &sc->time, &total);
2794 			ncall += sc->ncalls;
2795 			nerror += sc->nerror;
2796 		}
2797 	fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2798 	    "", "-------------", "-------", "-------");
2799 	fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2800 	    "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);
2801 }
2802