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