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