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