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