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