]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/truss/syscalls.c
Decode the arguments passed to __cap_rights_get() and cap_rights_limit().
[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 <machine/sysarch.h>
52 #include <netinet/in.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 <signal.h>
61 #include <stdbool.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <sysdecode.h>
66 #include <unistd.h>
67 #include <vis.h>
68
69 #include <contrib/cloudabi/cloudabi_types_common.h>
70
71 #include "truss.h"
72 #include "extern.h"
73 #include "syscall.h"
74
75 /*
76  * This should probably be in its own file, sorted alphabetically.
77  */
78 static struct syscall decoded_syscalls[] = {
79         /* Native ABI */
80         { .name = "__cap_rights_get", .ret_type = 1, .nargs = 3,
81           .args = { { Int, 0 }, { Int, 1 }, { CapRights | OUT, 2 } } },
82         { .name = "__getcwd", .ret_type = 1, .nargs = 2,
83           .args = { { Name | OUT, 0 }, { Int, 1 } } },
84         { .name = "_umtx_op", .ret_type = 1, .nargs = 5,
85           .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
86                     { Ptr, 4 } } },
87         { .name = "accept", .ret_type = 1, .nargs = 3,
88           .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
89         { .name = "access", .ret_type = 1, .nargs = 2,
90           .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
91         { .name = "bind", .ret_type = 1, .nargs = 3,
92           .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
93         { .name = "bindat", .ret_type = 1, .nargs = 4,
94           .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
95                     { Int, 3 } } },
96         { .name = "break", .ret_type = 1, .nargs = 1,
97           .args = { { Ptr, 0 } } },
98         { .name = "cap_fcntls_get", .ret_type = 1, .nargs = 2,
99           .args = { { Int, 0 }, { CapFcntlRights | OUT, 1 } } },
100         { .name = "cap_fcntls_limit", .ret_type = 1, .nargs = 2,
101           .args = { { Int, 0 }, { CapFcntlRights, 1 } } },
102         { .name = "cap_rights_limit", .ret_type = 1, .nargs = 2,
103           .args = { { Int, 0 }, { CapRights, 1 } } },
104         { .name = "chdir", .ret_type = 1, .nargs = 1,
105           .args = { { Name, 0 } } },
106         { .name = "chflags", .ret_type = 1, .nargs = 2,
107           .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
108         { .name = "chflagsat", .ret_type = 1, .nargs = 4,
109           .args = { { Atfd, 0 }, { Name | IN, 1 }, { FileFlags, 2 },
110                     { Atflags, 3 } } },
111         { .name = "chmod", .ret_type = 1, .nargs = 2,
112           .args = { { Name, 0 }, { Octal, 1 } } },
113         { .name = "chown", .ret_type = 1, .nargs = 3,
114           .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
115         { .name = "chroot", .ret_type = 1, .nargs = 1,
116           .args = { { Name, 0 } } },
117         { .name = "clock_gettime", .ret_type = 1, .nargs = 2,
118           .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
119         { .name = "close", .ret_type = 1, .nargs = 1,
120           .args = { { Int, 0 } } },
121         { .name = "connect", .ret_type = 1, .nargs = 3,
122           .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
123         { .name = "connectat", .ret_type = 1, .nargs = 4,
124           .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
125                     { Int, 3 } } },
126         { .name = "eaccess", .ret_type = 1, .nargs = 2,
127           .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
128         { .name = "execve", .ret_type = 1, .nargs = 3,
129           .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
130                     { ExecEnv | IN, 2 } } },
131         { .name = "exit", .ret_type = 0, .nargs = 1,
132           .args = { { Hex, 0 } } },
133         { .name = "faccessat", .ret_type = 1, .nargs = 4,
134           .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
135                     { Atflags, 3 } } },
136         { .name = "fchflags", .ret_type = 1, .nargs = 2,
137           .args = { { Int, 0 }, { FileFlags, 1 } } },
138         { .name = "fchmod", .ret_type = 1, .nargs = 2,
139           .args = { { Int, 0 }, { Octal, 1 } } },
140         { .name = "fchmodat", .ret_type = 1, .nargs = 4,
141           .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
142         { .name = "fchown", .ret_type = 1, .nargs = 3,
143           .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
144         { .name = "fchownat", .ret_type = 1, .nargs = 5,
145           .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
146                     { Atflags, 4 } } },
147         { .name = "fcntl", .ret_type = 1, .nargs = 3,
148           .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
149         { .name = "flock", .ret_type = 1, .nargs = 2,
150           .args = { { Int, 0 }, { Flockop, 1 } } },
151         { .name = "fstat", .ret_type = 1, .nargs = 2,
152           .args = { { Int, 0 }, { Stat | OUT, 1 } } },
153         { .name = "fstatat", .ret_type = 1, .nargs = 4,
154           .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
155                     { Atflags, 3 } } },
156         { .name = "fstatfs", .ret_type = 1, .nargs = 2,
157           .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
158         { .name = "ftruncate", .ret_type = 1, .nargs = 2,
159           .args = { { Int | IN, 0 }, { QuadHex | IN, 1 } } },
160         { .name = "futimens", .ret_type = 1, .nargs = 2,
161           .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
162         { .name = "futimes", .ret_type = 1, .nargs = 2,
163           .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
164         { .name = "futimesat", .ret_type = 1, .nargs = 3,
165           .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
166         { .name = "getfsstat", .ret_type = 1, .nargs = 3,
167           .args = { { Ptr, 0 }, { Long, 1 }, { Getfsstatmode, 2 } } },
168         { .name = "getitimer", .ret_type = 1, .nargs = 2,
169           .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
170         { .name = "getpeername", .ret_type = 1, .nargs = 3,
171           .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
172         { .name = "getpgid", .ret_type = 1, .nargs = 1,
173           .args = { { Int, 0 } } },
174         { .name = "getrlimit", .ret_type = 1, .nargs = 2,
175           .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
176         { .name = "getrusage", .ret_type = 1, .nargs = 2,
177           .args = { { Int, 0 }, { Rusage | OUT, 1 } } },
178         { .name = "getsid", .ret_type = 1, .nargs = 1,
179           .args = { { Int, 0 } } },
180         { .name = "getsockname", .ret_type = 1, .nargs = 3,
181           .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
182         { .name = "getsockopt", .ret_type = 1, .nargs = 5,
183           .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
184                     { Ptr | OUT, 3 }, { Ptr | OUT, 4 } } },
185         { .name = "gettimeofday", .ret_type = 1, .nargs = 2,
186           .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
187         { .name = "ioctl", .ret_type = 1, .nargs = 3,
188           .args = { { Int, 0 }, { Ioctl, 1 }, { Ptr, 2 } } },
189         { .name = "kevent", .ret_type = 1, .nargs = 6,
190           .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
191                     { Int, 4 }, { Timespec, 5 } } },
192         { .name = "kill", .ret_type = 1, .nargs = 2,
193           .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
194         { .name = "kldfind", .ret_type = 1, .nargs = 1,
195           .args = { { Name | IN, 0 } } },
196         { .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
197           .args = { { Int, 0 } } },
198         { .name = "kldload", .ret_type = 1, .nargs = 1,
199           .args = { { Name | IN, 0 } } },
200         { .name = "kldnext", .ret_type = 1, .nargs = 1,
201           .args = { { Int, 0 } } },
202         { .name = "kldstat", .ret_type = 1, .nargs = 2,
203           .args = { { Int, 0 }, { Ptr, 1 } } },
204         { .name = "kldsym", .ret_type = 1, .nargs = 3,
205           .args = { { Int, 0 }, { Kldsymcmd, 1 }, { Ptr, 2 } } },
206         { .name = "kldunload", .ret_type = 1, .nargs = 1,
207           .args = { { Int, 0 } } },
208         { .name = "kldunloadf", .ret_type = 1, .nargs = 2,
209           .args = { { Int, 0 }, { Kldunloadflags, 1 } } },
210         { .name = "kse_release", .ret_type = 0, .nargs = 1,
211           .args = { { Timespec, 0 } } },
212         { .name = "lchflags", .ret_type = 1, .nargs = 2,
213           .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
214         { .name = "lchmod", .ret_type = 1, .nargs = 2,
215           .args = { { Name, 0 }, { Octal, 1 } } },
216         { .name = "lchown", .ret_type = 1, .nargs = 3,
217           .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
218         { .name = "link", .ret_type = 1, .nargs = 2,
219           .args = { { Name, 0 }, { Name, 1 } } },
220         { .name = "linkat", .ret_type = 1, .nargs = 5,
221           .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
222                     { Atflags, 4 } } },
223         { .name = "listen", .ret_type = 1, .nargs = 2,
224           .args = { { Int, 0 }, { Int, 1 } } },
225         { .name = "lseek", .ret_type = 2, .nargs = 3,
226           .args = { { Int, 0 }, { QuadHex, 1 }, { Whence, 2 } } },
227         { .name = "lstat", .ret_type = 1, .nargs = 2,
228           .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
229         { .name = "lutimes", .ret_type = 1, .nargs = 2,
230           .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
231         { .name = "madvise", .ret_type = 1, .nargs = 3,
232           .args = { { Ptr, 0 }, { Sizet, 1 }, { Madvice, 2 } } },
233         { .name = "mkdir", .ret_type = 1, .nargs = 2,
234           .args = { { Name, 0 }, { Octal, 1 } } },
235         { .name = "mkdirat", .ret_type = 1, .nargs = 3,
236           .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
237         { .name = "mkfifo", .ret_type = 1, .nargs = 2,
238           .args = { { Name, 0 }, { Octal, 1 } } },
239         { .name = "mkfifoat", .ret_type = 1, .nargs = 3,
240           .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
241         { .name = "mknod", .ret_type = 1, .nargs = 3,
242           .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
243         { .name = "mknodat", .ret_type = 1, .nargs = 4,
244           .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
245         { .name = "mmap", .ret_type = 1, .nargs = 6,
246           .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
247                     { Int, 4 }, { QuadHex, 5 } } },
248         { .name = "modfind", .ret_type = 1, .nargs = 1,
249           .args = { { Name | IN, 0 } } },
250         { .name = "mount", .ret_type = 1, .nargs = 4,
251           .args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } },
252         { .name = "mprotect", .ret_type = 1, .nargs = 3,
253           .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 } } },
254         { .name = "munmap", .ret_type = 1, .nargs = 2,
255           .args = { { Ptr, 0 }, { Sizet, 1 } } },
256         { .name = "nanosleep", .ret_type = 1, .nargs = 1,
257           .args = { { Timespec, 0 } } },
258         { .name = "open", .ret_type = 1, .nargs = 3,
259           .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
260         { .name = "openat", .ret_type = 1, .nargs = 4,
261           .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
262                     { Octal, 3 } } },
263         { .name = "pathconf", .ret_type = 1, .nargs = 2,
264           .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
265         { .name = "pipe", .ret_type = 1, .nargs = 1,
266           .args = { { PipeFds | OUT, 0 } } },
267         { .name = "pipe2", .ret_type = 1, .nargs = 2,
268           .args = { { Ptr, 0 }, { Pipe2, 1 } } },
269         { .name = "poll", .ret_type = 1, .nargs = 3,
270           .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
271         { .name = "posix_fadvise", .ret_type = 1, .nargs = 4,
272           .args = { { Int, 0 }, { QuadHex, 1 }, { QuadHex, 2 },
273                     { Fadvice, 3 } } },
274         { .name = "posix_openpt", .ret_type = 1, .nargs = 1,
275           .args = { { Open, 0 } } },
276         { .name = "procctl", .ret_type = 1, .nargs = 4,
277           .args = { { Idtype, 0 }, { Quad, 1 }, { Procctl, 2 }, { Ptr, 3 } } },
278         { .name = "read", .ret_type = 1, .nargs = 3,
279           .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 } } },
280         { .name = "readlink", .ret_type = 1, .nargs = 3,
281           .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Sizet, 2 } } },
282         { .name = "readlinkat", .ret_type = 1, .nargs = 4,
283           .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
284                     { Sizet, 3 } } },
285         { .name = "recvfrom", .ret_type = 1, .nargs = 6,
286           .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
287                     { Msgflags, 3 }, { Sockaddr | OUT, 4 },
288                     { Ptr | OUT, 5 } } },
289         { .name = "recvmsg", .ret_type = 1, .nargs = 3,
290           .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
291         { .name = "rename", .ret_type = 1, .nargs = 2,
292           .args = { { Name, 0 }, { Name, 1 } } },
293         { .name = "renameat", .ret_type = 1, .nargs = 4,
294           .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
295         { .name = "rfork", .ret_type = 1, .nargs = 1,
296           .args = { { Rforkflags, 0 } } },
297         { .name = "rmdir", .ret_type = 1, .nargs = 1,
298           .args = { { Name, 0 } } },
299         { .name = "sctp_generic_recvmsg", .ret_type = 1, .nargs = 7,
300           .args = { { Int, 0 }, { Ptr | IN, 1 }, { Int, 2 },
301                     { Sockaddr | OUT, 3 }, { Ptr | OUT, 4 }, { Ptr | OUT, 5 },
302                     { Ptr | OUT, 6 } } },
303         { .name = "sctp_generic_sendmsg", .ret_type = 1, .nargs = 7,
304           .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
305                     { Sockaddr | IN, 3 }, { Socklent, 4 }, { Ptr | IN, 5 },
306                     { Msgflags, 6 } } },
307         { .name = "select", .ret_type = 1, .nargs = 5,
308           .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
309                     { Timeval, 4 } } },
310         { .name = "sendmsg", .ret_type = 1, .nargs = 3,
311           .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
312         { .name = "sendto", .ret_type = 1, .nargs = 6,
313           .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
314                     { Msgflags, 3 }, { Sockaddr | IN, 4 },
315                     { Socklent | IN, 5 } } },
316         { .name = "setitimer", .ret_type = 1, .nargs = 3,
317           .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
318         { .name = "setrlimit", .ret_type = 1, .nargs = 2,
319           .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
320         { .name = "setsockopt", .ret_type = 1, .nargs = 5,
321           .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
322                     { Ptr | IN, 3 }, { Socklent, 4 } } },
323         { .name = "shutdown", .ret_type = 1, .nargs = 2,
324           .args = { { Int, 0 }, { Shutdown, 1 } } },
325         { .name = "sigaction", .ret_type = 1, .nargs = 3,
326           .args = { { Signal, 0 }, { Sigaction | IN, 1 },
327                     { Sigaction | OUT, 2 } } },
328         { .name = "sigpending", .ret_type = 1, .nargs = 1,
329           .args = { { Sigset | OUT, 0 } } },
330         { .name = "sigprocmask", .ret_type = 1, .nargs = 3,
331           .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
332         { .name = "sigqueue", .ret_type = 1, .nargs = 3,
333           .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
334         { .name = "sigreturn", .ret_type = 1, .nargs = 1,
335           .args = { { Ptr, 0 } } },
336         { .name = "sigsuspend", .ret_type = 1, .nargs = 1,
337           .args = { { Sigset | IN, 0 } } },
338         { .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
339           .args = { { Sigset | IN, 0 }, { Ptr, 1 }, { Timespec | IN, 2 } } },
340         { .name = "sigwait", .ret_type = 1, .nargs = 2,
341           .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
342         { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
343           .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
344         { .name = "socket", .ret_type = 1, .nargs = 3,
345           .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Sockprotocol, 2 } } },
346         { .name = "stat", .ret_type = 1, .nargs = 2,
347           .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
348         { .name = "statfs", .ret_type = 1, .nargs = 2,
349           .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } },
350         { .name = "symlink", .ret_type = 1, .nargs = 2,
351           .args = { { Name, 0 }, { Name, 1 } } },
352         { .name = "symlinkat", .ret_type = 1, .nargs = 3,
353           .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } },
354         { .name = "sysarch", .ret_type = 1, .nargs = 2,
355           .args = { { Sysarch, 0 }, { Ptr, 1 } } },
356         { .name = "thr_kill", .ret_type = 1, .nargs = 2,
357           .args = { { Long, 0 }, { Signal, 1 } } },
358         { .name = "thr_self", .ret_type = 1, .nargs = 1,
359           .args = { { Ptr, 0 } } },
360         { .name = "truncate", .ret_type = 1, .nargs = 2,
361           .args = { { Name | IN, 0 }, { QuadHex | IN, 1 } } },
362 #if 0
363         /* Does not exist */
364         { .name = "umount", .ret_type = 1, .nargs = 2,
365           .args = { { Name, 0 }, { Int, 2 } } },
366 #endif
367         { .name = "unlink", .ret_type = 1, .nargs = 1,
368           .args = { { Name, 0 } } },
369         { .name = "unlinkat", .ret_type = 1, .nargs = 3,
370           .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
371         { .name = "unmount", .ret_type = 1, .nargs = 2,
372           .args = { { Name, 0 }, { Int, 1 } } },
373         { .name = "utimensat", .ret_type = 1, .nargs = 4,
374           .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
375                     { Atflags, 3 } } },
376         { .name = "utimes", .ret_type = 1, .nargs = 2,
377           .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
378         { .name = "utrace", .ret_type = 1, .nargs = 1,
379           .args = { { Utrace, 0 } } },
380         { .name = "wait4", .ret_type = 1, .nargs = 4,
381           .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
382                     { Rusage | OUT, 3 } } },
383         { .name = "wait6", .ret_type = 1, .nargs = 6,
384           .args = { { Idtype, 0 }, { Quad, 1 }, { ExitStatus | OUT, 2 },
385                     { Waitoptions, 3 }, { Rusage | OUT, 4 }, { Ptr, 5 } } },
386         { .name = "write", .ret_type = 1, .nargs = 3,
387           .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 } } },
388
389         /* Linux ABI */
390         { .name = "linux_access", .ret_type = 1, .nargs = 2,
391           .args = { { Name, 0 }, { Accessmode, 1 } } },
392         { .name = "linux_execve", .ret_type = 1, .nargs = 3,
393           .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
394                     { ExecEnv | IN, 2 } } },
395         { .name = "linux_lseek", .ret_type = 2, .nargs = 3,
396           .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
397         { .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
398           .args = { { Name | IN, 0 }, { Int, 1 } } },
399         { .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
400           .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
401         { .name = "linux_newstat", .ret_type = 1, .nargs = 2,
402           .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
403         { .name = "linux_open", .ret_type = 1, .nargs = 3,
404           .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
405         { .name = "linux_readlink", .ret_type = 1, .nargs = 3,
406           .args = { { Name, 0 }, { Name | OUT, 1 }, { Sizet, 2 } } },
407         { .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
408           .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
409         { .name = "linux_stat64", .ret_type = 1, .nargs = 2,
410           .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
411
412         /* CloudABI system calls. */
413         { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
414           .args = { { CloudABIClockID, 0 } } },
415         { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
416           .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
417         { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
418           .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
419         { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
420           .args = { { Int, 0 } } },
421         { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
422           .args = { { CloudABIFileType, 0 } } },
423         { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
424           .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
425         { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
426           .args = { { Int, 0 } } },
427         { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
428           .args = { { Int, 0 } } },
429         { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
430           .args = { { Int, 0 }, { Int, 1 } } },
431         { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
432           .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
433         { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
434           .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
435         { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
436           .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
437                     { ClouduABIFDSFlags, 2 } } },
438         { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
439           .args = { { Int, 0 } } },
440         { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
441           .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
442                     { CloudABIAdvice, 3 } } },
443         { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
444           .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
445         { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
446           .args = { { Int, 0 }, { BinString | IN, 1 },
447                     { CloudABIFileType, 3 } } },
448         { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
449           .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
450                     { Int, 3 }, { BinString | IN, 4 } } },
451         { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
452           .args = { { Int, 0 }, { BinString | IN, 1 },
453                     { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
454         { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
455           .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
456                     { Int, 3 } } },
457         { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
458           .args = { { Int, 0 }, { BinString | IN, 1 },
459                     { BinString | OUT, 3 }, { Int, 4 } } },
460         { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
461           .args = { { Int, 0 }, { BinString | IN, 1 },
462                     { Int, 3 }, { BinString | IN, 4 } } },
463         { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
464           .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
465         { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
466           .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
467                     { CloudABIFSFlags, 2 } } },
468         { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
469           .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
470                     { CloudABIFileStat | OUT, 3 } } },
471         { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
472           .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
473                     { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
474         { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
475           .args = { { BinString | IN, 0 },
476                     { Int, 2 }, { BinString | IN, 3 } } },
477         { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
478           .args = { { Int, 0 }, { BinString | IN, 1 },
479                     { CloudABIULFlags, 3 } } },
480         { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
481           .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
482         { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
483           .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
484         { .name = "cloudabi_sys_mem_lock", .ret_type = 1, .nargs = 2,
485           .args = { { Ptr, 0 }, { Int, 1 } } },
486         { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
487           .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
488                     { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
489         { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
490           .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
491         { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
492           .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
493         { .name = "cloudabi_sys_mem_unlock", .ret_type = 1, .nargs = 2,
494           .args = { { Ptr, 0 }, { Int, 1 } } },
495         { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
496           .args = { { Ptr, 0 }, { Int, 1 } } },
497         { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
498           .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
499                     { IntArray, 3 }, { Int, 4 } } },
500         { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
501           .args = { { Int, 0 } } },
502         { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
503         { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
504           .args = { { CloudABISignal, 0 } } },
505         { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
506           .args = { { BinString | OUT, 0 }, { Int, 1 } } },
507         { .name = "cloudabi_sys_sock_accept", .ret_type = 1, .nargs = 2,
508           .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 } } },
509         { .name = "cloudabi_sys_sock_bind", .ret_type = 1, .nargs = 3,
510           .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
511         { .name = "cloudabi_sys_sock_connect", .ret_type = 1, .nargs = 3,
512           .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
513         { .name = "cloudabi_sys_sock_listen", .ret_type = 1, .nargs = 2,
514           .args = { { Int, 0 }, { Int, 1 } } },
515         { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
516           .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
517         { .name = "cloudabi_sys_sock_stat_get", .ret_type = 1, .nargs = 3,
518           .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 },
519                     { CloudABISSFlags, 2 } } },
520         { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
521           .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
522         { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
523
524         { .name = 0 },
525 };
526 static STAILQ_HEAD(, syscall) syscalls;
527
528 /* Xlat idea taken from strace */
529 struct xlat {
530         int val;
531         const char *str;
532 };
533
534 #define X(a)    { a, #a },
535 #define XEND    { 0, NULL }
536
537 static struct xlat kevent_filters[] = {
538         X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
539         X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
540         X(EVFILT_PROCDESC) X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER)
541         X(EVFILT_SENDFILE) XEND
542 };
543
544 static struct xlat kevent_flags[] = {
545         X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
546         X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH) X(EV_FORCEONESHOT)
547         X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
548 };
549
550 static struct xlat kevent_user_ffctrl[] = {
551         X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
552         XEND
553 };
554
555 static struct xlat kevent_rdwr_fflags[] = {
556         X(NOTE_LOWAT) X(NOTE_FILE_POLL) XEND
557 };
558
559 static struct xlat kevent_vnode_fflags[] = {
560         X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB)
561         X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND
562 };
563
564 static struct xlat kevent_proc_fflags[] = {
565         X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR)
566         X(NOTE_CHILD) XEND
567 };
568
569 static struct xlat kevent_timer_fflags[] = {
570         X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS)
571         XEND
572 };
573
574 static struct xlat poll_flags[] = {
575         X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
576         X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
577         X(POLLWRBAND) X(POLLINIGNEOF) XEND
578 };
579
580 static struct xlat sigaction_flags[] = {
581         X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
582         X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
583 };
584
585 static struct xlat pathconf_arg[] = {
586         X(_PC_LINK_MAX)  X(_PC_MAX_CANON)  X(_PC_MAX_INPUT)
587         X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF)
588         X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE)
589         X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO)
590         X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS)
591         X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE)
592         X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
593         X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
594         X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
595         X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND
596 };
597
598 static struct xlat at_flags[] = {
599         X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW)
600         X(AT_REMOVEDIR) XEND
601 };
602
603 static struct xlat sysarch_ops[] = {
604 #if defined(__i386__) || defined(__amd64__)
605         X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM)
606         X(I386_VM86) X(I386_GET_FSBASE) X(I386_SET_FSBASE) X(I386_GET_GSBASE)
607         X(I386_SET_GSBASE) X(I386_GET_XFPUSTATE) X(AMD64_GET_FSBASE)
608         X(AMD64_SET_FSBASE) X(AMD64_GET_GSBASE) X(AMD64_SET_GSBASE)
609         X(AMD64_GET_XFPUSTATE)
610 #endif
611         XEND
612 };
613
614 static struct xlat linux_socketcall_ops[] = {
615         X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
616         X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
617         X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
618         X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
619         X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
620         XEND
621 };
622
623 #undef X
624 #define X(a)    { CLOUDABI_##a, #a },
625
626 static struct xlat cloudabi_advice[] = {
627         X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
628         X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
629         XEND
630 };
631
632 static struct xlat cloudabi_clockid[] = {
633         X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
634         X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
635         XEND
636 };
637
638 static struct xlat cloudabi_errno[] = {
639         X(E2BIG) X(EACCES) X(EADDRINUSE) X(EADDRNOTAVAIL)
640         X(EAFNOSUPPORT) X(EAGAIN) X(EALREADY) X(EBADF) X(EBADMSG)
641         X(EBUSY) X(ECANCELED) X(ECHILD) X(ECONNABORTED) X(ECONNREFUSED)
642         X(ECONNRESET) X(EDEADLK) X(EDESTADDRREQ) X(EDOM) X(EDQUOT)
643         X(EEXIST) X(EFAULT) X(EFBIG) X(EHOSTUNREACH) X(EIDRM) X(EILSEQ)
644         X(EINPROGRESS) X(EINTR) X(EINVAL) X(EIO) X(EISCONN) X(EISDIR)
645         X(ELOOP) X(EMFILE) X(EMLINK) X(EMSGSIZE) X(EMULTIHOP)
646         X(ENAMETOOLONG) X(ENETDOWN) X(ENETRESET) X(ENETUNREACH)
647         X(ENFILE) X(ENOBUFS) X(ENODEV) X(ENOENT) X(ENOEXEC) X(ENOLCK)
648         X(ENOLINK) X(ENOMEM) X(ENOMSG) X(ENOPROTOOPT) X(ENOSPC)
649         X(ENOSYS) X(ENOTCONN) X(ENOTDIR) X(ENOTEMPTY) X(ENOTRECOVERABLE)
650         X(ENOTSOCK) X(ENOTSUP) X(ENOTTY) X(ENXIO) X(EOVERFLOW)
651         X(EOWNERDEAD) X(EPERM) X(EPIPE) X(EPROTO) X(EPROTONOSUPPORT)
652         X(EPROTOTYPE) X(ERANGE) X(EROFS) X(ESPIPE) X(ESRCH) X(ESTALE)
653         X(ETIMEDOUT) X(ETXTBSY) X(EXDEV) X(ENOTCAPABLE)
654         XEND
655 };
656
657 static struct xlat cloudabi_fdflags[] = {
658         X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
659         X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
660         XEND
661 };
662
663 static struct xlat cloudabi_fdsflags[] = {
664         X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
665         XEND
666 };
667
668 static struct xlat cloudabi_filetype[] = {
669         X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
670         X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
671         X(FILETYPE_FIFO) X(FILETYPE_POLL) X(FILETYPE_PROCESS)
672         X(FILETYPE_REGULAR_FILE) X(FILETYPE_SHARED_MEMORY)
673         X(FILETYPE_SOCKET_DGRAM) X(FILETYPE_SOCKET_SEQPACKET)
674         X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK)
675         XEND
676 };
677
678 static struct xlat cloudabi_fsflags[] = {
679         X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
680         X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
681         XEND
682 };
683
684 static struct xlat cloudabi_mflags[] = {
685         X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
686         XEND
687 };
688
689 static struct xlat cloudabi_mprot[] = {
690         X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
691         XEND
692 };
693
694 static struct xlat cloudabi_msflags[] = {
695         X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
696         XEND
697 };
698
699 static struct xlat cloudabi_oflags[] = {
700         X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
701         XEND
702 };
703
704 static struct xlat cloudabi_sa_family[] = {
705         X(AF_UNSPEC) X(AF_INET) X(AF_INET6) X(AF_UNIX)
706         XEND
707 };
708
709 static struct xlat cloudabi_sdflags[] = {
710         X(SHUT_RD) X(SHUT_WR)
711         XEND
712 };
713
714 static struct xlat cloudabi_signal[] = {
715         X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
716         X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
717         X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
718         X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
719         X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
720         XEND
721 };
722
723 static struct xlat cloudabi_ssflags[] = {
724         X(SOCKSTAT_CLEAR_ERROR)
725         XEND
726 };
727
728 static struct xlat cloudabi_ssstate[] = {
729         X(SOCKSTATE_ACCEPTCONN)
730         XEND
731 };
732
733 static struct xlat cloudabi_ulflags[] = {
734         X(UNLINK_REMOVEDIR)
735         XEND
736 };
737
738 static struct xlat cloudabi_whence[] = {
739         X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
740         XEND
741 };
742
743 #undef X
744 #undef XEND
745
746 /*
747  * Searches an xlat array for a value, and returns it if found.  Otherwise
748  * return a string representation.
749  */
750 static const char *
751 lookup(struct xlat *xlat, int val, int base)
752 {
753         static char tmp[16];
754
755         for (; xlat->str != NULL; xlat++)
756                 if (xlat->val == val)
757                         return (xlat->str);
758         switch (base) {
759                 case 8:
760                         sprintf(tmp, "0%o", val);
761                         break;
762                 case 16:
763                         sprintf(tmp, "0x%x", val);
764                         break;
765                 case 10:
766                         sprintf(tmp, "%u", val);
767                         break;
768                 default:
769                         errx(1,"Unknown lookup base");
770                         break;
771         }
772         return (tmp);
773 }
774
775 static const char *
776 xlookup(struct xlat *xlat, int val)
777 {
778
779         return (lookup(xlat, val, 16));
780 }
781
782 /*
783  * Searches an xlat array containing bitfield values.  Remaining bits
784  * set after removing the known ones are printed at the end:
785  * IN|0x400.
786  */
787 static char *
788 xlookup_bits(struct xlat *xlat, int val)
789 {
790         int len, rem;
791         static char str[512];
792
793         len = 0;
794         rem = val;
795         for (; xlat->str != NULL; xlat++) {
796                 if ((xlat->val & rem) == xlat->val) {
797                         /*
798                          * Don't print the "all-bits-zero" string unless all
799                          * bits are really zero.
800                          */
801                         if (xlat->val == 0 && val != 0)
802                                 continue;
803                         len += sprintf(str + len, "%s|", xlat->str);
804                         rem &= ~(xlat->val);
805                 }
806         }
807
808         /*
809          * If we have leftover bits or didn't match anything, print
810          * the remainder.
811          */
812         if (rem || len == 0)
813                 len += sprintf(str + len, "0x%x", rem);
814         if (len && str[len - 1] == '|')
815                 len--;
816         str[len] = 0;
817         return (str);
818 }
819
820 static void
821 print_integer_arg(const char *(*decoder)(int), FILE *fp, int value)
822 {
823         const char *str;
824
825         str = decoder(value);
826         if (str != NULL)
827                 fputs(str, fp);
828         else
829                 fprintf(fp, "%d", value);
830 }
831
832 static void
833 print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value)
834 {
835         int rem;
836
837         if (!decoder(fp, value, &rem))
838                 fprintf(fp, "0x%x", rem);
839         else if (rem != 0)
840                 fprintf(fp, "|0x%x", rem);
841 }
842
843 static void
844 print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), FILE *fp,
845     uint32_t value)
846 {
847         uint32_t 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 #ifndef __LP64__
856 /*
857  * Add argument padding to subsequent system calls afater a Quad
858  * syscall arguments as needed.  This used to be done by hand in the
859  * decoded_syscalls table which was ugly and error prone.  It is
860  * simpler to do the fixup of offsets at initalization time than when
861  * decoding arguments.
862  */
863 static void
864 quad_fixup(struct syscall *sc)
865 {
866         int offset, prev;
867         u_int i;
868
869         offset = 0;
870         prev = -1;
871         for (i = 0; i < sc->nargs; i++) {
872                 /* This arg type is a dummy that doesn't use offset. */
873                 if ((sc->args[i].type & ARG_MASK) == PipeFds)
874                         continue;
875
876                 assert(prev < sc->args[i].offset);
877                 prev = sc->args[i].offset;
878                 sc->args[i].offset += offset;
879                 switch (sc->args[i].type & ARG_MASK) {
880                 case Quad:
881                 case QuadHex:
882 #ifdef __powerpc__
883                         /*
884                          * 64-bit arguments on 32-bit powerpc must be
885                          * 64-bit aligned.  If the current offset is
886                          * not aligned, the calling convention inserts
887                          * a 32-bit pad argument that should be skipped.
888                          */
889                         if (sc->args[i].offset % 2 == 1) {
890                                 sc->args[i].offset++;
891                                 offset++;
892                         }
893 #endif
894                         offset++;
895                 default:
896                         break;
897                 }
898         }
899 }
900 #endif
901
902 void
903 init_syscalls(void)
904 {
905         struct syscall *sc;
906
907         STAILQ_INIT(&syscalls);
908         for (sc = decoded_syscalls; sc->name != NULL; sc++) {
909 #ifndef __LP64__
910                 quad_fixup(sc);
911 #endif
912                 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
913         }
914 }
915
916 static struct syscall *
917 find_syscall(struct procabi *abi, u_int number)
918 {
919         struct extra_syscall *es;
920
921         if (number < nitems(abi->syscalls))
922                 return (abi->syscalls[number]);
923         STAILQ_FOREACH(es, &abi->extra_syscalls, entries) {
924                 if (es->number == number)
925                         return (es->sc);
926         }
927         return (NULL);
928 }
929
930 static void
931 add_syscall(struct procabi *abi, u_int number, struct syscall *sc)
932 {
933         struct extra_syscall *es;
934
935         if (number < nitems(abi->syscalls)) {
936                 assert(abi->syscalls[number] == NULL);
937                 abi->syscalls[number] = sc;
938         } else {
939                 es = malloc(sizeof(*es));
940                 es->sc = sc;
941                 es->number = number;
942                 STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries);
943         }
944 }
945
946 /*
947  * If/when the list gets big, it might be desirable to do it
948  * as a hash table or binary search.
949  */
950 struct syscall *
951 get_syscall(struct threadinfo *t, u_int number, u_int nargs)
952 {
953         struct syscall *sc;
954         const char *name;
955         char *new_name;
956         u_int i;
957
958         sc = find_syscall(t->proc->abi, number);
959         if (sc != NULL)
960                 return (sc);
961
962         name = sysdecode_syscallname(t->proc->abi->abi, number);
963         if (name == NULL) {
964                 asprintf(&new_name, "#%d", number);
965                 name = new_name;
966         } else
967                 new_name = NULL;
968         STAILQ_FOREACH(sc, &syscalls, entries) {
969                 if (strcmp(name, sc->name) == 0) {
970                         add_syscall(t->proc->abi, number, sc);
971                         free(new_name);
972                         return (sc);
973                 }
974         }
975
976         /* It is unknown.  Add it into the list. */
977 #if DEBUG
978         fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
979             nargs);
980 #endif
981
982         sc = calloc(1, sizeof(struct syscall));
983         sc->name = name;
984         if (new_name != NULL)
985                 sc->unknown = true;
986         sc->ret_type = 1;
987         sc->nargs = nargs;
988         for (i = 0; i < nargs; i++) {
989                 sc->args[i].offset = i;
990                 /* Treat all unknown arguments as LongHex. */
991                 sc->args[i].type = LongHex;
992         }
993         STAILQ_INSERT_HEAD(&syscalls, sc, entries);
994         add_syscall(t->proc->abi, number, sc);
995
996         return (sc);
997 }
998
999 /*
1000  * Copy a fixed amount of bytes from the process.
1001  */
1002 static int
1003 get_struct(pid_t pid, void *offset, void *buf, int len)
1004 {
1005         struct ptrace_io_desc iorequest;
1006
1007         iorequest.piod_op = PIOD_READ_D;
1008         iorequest.piod_offs = offset;
1009         iorequest.piod_addr = buf;
1010         iorequest.piod_len = len;
1011         if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
1012                 return (-1);
1013         return (0);
1014 }
1015
1016 #define MAXSIZE         4096
1017
1018 /*
1019  * Copy a string from the process.  Note that it is
1020  * expected to be a C string, but if max is set, it will
1021  * only get that much.
1022  */
1023 static char *
1024 get_string(pid_t pid, void *addr, int max)
1025 {
1026         struct ptrace_io_desc iorequest;
1027         char *buf, *nbuf;
1028         size_t offset, size, totalsize;
1029
1030         offset = 0;
1031         if (max)
1032                 size = max + 1;
1033         else {
1034                 /* Read up to the end of the current page. */
1035                 size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE);
1036                 if (size > MAXSIZE)
1037                         size = MAXSIZE;
1038         }
1039         totalsize = size;
1040         buf = malloc(totalsize);
1041         if (buf == NULL)
1042                 return (NULL);
1043         for (;;) {
1044                 iorequest.piod_op = PIOD_READ_D;
1045                 iorequest.piod_offs = (char *)addr + offset;
1046                 iorequest.piod_addr = buf + offset;
1047                 iorequest.piod_len = size;
1048                 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
1049                         free(buf);
1050                         return (NULL);
1051                 }
1052                 if (memchr(buf + offset, '\0', size) != NULL)
1053                         return (buf);
1054                 offset += size;
1055                 if (totalsize < MAXSIZE && max == 0) {
1056                         size = MAXSIZE - totalsize;
1057                         if (size > PAGE_SIZE)
1058                                 size = PAGE_SIZE;
1059                         nbuf = realloc(buf, totalsize + size);
1060                         if (nbuf == NULL) {
1061                                 buf[totalsize - 1] = '\0';
1062                                 return (buf);
1063                         }
1064                         buf = nbuf;
1065                         totalsize += size;
1066                 } else {
1067                         buf[totalsize - 1] = '\0';
1068                         return (buf);
1069                 }
1070         }
1071 }
1072
1073 static const char *
1074 strsig2(int sig)
1075 {
1076         static char tmp[32];
1077         const char *signame;
1078
1079         signame = sysdecode_signal(sig);
1080         if (signame == NULL) {
1081                 snprintf(tmp, sizeof(tmp), "%d", sig);
1082                 signame = tmp;
1083         }
1084         return (signame);
1085 }
1086
1087 static void
1088 print_kevent(FILE *fp, struct kevent *ke, int input)
1089 {
1090
1091         switch (ke->filter) {
1092         case EVFILT_READ:
1093         case EVFILT_WRITE:
1094         case EVFILT_VNODE:
1095         case EVFILT_PROC:
1096         case EVFILT_TIMER:
1097         case EVFILT_PROCDESC:
1098                 fprintf(fp, "%ju", (uintmax_t)ke->ident);
1099                 break;
1100         case EVFILT_SIGNAL:
1101                 fputs(strsig2(ke->ident), fp);
1102                 break;
1103         default:
1104                 fprintf(fp, "%p", (void *)ke->ident);
1105         }
1106         fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter),
1107             xlookup_bits(kevent_flags, ke->flags));
1108         switch (ke->filter) {
1109         case EVFILT_READ:
1110         case EVFILT_WRITE:
1111                 fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp);
1112                 break;
1113         case EVFILT_VNODE:
1114                 fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp);
1115                 break;
1116         case EVFILT_PROC:
1117         case EVFILT_PROCDESC:
1118                 fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp);
1119                 break;
1120         case EVFILT_TIMER:
1121                 fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp);
1122                 break;
1123         case EVFILT_USER: {
1124                 int ctrl, data;
1125
1126                 ctrl = ke->fflags & NOTE_FFCTRLMASK;
1127                 data = ke->fflags & NOTE_FFLAGSMASK;
1128                 if (input) {
1129                         fputs(xlookup(kevent_user_ffctrl, ctrl), fp);
1130                         if (ke->fflags & NOTE_TRIGGER)
1131                                 fputs("|NOTE_TRIGGER", fp);
1132                         if (data != 0)
1133                                 fprintf(fp, "|%#x", data);
1134                 } else {
1135                         fprintf(fp, "%#x", data);
1136                 }
1137                 break;
1138         }
1139         default:
1140                 fprintf(fp, "%#x", ke->fflags);
1141         }
1142         fprintf(fp, ",%p,%p", (void *)ke->data, (void *)ke->udata);
1143 }
1144
1145 static void
1146 print_utrace(FILE *fp, void *utrace_addr, size_t len)
1147 {
1148         unsigned char *utrace_buffer;
1149
1150         fprintf(fp, "{ ");
1151         if (sysdecode_utrace(fp, utrace_addr, len)) {
1152                 fprintf(fp, " }");
1153                 return;
1154         }
1155
1156         utrace_buffer = utrace_addr;
1157         fprintf(fp, "%zu:", len);
1158         while (len--)
1159                 fprintf(fp, " %02x", *utrace_buffer++);
1160         fprintf(fp, " }");
1161 }
1162
1163 /*
1164  * Converts a syscall argument into a string.  Said string is
1165  * allocated via malloc(), so needs to be free()'d.  sc is
1166  * a pointer to the syscall description (see above); args is
1167  * an array of all of the system call arguments.
1168  */
1169 char *
1170 print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
1171     struct trussinfo *trussinfo)
1172 {
1173         FILE *fp;
1174         char *tmp;
1175         size_t tmplen;
1176         pid_t pid;
1177
1178         fp = open_memstream(&tmp, &tmplen);
1179         pid = trussinfo->curthread->proc->pid;
1180         switch (sc->type & ARG_MASK) {
1181         case Hex:
1182                 fprintf(fp, "0x%x", (int)args[sc->offset]);
1183                 break;
1184         case Octal:
1185                 fprintf(fp, "0%o", (int)args[sc->offset]);
1186                 break;
1187         case Int:
1188                 fprintf(fp, "%d", (int)args[sc->offset]);
1189                 break;
1190         case UInt:
1191                 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1192                 break;
1193         case LongHex:
1194                 fprintf(fp, "0x%lx", args[sc->offset]);
1195                 break;
1196         case Long:
1197                 fprintf(fp, "%ld", args[sc->offset]);
1198                 break;
1199         case Sizet:
1200                 fprintf(fp, "%zu", (size_t)args[sc->offset]);
1201                 break;
1202         case Name: {
1203                 /* NULL-terminated string. */
1204                 char *tmp2;
1205
1206                 tmp2 = get_string(pid, (void*)args[sc->offset], 0);
1207                 fprintf(fp, "\"%s\"", tmp2);
1208                 free(tmp2);
1209                 break;
1210         }
1211         case BinString: {
1212                 /*
1213                  * Binary block of data that might have printable characters.
1214                  * XXX If type|OUT, assume that the length is the syscall's
1215                  * return value.  Otherwise, assume that the length of the block
1216                  * is in the next syscall argument.
1217                  */
1218                 int max_string = trussinfo->strsize;
1219                 char tmp2[max_string + 1], *tmp3;
1220                 int len;
1221                 int truncated = 0;
1222
1223                 if (sc->type & OUT)
1224                         len = retval[0];
1225                 else
1226                         len = args[sc->offset + 1];
1227
1228                 /*
1229                  * Don't print more than max_string characters, to avoid word
1230                  * wrap.  If we have to truncate put some ... after the string.
1231                  */
1232                 if (len > max_string) {
1233                         len = max_string;
1234                         truncated = 1;
1235                 }
1236                 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
1237                     != -1) {
1238                         tmp3 = malloc(len * 4 + 1);
1239                         while (len) {
1240                                 if (strvisx(tmp3, tmp2, len,
1241                                     VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1242                                         break;
1243                                 len--;
1244                                 truncated = 1;
1245                         }
1246                         fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1247                             "..." : "");
1248                         free(tmp3);
1249                 } else {
1250                         fprintf(fp, "0x%lx", args[sc->offset]);
1251                 }
1252                 break;
1253         }
1254         case ExecArgs:
1255         case ExecEnv:
1256         case StringArray: {
1257                 uintptr_t addr;
1258                 union {
1259                         char *strarray[0];
1260                         char buf[PAGE_SIZE];
1261                 } u;
1262                 char *string;
1263                 size_t len;
1264                 u_int first, i;
1265
1266                 /*
1267                  * Only parse argv[] and environment arrays from exec calls
1268                  * if requested.
1269                  */
1270                 if (((sc->type & ARG_MASK) == ExecArgs &&
1271                     (trussinfo->flags & EXECVEARGS) == 0) ||
1272                     ((sc->type & ARG_MASK) == ExecEnv &&
1273                     (trussinfo->flags & EXECVEENVS) == 0)) {
1274                         fprintf(fp, "0x%lx", args[sc->offset]);
1275                         break;
1276                 }
1277
1278                 /*
1279                  * Read a page of pointers at a time.  Punt if the top-level
1280                  * pointer is not aligned.  Note that the first read is of
1281                  * a partial page.
1282                  */
1283                 addr = args[sc->offset];
1284                 if (addr % sizeof(char *) != 0) {
1285                         fprintf(fp, "0x%lx", args[sc->offset]);
1286                         break;
1287                 }
1288
1289                 len = PAGE_SIZE - (addr & PAGE_MASK);
1290                 if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
1291                         fprintf(fp, "0x%lx", args[sc->offset]);
1292                         break;
1293                 }
1294
1295                 fputc('[', fp);
1296                 first = 1;
1297                 i = 0;
1298                 while (u.strarray[i] != NULL) {
1299                         string = get_string(pid, u.strarray[i], 0);
1300                         fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1301                         free(string);
1302                         first = 0;
1303
1304                         i++;
1305                         if (i == len / sizeof(char *)) {
1306                                 addr += len;
1307                                 len = PAGE_SIZE;
1308                                 if (get_struct(pid, (void *)addr, u.buf, len) ==
1309                                     -1) {
1310                                         fprintf(fp, ", <inval>");
1311                                         break;
1312                                 }
1313                                 i = 0;
1314                         }
1315                 }
1316                 fputs(" ]", fp);
1317                 break;
1318         }
1319 #ifdef __LP64__
1320         case Quad:
1321                 fprintf(fp, "%ld", args[sc->offset]);
1322                 break;
1323         case QuadHex:
1324                 fprintf(fp, "0x%lx", args[sc->offset]);
1325                 break;
1326 #else
1327         case Quad:
1328         case QuadHex: {
1329                 unsigned long long ll;
1330
1331 #if _BYTE_ORDER == _LITTLE_ENDIAN
1332                 ll = (unsigned long long)args[sc->offset + 1] << 32 |
1333                     args[sc->offset];
1334 #else
1335                 ll = (unsigned long long)args[sc->offset] << 32 |
1336                     args[sc->offset + 1];
1337 #endif
1338                 if ((sc->type & ARG_MASK) == Quad)
1339                         fprintf(fp, "%lld", ll);
1340                 else
1341                         fprintf(fp, "0x%llx", ll);
1342                 break;
1343         }
1344 #endif
1345         case Ptr:
1346                 fprintf(fp, "0x%lx", args[sc->offset]);
1347                 break;
1348         case Readlinkres: {
1349                 char *tmp2;
1350
1351                 if (retval[0] == -1)
1352                         break;
1353                 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
1354                 fprintf(fp, "\"%s\"", tmp2);
1355                 free(tmp2);
1356                 break;
1357         }
1358         case Ioctl: {
1359                 const char *temp;
1360                 unsigned long cmd;
1361
1362                 cmd = args[sc->offset];
1363                 temp = sysdecode_ioctlname(cmd);
1364                 if (temp)
1365                         fputs(temp, fp);
1366                 else {
1367                         fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1368                             cmd, cmd & IOC_OUT ? "R" : "",
1369                             cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1370                             isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1371                             cmd & 0xFF, IOCPARM_LEN(cmd));
1372                 }
1373                 break;
1374         }
1375         case Timespec: {
1376                 struct timespec ts;
1377
1378                 if (get_struct(pid, (void *)args[sc->offset], &ts,
1379                     sizeof(ts)) != -1)
1380                         fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1381                             ts.tv_nsec);
1382                 else
1383                         fprintf(fp, "0x%lx", args[sc->offset]);
1384                 break;
1385         }
1386         case Timespec2: {
1387                 struct timespec ts[2];
1388                 const char *sep;
1389                 unsigned int i;
1390
1391                 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
1392                     != -1) {
1393                         fputs("{ ", fp);
1394                         sep = "";
1395                         for (i = 0; i < nitems(ts); i++) {
1396                                 fputs(sep, fp);
1397                                 sep = ", ";
1398                                 switch (ts[i].tv_nsec) {
1399                                 case UTIME_NOW:
1400                                         fprintf(fp, "UTIME_NOW");
1401                                         break;
1402                                 case UTIME_OMIT:
1403                                         fprintf(fp, "UTIME_OMIT");
1404                                         break;
1405                                 default:
1406                                         fprintf(fp, "%jd.%09ld",
1407                                             (intmax_t)ts[i].tv_sec,
1408                                             ts[i].tv_nsec);
1409                                         break;
1410                                 }
1411                         }
1412                         fputs(" }", fp);
1413                 } else
1414                         fprintf(fp, "0x%lx", args[sc->offset]);
1415                 break;
1416         }
1417         case Timeval: {
1418                 struct timeval tv;
1419
1420                 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1421                     != -1)
1422                         fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1423                             tv.tv_usec);
1424                 else
1425                         fprintf(fp, "0x%lx", args[sc->offset]);
1426                 break;
1427         }
1428         case Timeval2: {
1429                 struct timeval tv[2];
1430
1431                 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1432                     != -1)
1433                         fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1434                             (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1435                             (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1436                 else
1437                         fprintf(fp, "0x%lx", args[sc->offset]);
1438                 break;
1439         }
1440         case Itimerval: {
1441                 struct itimerval itv;
1442
1443                 if (get_struct(pid, (void *)args[sc->offset], &itv,
1444                     sizeof(itv)) != -1)
1445                         fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1446                             (intmax_t)itv.it_interval.tv_sec,
1447                             itv.it_interval.tv_usec,
1448                             (intmax_t)itv.it_value.tv_sec,
1449                             itv.it_value.tv_usec);
1450                 else
1451                         fprintf(fp, "0x%lx", args[sc->offset]);
1452                 break;
1453         }
1454         case LinuxSockArgs:
1455         {
1456                 struct linux_socketcall_args largs;
1457
1458                 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
1459                     sizeof(largs)) != -1)
1460                         fprintf(fp, "{ %s, 0x%lx }",
1461                             lookup(linux_socketcall_ops, largs.what, 10),
1462                             (long unsigned int)largs.args);
1463                 else
1464                         fprintf(fp, "0x%lx", args[sc->offset]);
1465                 break;
1466         }
1467         case Pollfd: {
1468                 /*
1469                  * XXX: A Pollfd argument expects the /next/ syscall argument
1470                  * to be the number of fds in the array. This matches the poll
1471                  * syscall.
1472                  */
1473                 struct pollfd *pfd;
1474                 int numfds = args[sc->offset + 1];
1475                 size_t bytes = sizeof(struct pollfd) * numfds;
1476                 int i;
1477
1478                 if ((pfd = malloc(bytes)) == NULL)
1479                         err(1, "Cannot malloc %zu bytes for pollfd array",
1480                             bytes);
1481                 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
1482                     != -1) {
1483                         fputs("{", fp);
1484                         for (i = 0; i < numfds; i++) {
1485                                 fprintf(fp, " %d/%s", pfd[i].fd,
1486                                     xlookup_bits(poll_flags, pfd[i].events));
1487                         }
1488                         fputs(" }", fp);
1489                 } else {
1490                         fprintf(fp, "0x%lx", args[sc->offset]);
1491                 }
1492                 free(pfd);
1493                 break;
1494         }
1495         case Fd_set: {
1496                 /*
1497                  * XXX: A Fd_set argument expects the /first/ syscall argument
1498                  * to be the number of fds in the array.  This matches the
1499                  * select syscall.
1500                  */
1501                 fd_set *fds;
1502                 int numfds = args[0];
1503                 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1504                 int i;
1505
1506                 if ((fds = malloc(bytes)) == NULL)
1507                         err(1, "Cannot malloc %zu bytes for fd_set array",
1508                             bytes);
1509                 if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
1510                     != -1) {
1511                         fputs("{", fp);
1512                         for (i = 0; i < numfds; i++) {
1513                                 if (FD_ISSET(i, fds))
1514                                         fprintf(fp, " %d", i);
1515                         }
1516                         fputs(" }", fp);
1517                 } else
1518                         fprintf(fp, "0x%lx", args[sc->offset]);
1519                 free(fds);
1520                 break;
1521         }
1522         case Signal:
1523                 fputs(strsig2(args[sc->offset]), fp);
1524                 break;
1525         case Sigset: {
1526                 long sig;
1527                 sigset_t ss;
1528                 int i, first;
1529
1530                 sig = args[sc->offset];
1531                 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
1532                     sizeof(ss)) == -1) {
1533                         fprintf(fp, "0x%lx", args[sc->offset]);
1534                         break;
1535                 }
1536                 fputs("{ ", fp);
1537                 first = 1;
1538                 for (i = 1; i < sys_nsig; i++) {
1539                         if (sigismember(&ss, i)) {
1540                                 fprintf(fp, "%s%s", !first ? "|" : "",
1541                                     strsig2(i));
1542                                 first = 0;
1543                         }
1544                 }
1545                 if (!first)
1546                         fputc(' ', fp);
1547                 fputc('}', fp);
1548                 break;
1549         }
1550         case Sigprocmask:
1551                 print_integer_arg(sysdecode_sigprocmask_how, fp,
1552                     args[sc->offset]);
1553                 break;
1554         case Fcntlflag:
1555                 /* XXX: Output depends on the value of the previous argument. */
1556                 if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
1557                         sysdecode_fcntl_arg(fp, args[sc->offset - 1],
1558                             args[sc->offset], 16);
1559                 break;
1560         case Open:
1561                 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
1562                 break;
1563         case Fcntl:
1564                 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
1565                 break;
1566         case Mprot:
1567                 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
1568                 break;
1569         case Mmapflags:
1570                 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
1571                 break;
1572         case Whence:
1573                 print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
1574                 break;
1575         case Sockdomain:
1576                 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
1577                 break;
1578         case Socktype:
1579                 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
1580                 break;
1581         case Shutdown:
1582                 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
1583                 break;
1584         case Resource:
1585                 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
1586                 break;
1587         case Pathconf:
1588                 fputs(xlookup(pathconf_arg, args[sc->offset]), fp);
1589                 break;
1590         case Rforkflags:
1591                 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
1592                 break;
1593         case Sockaddr: {
1594                 char addr[64];
1595                 struct sockaddr_in *lsin;
1596                 struct sockaddr_in6 *lsin6;
1597                 struct sockaddr_un *sun;
1598                 struct sockaddr *sa;
1599                 socklen_t len;
1600                 u_char *q;
1601
1602                 if (args[sc->offset] == 0) {
1603                         fputs("NULL", fp);
1604                         break;
1605                 }
1606
1607                 /*
1608                  * Extract the address length from the next argument.  If
1609                  * this is an output sockaddr (OUT is set), then the
1610                  * next argument is a pointer to a socklen_t.  Otherwise
1611                  * the next argument contains a socklen_t by value.
1612                  */
1613                 if (sc->type & OUT) {
1614                         if (get_struct(pid, (void *)args[sc->offset + 1],
1615                             &len, sizeof(len)) == -1) {
1616                                 fprintf(fp, "0x%lx", args[sc->offset]);
1617                                 break;
1618                         }
1619                 } else
1620                         len = args[sc->offset + 1];
1621
1622                 /* If the length is too small, just bail. */
1623                 if (len < sizeof(*sa)) {
1624                         fprintf(fp, "0x%lx", args[sc->offset]);
1625                         break;
1626                 }
1627
1628                 sa = calloc(1, len);
1629                 if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) {
1630                         free(sa);
1631                         fprintf(fp, "0x%lx", args[sc->offset]);
1632                         break;
1633                 }
1634
1635                 switch (sa->sa_family) {
1636                 case AF_INET:
1637                         if (len < sizeof(*lsin))
1638                                 goto sockaddr_short;
1639                         lsin = (struct sockaddr_in *)(void *)sa;
1640                         inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1641                         fprintf(fp, "{ AF_INET %s:%d }", addr,
1642                             htons(lsin->sin_port));
1643                         break;
1644                 case AF_INET6:
1645                         if (len < sizeof(*lsin6))
1646                                 goto sockaddr_short;
1647                         lsin6 = (struct sockaddr_in6 *)(void *)sa;
1648                         inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1649                             sizeof(addr));
1650                         fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1651                             htons(lsin6->sin6_port));
1652                         break;
1653                 case AF_UNIX:
1654                         sun = (struct sockaddr_un *)sa;
1655                         fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1656                             (int)(len - offsetof(struct sockaddr_un, sun_path)),
1657                             sun->sun_path);
1658                         break;
1659                 default:
1660                 sockaddr_short:
1661                         fprintf(fp,
1662                             "{ sa_len = %d, sa_family = %d, sa_data = {",
1663                             (int)sa->sa_len, (int)sa->sa_family);
1664                         for (q = (u_char *)sa->sa_data;
1665                              q < (u_char *)sa + len; q++)
1666                                 fprintf(fp, "%s 0x%02x",
1667                                     q == (u_char *)sa->sa_data ? "" : ",",
1668                                     *q);
1669                         fputs(" } }", fp);
1670                 }
1671                 free(sa);
1672                 break;
1673         }
1674         case Sigaction: {
1675                 struct sigaction sa;
1676
1677                 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
1678                     != -1) {
1679                         fputs("{ ", fp);
1680                         if (sa.sa_handler == SIG_DFL)
1681                                 fputs("SIG_DFL", fp);
1682                         else if (sa.sa_handler == SIG_IGN)
1683                                 fputs("SIG_IGN", fp);
1684                         else
1685                                 fprintf(fp, "%p", sa.sa_handler);
1686                         fprintf(fp, " %s ss_t }",
1687                             xlookup_bits(sigaction_flags, sa.sa_flags));
1688                 } else
1689                         fprintf(fp, "0x%lx", args[sc->offset]);
1690                 break;
1691         }
1692         case Kevent: {
1693                 /*
1694                  * XXX XXX: The size of the array is determined by either the
1695                  * next syscall argument, or by the syscall return value,
1696                  * depending on which argument number we are.  This matches the
1697                  * kevent syscall, but luckily that's the only syscall that uses
1698                  * them.
1699                  */
1700                 struct kevent *ke;
1701                 int numevents = -1;
1702                 size_t bytes;
1703                 int i;
1704
1705                 if (sc->offset == 1)
1706                         numevents = args[sc->offset+1];
1707                 else if (sc->offset == 3 && retval[0] != -1)
1708                         numevents = retval[0];
1709
1710                 if (numevents >= 0) {
1711                         bytes = sizeof(struct kevent) * numevents;
1712                         if ((ke = malloc(bytes)) == NULL)
1713                                 err(1,
1714                                     "Cannot malloc %zu bytes for kevent array",
1715                                     bytes);
1716                 } else
1717                         ke = NULL;
1718                 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
1719                     ke, bytes) != -1) {
1720                         fputc('{', fp);
1721                         for (i = 0; i < numevents; i++) {
1722                                 fputc(' ', fp);
1723                                 print_kevent(fp, &ke[i], sc->offset == 1);
1724                         }
1725                         fputs(" }", fp);
1726                 } else {
1727                         fprintf(fp, "0x%lx", args[sc->offset]);
1728                 }
1729                 free(ke);
1730                 break;
1731         }
1732         case Stat: {
1733                 struct stat st;
1734
1735                 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1736                     != -1) {
1737                         char mode[12];
1738
1739                         strmode(st.st_mode, mode);
1740                         fprintf(fp,
1741                             "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1742                             (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1743                             (long)st.st_blksize);
1744                 } else {
1745                         fprintf(fp, "0x%lx", args[sc->offset]);
1746                 }
1747                 break;
1748         }
1749         case StatFs: {
1750                 unsigned int i;
1751                 struct statfs buf;
1752
1753                 if (get_struct(pid, (void *)args[sc->offset], &buf,
1754                     sizeof(buf)) != -1) {
1755                         char fsid[17];
1756
1757                         bzero(fsid, sizeof(fsid));
1758                         if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
1759                                 for (i = 0; i < sizeof(buf.f_fsid); i++)
1760                                         snprintf(&fsid[i*2],
1761                                             sizeof(fsid) - (i*2), "%02x",
1762                                             ((u_char *)&buf.f_fsid)[i]);
1763                         }
1764                         fprintf(fp,
1765                             "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
1766                             "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
1767                             buf.f_mntfromname, fsid);
1768                 } else
1769                         fprintf(fp, "0x%lx", args[sc->offset]);
1770                 break;
1771         }
1772
1773         case Rusage: {
1774                 struct rusage ru;
1775
1776                 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
1777                     != -1) {
1778                         fprintf(fp,
1779                             "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
1780                             (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
1781                             (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
1782                             ru.ru_inblock, ru.ru_oublock);
1783                 } else
1784                         fprintf(fp, "0x%lx", args[sc->offset]);
1785                 break;
1786         }
1787         case Rlimit: {
1788                 struct rlimit rl;
1789
1790                 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
1791                     != -1) {
1792                         fprintf(fp, "{ cur=%ju,max=%ju }",
1793                             rl.rlim_cur, rl.rlim_max);
1794                 } else
1795                         fprintf(fp, "0x%lx", args[sc->offset]);
1796                 break;
1797         }
1798         case ExitStatus: {
1799                 int status;
1800
1801                 if (get_struct(pid, (void *)args[sc->offset], &status,
1802                     sizeof(status)) != -1) {
1803                         fputs("{ ", fp);
1804                         if (WIFCONTINUED(status))
1805                                 fputs("CONTINUED", fp);
1806                         else if (WIFEXITED(status))
1807                                 fprintf(fp, "EXITED,val=%d",
1808                                     WEXITSTATUS(status));
1809                         else if (WIFSIGNALED(status))
1810                                 fprintf(fp, "SIGNALED,sig=%s%s",
1811                                     strsig2(WTERMSIG(status)),
1812                                     WCOREDUMP(status) ? ",cored" : "");
1813                         else
1814                                 fprintf(fp, "STOPPED,sig=%s",
1815                                     strsig2(WTERMSIG(status)));
1816                         fputs(" }", fp);
1817                 } else
1818                         fprintf(fp, "0x%lx", args[sc->offset]);
1819                 break;
1820         }
1821         case Waitoptions:
1822                 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]);
1823                 break;
1824         case Idtype:
1825                 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]);
1826                 break;
1827         case Procctl:
1828                 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]);
1829                 break;
1830         case Umtxop:
1831                 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]);
1832                 break;
1833         case Atfd:
1834                 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]);
1835                 break;
1836         case Atflags:
1837                 fputs(xlookup_bits(at_flags, args[sc->offset]), fp);
1838                 break;
1839         case Accessmode:
1840                 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]);
1841                 break;
1842         case Sysarch:
1843                 fputs(xlookup(sysarch_ops, args[sc->offset]), fp);
1844                 break;
1845         case PipeFds:
1846                 /*
1847                  * The pipe() system call in the kernel returns its
1848                  * two file descriptors via return values.  However,
1849                  * the interface exposed by libc is that pipe()
1850                  * accepts a pointer to an array of descriptors.
1851                  * Format the output to match the libc API by printing
1852                  * the returned file descriptors as a fake argument.
1853                  *
1854                  * Overwrite the first retval to signal a successful
1855                  * return as well.
1856                  */
1857                 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
1858                 retval[0] = 0;
1859                 break;
1860         case Utrace: {
1861                 size_t len;
1862                 void *utrace_addr;
1863
1864                 len = args[sc->offset + 1];
1865                 utrace_addr = calloc(1, len);
1866                 if (get_struct(pid, (void *)args[sc->offset],
1867                     (void *)utrace_addr, len) != -1)
1868                         print_utrace(fp, utrace_addr, len);
1869                 else
1870                         fprintf(fp, "0x%lx", args[sc->offset]);
1871                 free(utrace_addr);
1872                 break;
1873         }
1874         case IntArray: {
1875                 int descriptors[16];
1876                 unsigned long i, ndescriptors;
1877                 bool truncated;
1878
1879                 ndescriptors = args[sc->offset + 1];
1880                 truncated = false;
1881                 if (ndescriptors > nitems(descriptors)) {
1882                         ndescriptors = nitems(descriptors);
1883                         truncated = true;
1884                 }
1885                 if (get_struct(pid, (void *)args[sc->offset],
1886                     descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
1887                         fprintf(fp, "{");
1888                         for (i = 0; i < ndescriptors; i++)
1889                                 fprintf(fp, i == 0 ? " %d" : ", %d",
1890                                     descriptors[i]);
1891                         fprintf(fp, truncated ? ", ... }" : " }");
1892                 } else
1893                         fprintf(fp, "0x%lx", args[sc->offset]);
1894                 break;
1895         }
1896         case Pipe2:
1897                 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]);
1898                 break;
1899         case CapFcntlRights: {
1900                 uint32_t rights;
1901
1902                 if (sc->type & OUT) {
1903                         if (get_struct(pid, (void *)args[sc->offset], &rights,
1904                             sizeof(rights)) == -1) {
1905                                 fprintf(fp, "0x%lx", args[sc->offset]);
1906                                 break;
1907                         }
1908                 } else
1909                         rights = args[sc->offset];
1910                 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights);
1911                 break;
1912         }
1913         case Fadvice:
1914                 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]);
1915                 break;
1916         case FileFlags: {
1917                 fflags_t rem;
1918
1919                 if (!sysdecode_fileflags(fp, args[sc->offset], &rem))
1920                         fprintf(fp, "0x%x", rem);
1921                 else if (rem != 0)
1922                         fprintf(fp, "|0x%x", rem);
1923                 break;
1924         }
1925         case Flockop:
1926                 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]);
1927                 break;
1928         case Getfsstatmode:
1929                 print_integer_arg(sysdecode_getfsstat_mode, fp,
1930                     args[sc->offset]);
1931                 break;
1932         case Kldsymcmd:
1933                 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]);
1934                 break;
1935         case Kldunloadflags:
1936                 print_integer_arg(sysdecode_kldunload_flags, fp,
1937                     args[sc->offset]);
1938                 break;
1939         case Madvice:
1940                 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]);
1941                 break;
1942         case Socklent:
1943                 fprintf(fp, "%u", (socklen_t)args[sc->offset]);
1944                 break;
1945         case Sockprotocol: {
1946                 const char *temp;
1947                 int domain, protocol;
1948
1949                 domain = args[sc->offset - 2];
1950                 protocol = args[sc->offset];
1951                 if (protocol == 0) {
1952                         fputs("0", fp);
1953                 } else {
1954                         temp = sysdecode_socket_protocol(domain, protocol);
1955                         if (temp) {
1956                                 fputs(temp, fp);
1957                         } else {
1958                                 fprintf(fp, "%d", protocol);
1959                         }
1960                 }
1961                 break;
1962         }
1963         case Sockoptlevel:
1964                 print_integer_arg(sysdecode_sockopt_level, fp,
1965                     args[sc->offset]);
1966                 break;
1967         case Sockoptname: {
1968                 const char *temp;
1969                 int level, name;
1970
1971                 level = args[sc->offset - 1];
1972                 name = args[sc->offset];
1973                 temp = sysdecode_sockopt_name(level, name);
1974                 if (temp) {
1975                         fputs(temp, fp);
1976                 } else {
1977                         fprintf(fp, "%d", name);
1978                 }
1979                 break;
1980         }
1981         case Msgflags:
1982                 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]);
1983                 break;
1984         case CapRights: {
1985                 cap_rights_t rights;
1986
1987                 if (get_struct(pid, (void *)args[sc->offset], &rights,
1988                     sizeof(rights)) != -1) {
1989                         fputs("{ ", fp);
1990                         sysdecode_cap_rights(fp, &rights);
1991                         fputs(" }", fp);
1992                 } else
1993                         fprintf(fp, "0x%lx", args[sc->offset]);
1994                 break;
1995         }
1996
1997         case CloudABIAdvice:
1998                 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
1999                 break;
2000         case CloudABIClockID:
2001                 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2002                 break;
2003         case ClouduABIFDSFlags:
2004                 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2005                 break;
2006         case CloudABIFDStat: {
2007                 cloudabi_fdstat_t fds;
2008                 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds))
2009                     != -1) {
2010                         fprintf(fp, "{ %s, ",
2011                             xlookup(cloudabi_filetype, fds.fs_filetype));
2012                         fprintf(fp, "%s, ... }",
2013                             xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2014                 } else
2015                         fprintf(fp, "0x%lx", args[sc->offset]);
2016                 break;
2017         }
2018         case CloudABIFileStat: {
2019                 cloudabi_filestat_t fsb;
2020                 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb))
2021                     != -1)
2022                         fprintf(fp, "{ %s, %ju }",
2023                             xlookup(cloudabi_filetype, fsb.st_filetype),
2024                             (uintmax_t)fsb.st_size);
2025                 else
2026                         fprintf(fp, "0x%lx", args[sc->offset]);
2027                 break;
2028         }
2029         case CloudABIFileType:
2030                 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2031                 break;
2032         case CloudABIFSFlags:
2033                 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2034                 break;
2035         case CloudABILookup:
2036                 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2037                         fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2038                             (int)args[sc->offset]);
2039                 else
2040                         fprintf(fp, "%d", (int)args[sc->offset]);
2041                 break;
2042         case CloudABIMFlags:
2043                 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2044                 break;
2045         case CloudABIMProt:
2046                 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2047                 break;
2048         case CloudABIMSFlags:
2049                 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2050                 break;
2051         case CloudABIOFlags:
2052                 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2053                 break;
2054         case CloudABISDFlags:
2055                 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2056                 break;
2057         case CloudABISignal:
2058                 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2059                 break;
2060         case CloudABISockStat: {
2061                 cloudabi_sockstat_t ss;
2062                 if (get_struct(pid, (void *)args[sc->offset], &ss, sizeof(ss))
2063                     != -1) {
2064                         fprintf(fp, "{ %s, ", xlookup(
2065                             cloudabi_sa_family, ss.ss_sockname.sa_family));
2066                         fprintf(fp, "%s, ", xlookup(
2067                             cloudabi_sa_family, ss.ss_peername.sa_family));
2068                         fprintf(fp, "%s, ", xlookup(
2069                             cloudabi_errno, ss.ss_error));
2070                         fprintf(fp, "%s }", xlookup_bits(
2071                             cloudabi_ssstate, ss.ss_state));
2072                 } else
2073                         fprintf(fp, "0x%lx", args[sc->offset]);
2074                 break;
2075         }
2076         case CloudABISSFlags:
2077                 fputs(xlookup_bits(cloudabi_ssflags, args[sc->offset]), fp);
2078                 break;
2079         case CloudABITimestamp:
2080                 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2081                     args[sc->offset] % 1000000000);
2082                 break;
2083         case CloudABIULFlags:
2084                 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2085                 break;
2086         case CloudABIWhence:
2087                 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2088                 break;
2089
2090         default:
2091                 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2092         }
2093         fclose(fp);
2094         return (tmp);
2095 }
2096
2097 /*
2098  * Print (to outfile) the system call and its arguments.
2099  */
2100 void
2101 print_syscall(struct trussinfo *trussinfo)
2102 {
2103         struct threadinfo *t;
2104         const char *name;
2105         char **s_args;
2106         int i, len, nargs;
2107
2108         t = trussinfo->curthread;
2109
2110         name = t->cs.sc->name;
2111         nargs = t->cs.nargs;
2112         s_args = t->cs.s_args;
2113
2114         len = print_line_prefix(trussinfo);
2115         len += fprintf(trussinfo->outfile, "%s(", name);
2116
2117         for (i = 0; i < nargs; i++) {
2118                 if (s_args[i] != NULL)
2119                         len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2120                 else
2121                         len += fprintf(trussinfo->outfile,
2122                             "<missing argument>");
2123                 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2124                     "," : "");
2125         }
2126         len += fprintf(trussinfo->outfile, ")");
2127         for (i = 0; i < 6 - (len / 8); i++)
2128                 fprintf(trussinfo->outfile, "\t");
2129 }
2130
2131 void
2132 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
2133 {
2134         struct timespec timediff;
2135         struct threadinfo *t;
2136         struct syscall *sc;
2137         int error;
2138
2139         t = trussinfo->curthread;
2140         sc = t->cs.sc;
2141         if (trussinfo->flags & COUNTONLY) {
2142                 timespecsubt(&t->after, &t->before, &timediff);
2143                 timespecadd(&sc->time, &timediff, &sc->time);
2144                 sc->ncalls++;
2145                 if (errorp)
2146                         sc->nerror++;
2147                 return;
2148         }
2149
2150         print_syscall(trussinfo);
2151         fflush(trussinfo->outfile);
2152
2153         if (retval == NULL) {
2154                 /*
2155                  * This system call resulted in the current thread's exit,
2156                  * so there is no return value or error to display.
2157                  */
2158                 fprintf(trussinfo->outfile, "\n");
2159                 return;
2160         }
2161
2162         if (errorp) {
2163                 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi,
2164                     retval[0]);
2165                 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
2166                     error == INT_MAX ? "Unknown error" : strerror(error));
2167         }
2168 #ifndef __LP64__
2169         else if (sc->ret_type == 2) {
2170                 off_t off;
2171
2172 #if _BYTE_ORDER == _LITTLE_ENDIAN
2173                 off = (off_t)retval[1] << 32 | retval[0];
2174 #else
2175                 off = (off_t)retval[0] << 32 | retval[1];
2176 #endif
2177                 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2178                     (intmax_t)off);
2179         }
2180 #endif
2181         else
2182                 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
2183                     retval[0]);
2184 }
2185
2186 void
2187 print_summary(struct trussinfo *trussinfo)
2188 {
2189         struct timespec total = {0, 0};
2190         struct syscall *sc;
2191         int ncall, nerror;
2192
2193         fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2194             "syscall", "seconds", "calls", "errors");
2195         ncall = nerror = 0;
2196         STAILQ_FOREACH(sc, &syscalls, entries)
2197                 if (sc->ncalls) {
2198                         fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2199                             sc->name, (intmax_t)sc->time.tv_sec,
2200                             sc->time.tv_nsec, sc->ncalls, sc->nerror);
2201                         timespecadd(&total, &sc->time, &total);
2202                         ncall += sc->ncalls;
2203                         nerror += sc->nerror;
2204                 }
2205         fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2206             "", "-------------", "-------", "-------");
2207         fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2208             "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);
2209 }