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