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