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