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