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