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