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