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