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