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