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