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