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