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