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