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