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