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