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