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