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