]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/truss/syscalls.c
Decode arguments passed to thr_set_name().
[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 = "thr_set_name", .ret_type = 1, .nargs = 2,
487           .args = { { Long, 0 }, { Name, 1 } } },
488         { .name = "truncate", .ret_type = 1, .nargs = 2,
489           .args = { { Name | IN, 0 }, { QuadHex | IN, 1 } } },
490 #if 0
491         /* Does not exist */
492         { .name = "umount", .ret_type = 1, .nargs = 2,
493           .args = { { Name, 0 }, { Int, 2 } } },
494 #endif
495         { .name = "unlink", .ret_type = 1, .nargs = 1,
496           .args = { { Name, 0 } } },
497         { .name = "unlinkat", .ret_type = 1, .nargs = 3,
498           .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
499         { .name = "unmount", .ret_type = 1, .nargs = 2,
500           .args = { { Name, 0 }, { Mountflags, 1 } } },
501         { .name = "utimensat", .ret_type = 1, .nargs = 4,
502           .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
503                     { Atflags, 3 } } },
504         { .name = "utimes", .ret_type = 1, .nargs = 2,
505           .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
506         { .name = "utrace", .ret_type = 1, .nargs = 1,
507           .args = { { Utrace, 0 } } },
508         { .name = "wait4", .ret_type = 1, .nargs = 4,
509           .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
510                     { Rusage | OUT, 3 } } },
511         { .name = "wait6", .ret_type = 1, .nargs = 6,
512           .args = { { Idtype, 0 }, { Quad, 1 }, { ExitStatus | OUT, 2 },
513                     { Waitoptions, 3 }, { Rusage | OUT, 4 }, { Ptr, 5 } } },
514         { .name = "write", .ret_type = 1, .nargs = 3,
515           .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 } } },
516
517         /* Linux ABI */
518         { .name = "linux_access", .ret_type = 1, .nargs = 2,
519           .args = { { Name, 0 }, { Accessmode, 1 } } },
520         { .name = "linux_execve", .ret_type = 1, .nargs = 3,
521           .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
522                     { ExecEnv | IN, 2 } } },
523         { .name = "linux_lseek", .ret_type = 2, .nargs = 3,
524           .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
525         { .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
526           .args = { { Name | IN, 0 }, { Int, 1 } } },
527         { .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
528           .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
529         { .name = "linux_newstat", .ret_type = 1, .nargs = 2,
530           .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
531         { .name = "linux_open", .ret_type = 1, .nargs = 3,
532           .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
533         { .name = "linux_readlink", .ret_type = 1, .nargs = 3,
534           .args = { { Name, 0 }, { Name | OUT, 1 }, { Sizet, 2 } } },
535         { .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
536           .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
537         { .name = "linux_stat64", .ret_type = 1, .nargs = 2,
538           .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
539
540         /* CloudABI system calls. */
541         { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
542           .args = { { CloudABIClockID, 0 } } },
543         { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
544           .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
545         { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
546           .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
547         { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
548           .args = { { Int, 0 } } },
549         { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
550           .args = { { CloudABIFileType, 0 } } },
551         { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
552           .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
553         { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
554           .args = { { Int, 0 } } },
555         { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
556           .args = { { Int, 0 } } },
557         { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
558           .args = { { Int, 0 }, { Int, 1 } } },
559         { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
560           .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
561         { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
562           .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
563         { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
564           .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
565                     { ClouduABIFDSFlags, 2 } } },
566         { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
567           .args = { { Int, 0 } } },
568         { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
569           .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
570                     { CloudABIAdvice, 3 } } },
571         { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
572           .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
573         { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
574           .args = { { Int, 0 }, { BinString | IN, 1 },
575                     { CloudABIFileType, 3 } } },
576         { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
577           .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
578                     { Int, 3 }, { BinString | IN, 4 } } },
579         { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
580           .args = { { Int, 0 }, { BinString | IN, 1 },
581                     { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
582         { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
583           .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
584                     { Int, 3 } } },
585         { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
586           .args = { { Int, 0 }, { BinString | IN, 1 },
587                     { BinString | OUT, 3 }, { Int, 4 } } },
588         { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
589           .args = { { Int, 0 }, { BinString | IN, 1 },
590                     { Int, 3 }, { BinString | IN, 4 } } },
591         { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
592           .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
593         { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
594           .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
595                     { CloudABIFSFlags, 2 } } },
596         { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
597           .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
598                     { CloudABIFileStat | OUT, 3 } } },
599         { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
600           .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
601                     { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
602         { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
603           .args = { { BinString | IN, 0 },
604                     { Int, 2 }, { BinString | IN, 3 } } },
605         { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
606           .args = { { Int, 0 }, { BinString | IN, 1 },
607                     { CloudABIULFlags, 3 } } },
608         { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
609           .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
610         { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
611           .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
612         { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
613           .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
614                     { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
615         { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
616           .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
617         { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
618           .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
619         { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
620           .args = { { Ptr, 0 }, { Int, 1 } } },
621         { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
622           .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
623                     { IntArray, 3 }, { Int, 4 } } },
624         { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
625           .args = { { Int, 0 } } },
626         { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
627         { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
628           .args = { { CloudABISignal, 0 } } },
629         { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
630           .args = { { BinString | OUT, 0 }, { Int, 1 } } },
631         { .name = "cloudabi_sys_sock_accept", .ret_type = 1, .nargs = 2,
632           .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 } } },
633         { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
634           .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
635         { .name = "cloudabi_sys_sock_stat_get", .ret_type = 1, .nargs = 3,
636           .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 },
637                     { CloudABISSFlags, 2 } } },
638         { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
639           .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
640         { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
641
642         { .name = 0 },
643 };
644 static STAILQ_HEAD(, syscall) syscalls;
645
646 /* Xlat idea taken from strace */
647 struct xlat {
648         int val;
649         const char *str;
650 };
651
652 #define X(a)    { a, #a },
653 #define XEND    { 0, NULL }
654
655 static struct xlat kevent_filters[] = {
656         X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
657         X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
658         X(EVFILT_PROCDESC) X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER)
659         X(EVFILT_SENDFILE) XEND
660 };
661
662 static struct xlat kevent_flags[] = {
663         X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
664         X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH) X(EV_FORCEONESHOT)
665         X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
666 };
667
668 static struct xlat kevent_user_ffctrl[] = {
669         X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
670         XEND
671 };
672
673 static struct xlat kevent_rdwr_fflags[] = {
674         X(NOTE_LOWAT) X(NOTE_FILE_POLL) XEND
675 };
676
677 static struct xlat kevent_vnode_fflags[] = {
678         X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB)
679         X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND
680 };
681
682 static struct xlat kevent_proc_fflags[] = {
683         X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR)
684         X(NOTE_CHILD) XEND
685 };
686
687 static struct xlat kevent_timer_fflags[] = {
688         X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS)
689         XEND
690 };
691
692 static struct xlat poll_flags[] = {
693         X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
694         X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
695         X(POLLWRBAND) X(POLLINIGNEOF) XEND
696 };
697
698 static struct xlat sigaction_flags[] = {
699         X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
700         X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
701 };
702
703 static struct xlat pathconf_arg[] = {
704         X(_PC_LINK_MAX)  X(_PC_MAX_CANON)  X(_PC_MAX_INPUT)
705         X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF)
706         X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE)
707         X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO)
708         X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS)
709         X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE)
710         X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
711         X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
712         X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
713         X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND
714 };
715
716 static struct xlat at_flags[] = {
717         X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW)
718         X(AT_REMOVEDIR) XEND
719 };
720
721 static struct xlat sysarch_ops[] = {
722 #if defined(__i386__) || defined(__amd64__)
723         X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM)
724         X(I386_VM86) X(I386_GET_FSBASE) X(I386_SET_FSBASE) X(I386_GET_GSBASE)
725         X(I386_SET_GSBASE) X(I386_GET_XFPUSTATE) X(AMD64_GET_FSBASE)
726         X(AMD64_SET_FSBASE) X(AMD64_GET_GSBASE) X(AMD64_SET_GSBASE)
727         X(AMD64_GET_XFPUSTATE)
728 #endif
729         XEND
730 };
731
732 static struct xlat linux_socketcall_ops[] = {
733         X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
734         X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
735         X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
736         X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
737         X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
738         XEND
739 };
740
741 #undef X
742 #define X(a)    { CLOUDABI_##a, #a },
743
744 static struct xlat cloudabi_advice[] = {
745         X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
746         X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
747         XEND
748 };
749
750 static struct xlat cloudabi_clockid[] = {
751         X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
752         X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
753         XEND
754 };
755
756 static struct xlat cloudabi_errno[] = {
757         X(E2BIG) X(EACCES) X(EADDRINUSE) X(EADDRNOTAVAIL)
758         X(EAFNOSUPPORT) X(EAGAIN) X(EALREADY) X(EBADF) X(EBADMSG)
759         X(EBUSY) X(ECANCELED) X(ECHILD) X(ECONNABORTED) X(ECONNREFUSED)
760         X(ECONNRESET) X(EDEADLK) X(EDESTADDRREQ) X(EDOM) X(EDQUOT)
761         X(EEXIST) X(EFAULT) X(EFBIG) X(EHOSTUNREACH) X(EIDRM) X(EILSEQ)
762         X(EINPROGRESS) X(EINTR) X(EINVAL) X(EIO) X(EISCONN) X(EISDIR)
763         X(ELOOP) X(EMFILE) X(EMLINK) X(EMSGSIZE) X(EMULTIHOP)
764         X(ENAMETOOLONG) X(ENETDOWN) X(ENETRESET) X(ENETUNREACH)
765         X(ENFILE) X(ENOBUFS) X(ENODEV) X(ENOENT) X(ENOEXEC) X(ENOLCK)
766         X(ENOLINK) X(ENOMEM) X(ENOMSG) X(ENOPROTOOPT) X(ENOSPC)
767         X(ENOSYS) X(ENOTCONN) X(ENOTDIR) X(ENOTEMPTY) X(ENOTRECOVERABLE)
768         X(ENOTSOCK) X(ENOTSUP) X(ENOTTY) X(ENXIO) X(EOVERFLOW)
769         X(EOWNERDEAD) X(EPERM) X(EPIPE) X(EPROTO) X(EPROTONOSUPPORT)
770         X(EPROTOTYPE) X(ERANGE) X(EROFS) X(ESPIPE) X(ESRCH) X(ESTALE)
771         X(ETIMEDOUT) X(ETXTBSY) X(EXDEV) X(ENOTCAPABLE)
772         XEND
773 };
774
775 static struct xlat cloudabi_fdflags[] = {
776         X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
777         X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
778         XEND
779 };
780
781 static struct xlat cloudabi_fdsflags[] = {
782         X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
783         XEND
784 };
785
786 static struct xlat cloudabi_filetype[] = {
787         X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
788         X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
789         X(FILETYPE_FIFO) X(FILETYPE_POLL) X(FILETYPE_PROCESS)
790         X(FILETYPE_REGULAR_FILE) X(FILETYPE_SHARED_MEMORY)
791         X(FILETYPE_SOCKET_DGRAM) X(FILETYPE_SOCKET_STREAM)
792         X(FILETYPE_SYMBOLIC_LINK)
793         XEND
794 };
795
796 static struct xlat cloudabi_fsflags[] = {
797         X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
798         X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
799         XEND
800 };
801
802 static struct xlat cloudabi_mflags[] = {
803         X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
804         XEND
805 };
806
807 static struct xlat cloudabi_mprot[] = {
808         X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
809         XEND
810 };
811
812 static struct xlat cloudabi_msflags[] = {
813         X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
814         XEND
815 };
816
817 static struct xlat cloudabi_oflags[] = {
818         X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
819         XEND
820 };
821
822 static struct xlat cloudabi_sdflags[] = {
823         X(SHUT_RD) X(SHUT_WR)
824         XEND
825 };
826
827 static struct xlat cloudabi_signal[] = {
828         X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
829         X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
830         X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
831         X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
832         X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
833         XEND
834 };
835
836 static struct xlat cloudabi_ssflags[] = {
837         X(SOCKSTAT_CLEAR_ERROR)
838         XEND
839 };
840
841 static struct xlat cloudabi_ssstate[] = {
842         X(SOCKSTATE_ACCEPTCONN)
843         XEND
844 };
845
846 static struct xlat cloudabi_ulflags[] = {
847         X(UNLINK_REMOVEDIR)
848         XEND
849 };
850
851 static struct xlat cloudabi_whence[] = {
852         X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
853         XEND
854 };
855
856 #undef X
857 #undef XEND
858
859 /*
860  * Searches an xlat array for a value, and returns it if found.  Otherwise
861  * return a string representation.
862  */
863 static const char *
864 lookup(struct xlat *xlat, int val, int base)
865 {
866         static char tmp[16];
867
868         for (; xlat->str != NULL; xlat++)
869                 if (xlat->val == val)
870                         return (xlat->str);
871         switch (base) {
872                 case 8:
873                         sprintf(tmp, "0%o", val);
874                         break;
875                 case 16:
876                         sprintf(tmp, "0x%x", val);
877                         break;
878                 case 10:
879                         sprintf(tmp, "%u", val);
880                         break;
881                 default:
882                         errx(1,"Unknown lookup base");
883                         break;
884         }
885         return (tmp);
886 }
887
888 static const char *
889 xlookup(struct xlat *xlat, int val)
890 {
891
892         return (lookup(xlat, val, 16));
893 }
894
895 /*
896  * Searches an xlat array containing bitfield values.  Remaining bits
897  * set after removing the known ones are printed at the end:
898  * IN|0x400.
899  */
900 static char *
901 xlookup_bits(struct xlat *xlat, int val)
902 {
903         int len, rem;
904         static char str[512];
905
906         len = 0;
907         rem = val;
908         for (; xlat->str != NULL; xlat++) {
909                 if ((xlat->val & rem) == xlat->val) {
910                         /*
911                          * Don't print the "all-bits-zero" string unless all
912                          * bits are really zero.
913                          */
914                         if (xlat->val == 0 && val != 0)
915                                 continue;
916                         len += sprintf(str + len, "%s|", xlat->str);
917                         rem &= ~(xlat->val);
918                 }
919         }
920
921         /*
922          * If we have leftover bits or didn't match anything, print
923          * the remainder.
924          */
925         if (rem || len == 0)
926                 len += sprintf(str + len, "0x%x", rem);
927         if (len && str[len - 1] == '|')
928                 len--;
929         str[len] = 0;
930         return (str);
931 }
932
933 static void
934 print_integer_arg(const char *(*decoder)(int), FILE *fp, int value)
935 {
936         const char *str;
937
938         str = decoder(value);
939         if (str != NULL)
940                 fputs(str, fp);
941         else
942                 fprintf(fp, "%d", value);
943 }
944
945 static void
946 print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value)
947 {
948         int rem;
949
950         if (!decoder(fp, value, &rem))
951                 fprintf(fp, "0x%x", rem);
952         else if (rem != 0)
953                 fprintf(fp, "|0x%x", rem);
954 }
955
956 static void
957 print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), FILE *fp,
958     uint32_t value)
959 {
960         uint32_t rem;
961
962         if (!decoder(fp, value, &rem))
963                 fprintf(fp, "0x%x", rem);
964         else if (rem != 0)
965                 fprintf(fp, "|0x%x", rem);
966 }
967
968 #ifndef __LP64__
969 /*
970  * Add argument padding to subsequent system calls afater a Quad
971  * syscall arguments as needed.  This used to be done by hand in the
972  * decoded_syscalls table which was ugly and error prone.  It is
973  * simpler to do the fixup of offsets at initalization time than when
974  * decoding arguments.
975  */
976 static void
977 quad_fixup(struct syscall *sc)
978 {
979         int offset, prev;
980         u_int i;
981
982         offset = 0;
983         prev = -1;
984         for (i = 0; i < sc->nargs; i++) {
985                 /* This arg type is a dummy that doesn't use offset. */
986                 if ((sc->args[i].type & ARG_MASK) == PipeFds)
987                         continue;
988
989                 assert(prev < sc->args[i].offset);
990                 prev = sc->args[i].offset;
991                 sc->args[i].offset += offset;
992                 switch (sc->args[i].type & ARG_MASK) {
993                 case Quad:
994                 case QuadHex:
995 #ifdef __powerpc__
996                         /*
997                          * 64-bit arguments on 32-bit powerpc must be
998                          * 64-bit aligned.  If the current offset is
999                          * not aligned, the calling convention inserts
1000                          * a 32-bit pad argument that should be skipped.
1001                          */
1002                         if (sc->args[i].offset % 2 == 1) {
1003                                 sc->args[i].offset++;
1004                                 offset++;
1005                         }
1006 #endif
1007                         offset++;
1008                 default:
1009                         break;
1010                 }
1011         }
1012 }
1013 #endif
1014
1015 void
1016 init_syscalls(void)
1017 {
1018         struct syscall *sc;
1019
1020         STAILQ_INIT(&syscalls);
1021         for (sc = decoded_syscalls; sc->name != NULL; sc++) {
1022 #ifndef __LP64__
1023                 quad_fixup(sc);
1024 #endif
1025                 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
1026         }
1027 }
1028
1029 static struct syscall *
1030 find_syscall(struct procabi *abi, u_int number)
1031 {
1032         struct extra_syscall *es;
1033
1034         if (number < nitems(abi->syscalls))
1035                 return (abi->syscalls[number]);
1036         STAILQ_FOREACH(es, &abi->extra_syscalls, entries) {
1037                 if (es->number == number)
1038                         return (es->sc);
1039         }
1040         return (NULL);
1041 }
1042
1043 static void
1044 add_syscall(struct procabi *abi, u_int number, struct syscall *sc)
1045 {
1046         struct extra_syscall *es;
1047
1048         if (number < nitems(abi->syscalls)) {
1049                 assert(abi->syscalls[number] == NULL);
1050                 abi->syscalls[number] = sc;
1051         } else {
1052                 es = malloc(sizeof(*es));
1053                 es->sc = sc;
1054                 es->number = number;
1055                 STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries);
1056         }
1057 }
1058
1059 /*
1060  * If/when the list gets big, it might be desirable to do it
1061  * as a hash table or binary search.
1062  */
1063 struct syscall *
1064 get_syscall(struct threadinfo *t, u_int number, u_int nargs)
1065 {
1066         struct syscall *sc;
1067         const char *name;
1068         char *new_name;
1069         u_int i;
1070
1071         sc = find_syscall(t->proc->abi, number);
1072         if (sc != NULL)
1073                 return (sc);
1074
1075         name = sysdecode_syscallname(t->proc->abi->abi, number);
1076         if (name == NULL) {
1077                 asprintf(&new_name, "#%d", number);
1078                 name = new_name;
1079         } else
1080                 new_name = NULL;
1081         STAILQ_FOREACH(sc, &syscalls, entries) {
1082                 if (strcmp(name, sc->name) == 0) {
1083                         add_syscall(t->proc->abi, number, sc);
1084                         free(new_name);
1085                         return (sc);
1086                 }
1087         }
1088
1089         /* It is unknown.  Add it into the list. */
1090 #if DEBUG
1091         fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
1092             nargs);
1093 #endif
1094
1095         sc = calloc(1, sizeof(struct syscall));
1096         sc->name = name;
1097         if (new_name != NULL)
1098                 sc->unknown = true;
1099         sc->ret_type = 1;
1100         sc->nargs = nargs;
1101         for (i = 0; i < nargs; i++) {
1102                 sc->args[i].offset = i;
1103                 /* Treat all unknown arguments as LongHex. */
1104                 sc->args[i].type = LongHex;
1105         }
1106         STAILQ_INSERT_HEAD(&syscalls, sc, entries);
1107         add_syscall(t->proc->abi, number, sc);
1108
1109         return (sc);
1110 }
1111
1112 /*
1113  * Copy a fixed amount of bytes from the process.
1114  */
1115 static int
1116 get_struct(pid_t pid, void *offset, void *buf, int len)
1117 {
1118         struct ptrace_io_desc iorequest;
1119
1120         iorequest.piod_op = PIOD_READ_D;
1121         iorequest.piod_offs = offset;
1122         iorequest.piod_addr = buf;
1123         iorequest.piod_len = len;
1124         if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
1125                 return (-1);
1126         return (0);
1127 }
1128
1129 #define MAXSIZE         4096
1130
1131 /*
1132  * Copy a string from the process.  Note that it is
1133  * expected to be a C string, but if max is set, it will
1134  * only get that much.
1135  */
1136 static char *
1137 get_string(pid_t pid, void *addr, int max)
1138 {
1139         struct ptrace_io_desc iorequest;
1140         char *buf, *nbuf;
1141         size_t offset, size, totalsize;
1142
1143         offset = 0;
1144         if (max)
1145                 size = max + 1;
1146         else {
1147                 /* Read up to the end of the current page. */
1148                 size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE);
1149                 if (size > MAXSIZE)
1150                         size = MAXSIZE;
1151         }
1152         totalsize = size;
1153         buf = malloc(totalsize);
1154         if (buf == NULL)
1155                 return (NULL);
1156         for (;;) {
1157                 iorequest.piod_op = PIOD_READ_D;
1158                 iorequest.piod_offs = (char *)addr + offset;
1159                 iorequest.piod_addr = buf + offset;
1160                 iorequest.piod_len = size;
1161                 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
1162                         free(buf);
1163                         return (NULL);
1164                 }
1165                 if (memchr(buf + offset, '\0', size) != NULL)
1166                         return (buf);
1167                 offset += size;
1168                 if (totalsize < MAXSIZE && max == 0) {
1169                         size = MAXSIZE - totalsize;
1170                         if (size > PAGE_SIZE)
1171                                 size = PAGE_SIZE;
1172                         nbuf = realloc(buf, totalsize + size);
1173                         if (nbuf == NULL) {
1174                                 buf[totalsize - 1] = '\0';
1175                                 return (buf);
1176                         }
1177                         buf = nbuf;
1178                         totalsize += size;
1179                 } else {
1180                         buf[totalsize - 1] = '\0';
1181                         return (buf);
1182                 }
1183         }
1184 }
1185
1186 static const char *
1187 strsig2(int sig)
1188 {
1189         static char tmp[32];
1190         const char *signame;
1191
1192         signame = sysdecode_signal(sig);
1193         if (signame == NULL) {
1194                 snprintf(tmp, sizeof(tmp), "%d", sig);
1195                 signame = tmp;
1196         }
1197         return (signame);
1198 }
1199
1200 static void
1201 print_kevent(FILE *fp, struct kevent *ke, int input)
1202 {
1203
1204         switch (ke->filter) {
1205         case EVFILT_READ:
1206         case EVFILT_WRITE:
1207         case EVFILT_VNODE:
1208         case EVFILT_PROC:
1209         case EVFILT_TIMER:
1210         case EVFILT_PROCDESC:
1211                 fprintf(fp, "%ju", (uintmax_t)ke->ident);
1212                 break;
1213         case EVFILT_SIGNAL:
1214                 fputs(strsig2(ke->ident), fp);
1215                 break;
1216         default:
1217                 fprintf(fp, "%p", (void *)ke->ident);
1218         }
1219         fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter),
1220             xlookup_bits(kevent_flags, ke->flags));
1221         switch (ke->filter) {
1222         case EVFILT_READ:
1223         case EVFILT_WRITE:
1224                 fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp);
1225                 break;
1226         case EVFILT_VNODE:
1227                 fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp);
1228                 break;
1229         case EVFILT_PROC:
1230         case EVFILT_PROCDESC:
1231                 fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp);
1232                 break;
1233         case EVFILT_TIMER:
1234                 fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp);
1235                 break;
1236         case EVFILT_USER: {
1237                 int ctrl, data;
1238
1239                 ctrl = ke->fflags & NOTE_FFCTRLMASK;
1240                 data = ke->fflags & NOTE_FFLAGSMASK;
1241                 if (input) {
1242                         fputs(xlookup(kevent_user_ffctrl, ctrl), fp);
1243                         if (ke->fflags & NOTE_TRIGGER)
1244                                 fputs("|NOTE_TRIGGER", fp);
1245                         if (data != 0)
1246                                 fprintf(fp, "|%#x", data);
1247                 } else {
1248                         fprintf(fp, "%#x", data);
1249                 }
1250                 break;
1251         }
1252         default:
1253                 fprintf(fp, "%#x", ke->fflags);
1254         }
1255         fprintf(fp, ",%#jx,%p", (uintmax_t)ke->data, ke->udata);
1256 }
1257
1258 static void
1259 print_utrace(FILE *fp, void *utrace_addr, size_t len)
1260 {
1261         unsigned char *utrace_buffer;
1262
1263         fprintf(fp, "{ ");
1264         if (sysdecode_utrace(fp, utrace_addr, len)) {
1265                 fprintf(fp, " }");
1266                 return;
1267         }
1268
1269         utrace_buffer = utrace_addr;
1270         fprintf(fp, "%zu:", len);
1271         while (len--)
1272                 fprintf(fp, " %02x", *utrace_buffer++);
1273         fprintf(fp, " }");
1274 }
1275
1276 /*
1277  * Converts a syscall argument into a string.  Said string is
1278  * allocated via malloc(), so needs to be free()'d.  sc is
1279  * a pointer to the syscall description (see above); args is
1280  * an array of all of the system call arguments.
1281  */
1282 char *
1283 print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
1284     struct trussinfo *trussinfo)
1285 {
1286         FILE *fp;
1287         char *tmp;
1288         size_t tmplen;
1289         pid_t pid;
1290
1291         fp = open_memstream(&tmp, &tmplen);
1292         pid = trussinfo->curthread->proc->pid;
1293         switch (sc->type & ARG_MASK) {
1294         case Hex:
1295                 fprintf(fp, "0x%x", (int)args[sc->offset]);
1296                 break;
1297         case Octal:
1298                 fprintf(fp, "0%o", (int)args[sc->offset]);
1299                 break;
1300         case Int:
1301                 fprintf(fp, "%d", (int)args[sc->offset]);
1302                 break;
1303         case UInt:
1304                 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1305                 break;
1306         case PUInt: {
1307                 unsigned int val;
1308
1309                 if (get_struct(pid, (void *)args[sc->offset], &val,
1310                     sizeof(val)) == 0) 
1311                         fprintf(fp, "{ %u }", val);
1312                 else
1313                         fprintf(fp, "0x%lx", args[sc->offset]);
1314                 break;
1315         }
1316         case LongHex:
1317                 fprintf(fp, "0x%lx", args[sc->offset]);
1318                 break;
1319         case Long:
1320                 fprintf(fp, "%ld", args[sc->offset]);
1321                 break;
1322         case Sizet:
1323                 fprintf(fp, "%zu", (size_t)args[sc->offset]);
1324                 break;
1325         case Name: {
1326                 /* NULL-terminated string. */
1327                 char *tmp2;
1328
1329                 tmp2 = get_string(pid, (void*)args[sc->offset], 0);
1330                 fprintf(fp, "\"%s\"", tmp2);
1331                 free(tmp2);
1332                 break;
1333         }
1334         case BinString: {
1335                 /*
1336                  * Binary block of data that might have printable characters.
1337                  * XXX If type|OUT, assume that the length is the syscall's
1338                  * return value.  Otherwise, assume that the length of the block
1339                  * is in the next syscall argument.
1340                  */
1341                 int max_string = trussinfo->strsize;
1342                 char tmp2[max_string + 1], *tmp3;
1343                 int len;
1344                 int truncated = 0;
1345
1346                 if (sc->type & OUT)
1347                         len = retval[0];
1348                 else
1349                         len = args[sc->offset + 1];
1350
1351                 /*
1352                  * Don't print more than max_string characters, to avoid word
1353                  * wrap.  If we have to truncate put some ... after the string.
1354                  */
1355                 if (len > max_string) {
1356                         len = max_string;
1357                         truncated = 1;
1358                 }
1359                 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
1360                     != -1) {
1361                         tmp3 = malloc(len * 4 + 1);
1362                         while (len) {
1363                                 if (strvisx(tmp3, tmp2, len,
1364                                     VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1365                                         break;
1366                                 len--;
1367                                 truncated = 1;
1368                         }
1369                         fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1370                             "..." : "");
1371                         free(tmp3);
1372                 } else {
1373                         fprintf(fp, "0x%lx", args[sc->offset]);
1374                 }
1375                 break;
1376         }
1377         case ExecArgs:
1378         case ExecEnv:
1379         case StringArray: {
1380                 uintptr_t addr;
1381                 union {
1382                         char *strarray[0];
1383                         char buf[PAGE_SIZE];
1384                 } u;
1385                 char *string;
1386                 size_t len;
1387                 u_int first, i;
1388
1389                 /*
1390                  * Only parse argv[] and environment arrays from exec calls
1391                  * if requested.
1392                  */
1393                 if (((sc->type & ARG_MASK) == ExecArgs &&
1394                     (trussinfo->flags & EXECVEARGS) == 0) ||
1395                     ((sc->type & ARG_MASK) == ExecEnv &&
1396                     (trussinfo->flags & EXECVEENVS) == 0)) {
1397                         fprintf(fp, "0x%lx", args[sc->offset]);
1398                         break;
1399                 }
1400
1401                 /*
1402                  * Read a page of pointers at a time.  Punt if the top-level
1403                  * pointer is not aligned.  Note that the first read is of
1404                  * a partial page.
1405                  */
1406                 addr = args[sc->offset];
1407                 if (addr % sizeof(char *) != 0) {
1408                         fprintf(fp, "0x%lx", args[sc->offset]);
1409                         break;
1410                 }
1411
1412                 len = PAGE_SIZE - (addr & PAGE_MASK);
1413                 if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
1414                         fprintf(fp, "0x%lx", args[sc->offset]);
1415                         break;
1416                 }
1417
1418                 fputc('[', fp);
1419                 first = 1;
1420                 i = 0;
1421                 while (u.strarray[i] != NULL) {
1422                         string = get_string(pid, u.strarray[i], 0);
1423                         fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1424                         free(string);
1425                         first = 0;
1426
1427                         i++;
1428                         if (i == len / sizeof(char *)) {
1429                                 addr += len;
1430                                 len = PAGE_SIZE;
1431                                 if (get_struct(pid, (void *)addr, u.buf, len) ==
1432                                     -1) {
1433                                         fprintf(fp, ", <inval>");
1434                                         break;
1435                                 }
1436                                 i = 0;
1437                         }
1438                 }
1439                 fputs(" ]", fp);
1440                 break;
1441         }
1442 #ifdef __LP64__
1443         case Quad:
1444                 fprintf(fp, "%ld", args[sc->offset]);
1445                 break;
1446         case QuadHex:
1447                 fprintf(fp, "0x%lx", args[sc->offset]);
1448                 break;
1449 #else
1450         case Quad:
1451         case QuadHex: {
1452                 unsigned long long ll;
1453
1454 #if _BYTE_ORDER == _LITTLE_ENDIAN
1455                 ll = (unsigned long long)args[sc->offset + 1] << 32 |
1456                     args[sc->offset];
1457 #else
1458                 ll = (unsigned long long)args[sc->offset] << 32 |
1459                     args[sc->offset + 1];
1460 #endif
1461                 if ((sc->type & ARG_MASK) == Quad)
1462                         fprintf(fp, "%lld", ll);
1463                 else
1464                         fprintf(fp, "0x%llx", ll);
1465                 break;
1466         }
1467 #endif
1468         case PQuadHex: {
1469                 uint64_t val;
1470
1471                 if (get_struct(pid, (void *)args[sc->offset], &val,
1472                     sizeof(val)) == 0) 
1473                         fprintf(fp, "{ 0x%jx }", (uintmax_t)val);
1474                 else
1475                         fprintf(fp, "0x%lx", args[sc->offset]);
1476                 break;
1477         }
1478         case Ptr:
1479                 fprintf(fp, "0x%lx", args[sc->offset]);
1480                 break;
1481         case Readlinkres: {
1482                 char *tmp2;
1483
1484                 if (retval[0] == -1)
1485                         break;
1486                 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
1487                 fprintf(fp, "\"%s\"", tmp2);
1488                 free(tmp2);
1489                 break;
1490         }
1491         case Ioctl: {
1492                 const char *temp;
1493                 unsigned long cmd;
1494
1495                 cmd = args[sc->offset];
1496                 temp = sysdecode_ioctlname(cmd);
1497                 if (temp)
1498                         fputs(temp, fp);
1499                 else {
1500                         fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1501                             cmd, cmd & IOC_OUT ? "R" : "",
1502                             cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1503                             isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1504                             cmd & 0xFF, IOCPARM_LEN(cmd));
1505                 }
1506                 break;
1507         }
1508         case Timespec: {
1509                 struct timespec ts;
1510
1511                 if (get_struct(pid, (void *)args[sc->offset], &ts,
1512                     sizeof(ts)) != -1)
1513                         fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1514                             ts.tv_nsec);
1515                 else
1516                         fprintf(fp, "0x%lx", args[sc->offset]);
1517                 break;
1518         }
1519         case Timespec2: {
1520                 struct timespec ts[2];
1521                 const char *sep;
1522                 unsigned int i;
1523
1524                 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
1525                     != -1) {
1526                         fputs("{ ", fp);
1527                         sep = "";
1528                         for (i = 0; i < nitems(ts); i++) {
1529                                 fputs(sep, fp);
1530                                 sep = ", ";
1531                                 switch (ts[i].tv_nsec) {
1532                                 case UTIME_NOW:
1533                                         fprintf(fp, "UTIME_NOW");
1534                                         break;
1535                                 case UTIME_OMIT:
1536                                         fprintf(fp, "UTIME_OMIT");
1537                                         break;
1538                                 default:
1539                                         fprintf(fp, "%jd.%09ld",
1540                                             (intmax_t)ts[i].tv_sec,
1541                                             ts[i].tv_nsec);
1542                                         break;
1543                                 }
1544                         }
1545                         fputs(" }", fp);
1546                 } else
1547                         fprintf(fp, "0x%lx", args[sc->offset]);
1548                 break;
1549         }
1550         case Timeval: {
1551                 struct timeval tv;
1552
1553                 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1554                     != -1)
1555                         fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1556                             tv.tv_usec);
1557                 else
1558                         fprintf(fp, "0x%lx", args[sc->offset]);
1559                 break;
1560         }
1561         case Timeval2: {
1562                 struct timeval tv[2];
1563
1564                 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1565                     != -1)
1566                         fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1567                             (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1568                             (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1569                 else
1570                         fprintf(fp, "0x%lx", args[sc->offset]);
1571                 break;
1572         }
1573         case Itimerval: {
1574                 struct itimerval itv;
1575
1576                 if (get_struct(pid, (void *)args[sc->offset], &itv,
1577                     sizeof(itv)) != -1)
1578                         fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1579                             (intmax_t)itv.it_interval.tv_sec,
1580                             itv.it_interval.tv_usec,
1581                             (intmax_t)itv.it_value.tv_sec,
1582                             itv.it_value.tv_usec);
1583                 else
1584                         fprintf(fp, "0x%lx", args[sc->offset]);
1585                 break;
1586         }
1587         case LinuxSockArgs:
1588         {
1589                 struct linux_socketcall_args largs;
1590
1591                 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
1592                     sizeof(largs)) != -1)
1593                         fprintf(fp, "{ %s, 0x%lx }",
1594                             lookup(linux_socketcall_ops, largs.what, 10),
1595                             (long unsigned int)largs.args);
1596                 else
1597                         fprintf(fp, "0x%lx", args[sc->offset]);
1598                 break;
1599         }
1600         case Pollfd: {
1601                 /*
1602                  * XXX: A Pollfd argument expects the /next/ syscall argument
1603                  * to be the number of fds in the array. This matches the poll
1604                  * syscall.
1605                  */
1606                 struct pollfd *pfd;
1607                 int numfds = args[sc->offset + 1];
1608                 size_t bytes = sizeof(struct pollfd) * numfds;
1609                 int i;
1610
1611                 if ((pfd = malloc(bytes)) == NULL)
1612                         err(1, "Cannot malloc %zu bytes for pollfd array",
1613                             bytes);
1614                 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
1615                     != -1) {
1616                         fputs("{", fp);
1617                         for (i = 0; i < numfds; i++) {
1618                                 fprintf(fp, " %d/%s", pfd[i].fd,
1619                                     xlookup_bits(poll_flags, pfd[i].events));
1620                         }
1621                         fputs(" }", fp);
1622                 } else {
1623                         fprintf(fp, "0x%lx", args[sc->offset]);
1624                 }
1625                 free(pfd);
1626                 break;
1627         }
1628         case Fd_set: {
1629                 /*
1630                  * XXX: A Fd_set argument expects the /first/ syscall argument
1631                  * to be the number of fds in the array.  This matches the
1632                  * select syscall.
1633                  */
1634                 fd_set *fds;
1635                 int numfds = args[0];
1636                 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1637                 int i;
1638
1639                 if ((fds = malloc(bytes)) == NULL)
1640                         err(1, "Cannot malloc %zu bytes for fd_set array",
1641                             bytes);
1642                 if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
1643                     != -1) {
1644                         fputs("{", fp);
1645                         for (i = 0; i < numfds; i++) {
1646                                 if (FD_ISSET(i, fds))
1647                                         fprintf(fp, " %d", i);
1648                         }
1649                         fputs(" }", fp);
1650                 } else
1651                         fprintf(fp, "0x%lx", args[sc->offset]);
1652                 free(fds);
1653                 break;
1654         }
1655         case Signal:
1656                 fputs(strsig2(args[sc->offset]), fp);
1657                 break;
1658         case Sigset: {
1659                 long sig;
1660                 sigset_t ss;
1661                 int i, first;
1662
1663                 sig = args[sc->offset];
1664                 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
1665                     sizeof(ss)) == -1) {
1666                         fprintf(fp, "0x%lx", args[sc->offset]);
1667                         break;
1668                 }
1669                 fputs("{ ", fp);
1670                 first = 1;
1671                 for (i = 1; i < sys_nsig; i++) {
1672                         if (sigismember(&ss, i)) {
1673                                 fprintf(fp, "%s%s", !first ? "|" : "",
1674                                     strsig2(i));
1675                                 first = 0;
1676                         }
1677                 }
1678                 if (!first)
1679                         fputc(' ', fp);
1680                 fputc('}', fp);
1681                 break;
1682         }
1683         case Sigprocmask:
1684                 print_integer_arg(sysdecode_sigprocmask_how, fp,
1685                     args[sc->offset]);
1686                 break;
1687         case Fcntlflag:
1688                 /* XXX: Output depends on the value of the previous argument. */
1689                 if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
1690                         sysdecode_fcntl_arg(fp, args[sc->offset - 1],
1691                             args[sc->offset], 16);
1692                 break;
1693         case Open:
1694                 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
1695                 break;
1696         case Fcntl:
1697                 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
1698                 break;
1699         case Mprot:
1700                 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
1701                 break;
1702         case Mmapflags:
1703                 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
1704                 break;
1705         case Whence:
1706                 print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
1707                 break;
1708         case Sockdomain:
1709                 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
1710                 break;
1711         case Socktype:
1712                 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
1713                 break;
1714         case Shutdown:
1715                 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
1716                 break;
1717         case Resource:
1718                 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
1719                 break;
1720         case RusageWho:
1721                 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]);
1722                 break;
1723         case Pathconf:
1724                 fputs(xlookup(pathconf_arg, args[sc->offset]), fp);
1725                 break;
1726         case Rforkflags:
1727                 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
1728                 break;
1729         case Sockaddr: {
1730                 char addr[64];
1731                 struct sockaddr_in *lsin;
1732                 struct sockaddr_in6 *lsin6;
1733                 struct sockaddr_un *sun;
1734                 struct sockaddr *sa;
1735                 socklen_t len;
1736                 u_char *q;
1737
1738                 if (args[sc->offset] == 0) {
1739                         fputs("NULL", fp);
1740                         break;
1741                 }
1742
1743                 /*
1744                  * Extract the address length from the next argument.  If
1745                  * this is an output sockaddr (OUT is set), then the
1746                  * next argument is a pointer to a socklen_t.  Otherwise
1747                  * the next argument contains a socklen_t by value.
1748                  */
1749                 if (sc->type & OUT) {
1750                         if (get_struct(pid, (void *)args[sc->offset + 1],
1751                             &len, sizeof(len)) == -1) {
1752                                 fprintf(fp, "0x%lx", args[sc->offset]);
1753                                 break;
1754                         }
1755                 } else
1756                         len = args[sc->offset + 1];
1757
1758                 /* If the length is too small, just bail. */
1759                 if (len < sizeof(*sa)) {
1760                         fprintf(fp, "0x%lx", args[sc->offset]);
1761                         break;
1762                 }
1763
1764                 sa = calloc(1, len);
1765                 if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) {
1766                         free(sa);
1767                         fprintf(fp, "0x%lx", args[sc->offset]);
1768                         break;
1769                 }
1770
1771                 switch (sa->sa_family) {
1772                 case AF_INET:
1773                         if (len < sizeof(*lsin))
1774                                 goto sockaddr_short;
1775                         lsin = (struct sockaddr_in *)(void *)sa;
1776                         inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1777                         fprintf(fp, "{ AF_INET %s:%d }", addr,
1778                             htons(lsin->sin_port));
1779                         break;
1780                 case AF_INET6:
1781                         if (len < sizeof(*lsin6))
1782                                 goto sockaddr_short;
1783                         lsin6 = (struct sockaddr_in6 *)(void *)sa;
1784                         inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1785                             sizeof(addr));
1786                         fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1787                             htons(lsin6->sin6_port));
1788                         break;
1789                 case AF_UNIX:
1790                         sun = (struct sockaddr_un *)sa;
1791                         fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1792                             (int)(len - offsetof(struct sockaddr_un, sun_path)),
1793                             sun->sun_path);
1794                         break;
1795                 default:
1796                 sockaddr_short:
1797                         fprintf(fp,
1798                             "{ sa_len = %d, sa_family = %d, sa_data = {",
1799                             (int)sa->sa_len, (int)sa->sa_family);
1800                         for (q = (u_char *)sa->sa_data;
1801                              q < (u_char *)sa + len; q++)
1802                                 fprintf(fp, "%s 0x%02x",
1803                                     q == (u_char *)sa->sa_data ? "" : ",",
1804                                     *q);
1805                         fputs(" } }", fp);
1806                 }
1807                 free(sa);
1808                 break;
1809         }
1810         case Sigaction: {
1811                 struct sigaction sa;
1812
1813                 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
1814                     != -1) {
1815                         fputs("{ ", fp);
1816                         if (sa.sa_handler == SIG_DFL)
1817                                 fputs("SIG_DFL", fp);
1818                         else if (sa.sa_handler == SIG_IGN)
1819                                 fputs("SIG_IGN", fp);
1820                         else
1821                                 fprintf(fp, "%p", sa.sa_handler);
1822                         fprintf(fp, " %s ss_t }",
1823                             xlookup_bits(sigaction_flags, sa.sa_flags));
1824                 } else
1825                         fprintf(fp, "0x%lx", args[sc->offset]);
1826                 break;
1827         }
1828         case Kevent: {
1829                 /*
1830                  * XXX XXX: The size of the array is determined by either the
1831                  * next syscall argument, or by the syscall return value,
1832                  * depending on which argument number we are.  This matches the
1833                  * kevent syscall, but luckily that's the only syscall that uses
1834                  * them.
1835                  */
1836                 struct kevent *ke;
1837                 int numevents = -1;
1838                 size_t bytes;
1839                 int i;
1840
1841                 if (sc->offset == 1)
1842                         numevents = args[sc->offset+1];
1843                 else if (sc->offset == 3 && retval[0] != -1)
1844                         numevents = retval[0];
1845
1846                 if (numevents >= 0) {
1847                         bytes = sizeof(struct kevent) * numevents;
1848                         if ((ke = malloc(bytes)) == NULL)
1849                                 err(1,
1850                                     "Cannot malloc %zu bytes for kevent array",
1851                                     bytes);
1852                 } else
1853                         ke = NULL;
1854                 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
1855                     ke, bytes) != -1) {
1856                         fputc('{', fp);
1857                         for (i = 0; i < numevents; i++) {
1858                                 fputc(' ', fp);
1859                                 print_kevent(fp, &ke[i], sc->offset == 1);
1860                         }
1861                         fputs(" }", fp);
1862                 } else {
1863                         fprintf(fp, "0x%lx", args[sc->offset]);
1864                 }
1865                 free(ke);
1866                 break;
1867         }
1868         case Stat: {
1869                 struct stat st;
1870
1871                 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1872                     != -1) {
1873                         char mode[12];
1874
1875                         strmode(st.st_mode, mode);
1876                         fprintf(fp,
1877                             "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1878                             (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1879                             (long)st.st_blksize);
1880                 } else {
1881                         fprintf(fp, "0x%lx", args[sc->offset]);
1882                 }
1883                 break;
1884         }
1885         case Stat11: {
1886                 struct freebsd11_stat st;
1887
1888                 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1889                     != -1) {
1890                         char mode[12];
1891
1892                         strmode(st.st_mode, mode);
1893                         fprintf(fp,
1894                             "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1895                             (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1896                             (long)st.st_blksize);
1897                 } else {
1898                         fprintf(fp, "0x%lx", args[sc->offset]);
1899                 }
1900                 break;
1901         }
1902         case StatFs: {
1903                 unsigned int i;
1904                 struct statfs buf;
1905
1906                 if (get_struct(pid, (void *)args[sc->offset], &buf,
1907                     sizeof(buf)) != -1) {
1908                         char fsid[17];
1909
1910                         bzero(fsid, sizeof(fsid));
1911                         if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
1912                                 for (i = 0; i < sizeof(buf.f_fsid); i++)
1913                                         snprintf(&fsid[i*2],
1914                                             sizeof(fsid) - (i*2), "%02x",
1915                                             ((u_char *)&buf.f_fsid)[i]);
1916                         }
1917                         fprintf(fp,
1918                             "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
1919                             "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
1920                             buf.f_mntfromname, fsid);
1921                 } else
1922                         fprintf(fp, "0x%lx", args[sc->offset]);
1923                 break;
1924         }
1925
1926         case Rusage: {
1927                 struct rusage ru;
1928
1929                 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
1930                     != -1) {
1931                         fprintf(fp,
1932                             "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
1933                             (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
1934                             (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
1935                             ru.ru_inblock, ru.ru_oublock);
1936                 } else
1937                         fprintf(fp, "0x%lx", args[sc->offset]);
1938                 break;
1939         }
1940         case Rlimit: {
1941                 struct rlimit rl;
1942
1943                 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
1944                     != -1) {
1945                         fprintf(fp, "{ cur=%ju,max=%ju }",
1946                             rl.rlim_cur, rl.rlim_max);
1947                 } else
1948                         fprintf(fp, "0x%lx", args[sc->offset]);
1949                 break;
1950         }
1951         case ExitStatus: {
1952                 int status;
1953
1954                 if (get_struct(pid, (void *)args[sc->offset], &status,
1955                     sizeof(status)) != -1) {
1956                         fputs("{ ", fp);
1957                         if (WIFCONTINUED(status))
1958                                 fputs("CONTINUED", fp);
1959                         else if (WIFEXITED(status))
1960                                 fprintf(fp, "EXITED,val=%d",
1961                                     WEXITSTATUS(status));
1962                         else if (WIFSIGNALED(status))
1963                                 fprintf(fp, "SIGNALED,sig=%s%s",
1964                                     strsig2(WTERMSIG(status)),
1965                                     WCOREDUMP(status) ? ",cored" : "");
1966                         else
1967                                 fprintf(fp, "STOPPED,sig=%s",
1968                                     strsig2(WTERMSIG(status)));
1969                         fputs(" }", fp);
1970                 } else
1971                         fprintf(fp, "0x%lx", args[sc->offset]);
1972                 break;
1973         }
1974         case Waitoptions:
1975                 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]);
1976                 break;
1977         case Idtype:
1978                 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]);
1979                 break;
1980         case Procctl:
1981                 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]);
1982                 break;
1983         case Umtxop:
1984                 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]);
1985                 break;
1986         case Atfd:
1987                 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]);
1988                 break;
1989         case Atflags:
1990                 fputs(xlookup_bits(at_flags, args[sc->offset]), fp);
1991                 break;
1992         case Accessmode:
1993                 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]);
1994                 break;
1995         case Sysarch:
1996                 fputs(xlookup(sysarch_ops, args[sc->offset]), fp);
1997                 break;
1998         case PipeFds:
1999                 /*
2000                  * The pipe() system call in the kernel returns its
2001                  * two file descriptors via return values.  However,
2002                  * the interface exposed by libc is that pipe()
2003                  * accepts a pointer to an array of descriptors.
2004                  * Format the output to match the libc API by printing
2005                  * the returned file descriptors as a fake argument.
2006                  *
2007                  * Overwrite the first retval to signal a successful
2008                  * return as well.
2009                  */
2010                 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
2011                 retval[0] = 0;
2012                 break;
2013         case Utrace: {
2014                 size_t len;
2015                 void *utrace_addr;
2016
2017                 len = args[sc->offset + 1];
2018                 utrace_addr = calloc(1, len);
2019                 if (get_struct(pid, (void *)args[sc->offset],
2020                     (void *)utrace_addr, len) != -1)
2021                         print_utrace(fp, utrace_addr, len);
2022                 else
2023                         fprintf(fp, "0x%lx", args[sc->offset]);
2024                 free(utrace_addr);
2025                 break;
2026         }
2027         case IntArray: {
2028                 int descriptors[16];
2029                 unsigned long i, ndescriptors;
2030                 bool truncated;
2031
2032                 ndescriptors = args[sc->offset + 1];
2033                 truncated = false;
2034                 if (ndescriptors > nitems(descriptors)) {
2035                         ndescriptors = nitems(descriptors);
2036                         truncated = true;
2037                 }
2038                 if (get_struct(pid, (void *)args[sc->offset],
2039                     descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
2040                         fprintf(fp, "{");
2041                         for (i = 0; i < ndescriptors; i++)
2042                                 fprintf(fp, i == 0 ? " %d" : ", %d",
2043                                     descriptors[i]);
2044                         fprintf(fp, truncated ? ", ... }" : " }");
2045                 } else
2046                         fprintf(fp, "0x%lx", args[sc->offset]);
2047                 break;
2048         }
2049         case Pipe2:
2050                 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]);
2051                 break;
2052         case CapFcntlRights: {
2053                 uint32_t rights;
2054
2055                 if (sc->type & OUT) {
2056                         if (get_struct(pid, (void *)args[sc->offset], &rights,
2057                             sizeof(rights)) == -1) {
2058                                 fprintf(fp, "0x%lx", args[sc->offset]);
2059                                 break;
2060                         }
2061                 } else
2062                         rights = args[sc->offset];
2063                 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights);
2064                 break;
2065         }
2066         case Fadvice:
2067                 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]);
2068                 break;
2069         case FileFlags: {
2070                 fflags_t rem;
2071
2072                 if (!sysdecode_fileflags(fp, args[sc->offset], &rem))
2073                         fprintf(fp, "0x%x", rem);
2074                 else if (rem != 0)
2075                         fprintf(fp, "|0x%x", rem);
2076                 break;
2077         }
2078         case Flockop:
2079                 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]);
2080                 break;
2081         case Getfsstatmode:
2082                 print_integer_arg(sysdecode_getfsstat_mode, fp,
2083                     args[sc->offset]);
2084                 break;
2085         case Kldsymcmd:
2086                 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]);
2087                 break;
2088         case Kldunloadflags:
2089                 print_integer_arg(sysdecode_kldunload_flags, fp,
2090                     args[sc->offset]);
2091                 break;
2092         case Madvice:
2093                 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]);
2094                 break;
2095         case Socklent:
2096                 fprintf(fp, "%u", (socklen_t)args[sc->offset]);
2097                 break;
2098         case Sockprotocol: {
2099                 const char *temp;
2100                 int domain, protocol;
2101
2102                 domain = args[sc->offset - 2];
2103                 protocol = args[sc->offset];
2104                 if (protocol == 0) {
2105                         fputs("0", fp);
2106                 } else {
2107                         temp = sysdecode_socket_protocol(domain, protocol);
2108                         if (temp) {
2109                                 fputs(temp, fp);
2110                         } else {
2111                                 fprintf(fp, "%d", protocol);
2112                         }
2113                 }
2114                 break;
2115         }
2116         case Sockoptlevel:
2117                 print_integer_arg(sysdecode_sockopt_level, fp,
2118                     args[sc->offset]);
2119                 break;
2120         case Sockoptname: {
2121                 const char *temp;
2122                 int level, name;
2123
2124                 level = args[sc->offset - 1];
2125                 name = args[sc->offset];
2126                 temp = sysdecode_sockopt_name(level, name);
2127                 if (temp) {
2128                         fputs(temp, fp);
2129                 } else {
2130                         fprintf(fp, "%d", name);
2131                 }
2132                 break;
2133         }
2134         case Msgflags:
2135                 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]);
2136                 break;
2137         case CapRights: {
2138                 cap_rights_t rights;
2139
2140                 if (get_struct(pid, (void *)args[sc->offset], &rights,
2141                     sizeof(rights)) != -1) {
2142                         fputs("{ ", fp);
2143                         sysdecode_cap_rights(fp, &rights);
2144                         fputs(" }", fp);
2145                 } else
2146                         fprintf(fp, "0x%lx", args[sc->offset]);
2147                 break;
2148         }
2149         case Acltype:
2150                 print_integer_arg(sysdecode_acltype, fp, args[sc->offset]);
2151                 break;
2152         case Extattrnamespace:
2153                 print_integer_arg(sysdecode_extattrnamespace, fp,
2154                     args[sc->offset]);
2155                 break;
2156         case Minherit:
2157                 print_integer_arg(sysdecode_minherit_inherit, fp,
2158                     args[sc->offset]);
2159                 break;
2160         case Mlockall:
2161                 print_mask_arg(sysdecode_mlockall_flags, fp, args[sc->offset]);
2162                 break;
2163         case Mountflags:
2164                 print_mask_arg(sysdecode_mount_flags, fp, args[sc->offset]);
2165                 break;
2166         case Msync:
2167                 print_mask_arg(sysdecode_msync_flags, fp, args[sc->offset]);
2168                 break;
2169         case Priowhich:
2170                 print_integer_arg(sysdecode_prio_which, fp, args[sc->offset]);
2171                 break;
2172         case Ptraceop:
2173                 print_integer_arg(sysdecode_ptrace_request, fp,
2174                     args[sc->offset]);
2175                 break;
2176         case Quotactlcmd:
2177                 if (!sysdecode_quotactl_cmd(fp, args[sc->offset]))
2178                         fprintf(fp, "%#x", (int)args[sc->offset]);
2179                 break;
2180         case Reboothowto:
2181                 print_mask_arg(sysdecode_reboot_howto, fp, args[sc->offset]);
2182                 break;
2183         case Rtpriofunc:
2184                 print_integer_arg(sysdecode_rtprio_function, fp,
2185                     args[sc->offset]);
2186                 break;
2187         case Schedpolicy:
2188                 print_integer_arg(sysdecode_scheduler_policy, fp,
2189                     args[sc->offset]);
2190                 break;
2191         case Schedparam: {
2192                 struct sched_param sp;
2193
2194                 if (get_struct(pid, (void *)args[sc->offset], &sp,
2195                     sizeof(sp)) != -1)
2196                         fprintf(fp, "{ %d }", sp.sched_priority);
2197                 else
2198                         fprintf(fp, "0x%lx", args[sc->offset]);
2199                 break;
2200         }
2201
2202         case CloudABIAdvice:
2203                 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
2204                 break;
2205         case CloudABIClockID:
2206                 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2207                 break;
2208         case ClouduABIFDSFlags:
2209                 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2210                 break;
2211         case CloudABIFDStat: {
2212                 cloudabi_fdstat_t fds;
2213                 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds))
2214                     != -1) {
2215                         fprintf(fp, "{ %s, ",
2216                             xlookup(cloudabi_filetype, fds.fs_filetype));
2217                         fprintf(fp, "%s, ... }",
2218                             xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2219                 } else
2220                         fprintf(fp, "0x%lx", args[sc->offset]);
2221                 break;
2222         }
2223         case CloudABIFileStat: {
2224                 cloudabi_filestat_t fsb;
2225                 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb))
2226                     != -1)
2227                         fprintf(fp, "{ %s, %ju }",
2228                             xlookup(cloudabi_filetype, fsb.st_filetype),
2229                             (uintmax_t)fsb.st_size);
2230                 else
2231                         fprintf(fp, "0x%lx", args[sc->offset]);
2232                 break;
2233         }
2234         case CloudABIFileType:
2235                 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2236                 break;
2237         case CloudABIFSFlags:
2238                 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2239                 break;
2240         case CloudABILookup:
2241                 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2242                         fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2243                             (int)args[sc->offset]);
2244                 else
2245                         fprintf(fp, "%d", (int)args[sc->offset]);
2246                 break;
2247         case CloudABIMFlags:
2248                 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2249                 break;
2250         case CloudABIMProt:
2251                 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2252                 break;
2253         case CloudABIMSFlags:
2254                 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2255                 break;
2256         case CloudABIOFlags:
2257                 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2258                 break;
2259         case CloudABISDFlags:
2260                 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2261                 break;
2262         case CloudABISignal:
2263                 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2264                 break;
2265         case CloudABISockStat: {
2266                 cloudabi_sockstat_t ss;
2267                 if (get_struct(pid, (void *)args[sc->offset], &ss, sizeof(ss))
2268                     != -1) {
2269                         fprintf(fp, "%s, ", xlookup(
2270                             cloudabi_errno, ss.ss_error));
2271                         fprintf(fp, "%s }", xlookup_bits(
2272                             cloudabi_ssstate, ss.ss_state));
2273                 } else
2274                         fprintf(fp, "0x%lx", args[sc->offset]);
2275                 break;
2276         }
2277         case CloudABISSFlags:
2278                 fputs(xlookup_bits(cloudabi_ssflags, args[sc->offset]), fp);
2279                 break;
2280         case CloudABITimestamp:
2281                 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2282                     args[sc->offset] % 1000000000);
2283                 break;
2284         case CloudABIULFlags:
2285                 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2286                 break;
2287         case CloudABIWhence:
2288                 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2289                 break;
2290
2291         default:
2292                 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2293         }
2294         fclose(fp);
2295         return (tmp);
2296 }
2297
2298 /*
2299  * Print (to outfile) the system call and its arguments.
2300  */
2301 void
2302 print_syscall(struct trussinfo *trussinfo)
2303 {
2304         struct threadinfo *t;
2305         const char *name;
2306         char **s_args;
2307         int i, len, nargs;
2308
2309         t = trussinfo->curthread;
2310
2311         name = t->cs.sc->name;
2312         nargs = t->cs.nargs;
2313         s_args = t->cs.s_args;
2314
2315         len = print_line_prefix(trussinfo);
2316         len += fprintf(trussinfo->outfile, "%s(", name);
2317
2318         for (i = 0; i < nargs; i++) {
2319                 if (s_args[i] != NULL)
2320                         len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2321                 else
2322                         len += fprintf(trussinfo->outfile,
2323                             "<missing argument>");
2324                 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2325                     "," : "");
2326         }
2327         len += fprintf(trussinfo->outfile, ")");
2328         for (i = 0; i < 6 - (len / 8); i++)
2329                 fprintf(trussinfo->outfile, "\t");
2330 }
2331
2332 void
2333 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
2334 {
2335         struct timespec timediff;
2336         struct threadinfo *t;
2337         struct syscall *sc;
2338         int error;
2339
2340         t = trussinfo->curthread;
2341         sc = t->cs.sc;
2342         if (trussinfo->flags & COUNTONLY) {
2343                 timespecsubt(&t->after, &t->before, &timediff);
2344                 timespecadd(&sc->time, &timediff, &sc->time);
2345                 sc->ncalls++;
2346                 if (errorp)
2347                         sc->nerror++;
2348                 return;
2349         }
2350
2351         print_syscall(trussinfo);
2352         fflush(trussinfo->outfile);
2353
2354         if (retval == NULL) {
2355                 /*
2356                  * This system call resulted in the current thread's exit,
2357                  * so there is no return value or error to display.
2358                  */
2359                 fprintf(trussinfo->outfile, "\n");
2360                 return;
2361         }
2362
2363         if (errorp) {
2364                 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi,
2365                     retval[0]);
2366                 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
2367                     error == INT_MAX ? "Unknown error" : strerror(error));
2368         }
2369 #ifndef __LP64__
2370         else if (sc->ret_type == 2) {
2371                 off_t off;
2372
2373 #if _BYTE_ORDER == _LITTLE_ENDIAN
2374                 off = (off_t)retval[1] << 32 | retval[0];
2375 #else
2376                 off = (off_t)retval[0] << 32 | retval[1];
2377 #endif
2378                 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2379                     (intmax_t)off);
2380         }
2381 #endif
2382         else
2383                 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
2384                     retval[0]);
2385 }
2386
2387 void
2388 print_summary(struct trussinfo *trussinfo)
2389 {
2390         struct timespec total = {0, 0};
2391         struct syscall *sc;
2392         int ncall, nerror;
2393
2394         fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2395             "syscall", "seconds", "calls", "errors");
2396         ncall = nerror = 0;
2397         STAILQ_FOREACH(sc, &syscalls, entries)
2398                 if (sc->ncalls) {
2399                         fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2400                             sc->name, (intmax_t)sc->time.tv_sec,
2401                             sc->time.tv_nsec, sc->ncalls, sc->nerror);
2402                         timespecadd(&total, &sc->time, &total);
2403                         ncall += sc->ncalls;
2404                         nerror += sc->nerror;
2405                 }
2406         fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2407             "", "-------------", "-------", "-------");
2408         fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2409             "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);
2410 }