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