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