]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/truss/syscalls.c
Import libxo-1.3.0:
[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, uintptr_t offset, void *buf, int len)
1055 {
1056         struct ptrace_io_desc iorequest;
1057
1058         iorequest.piod_op = PIOD_READ_D;
1059         iorequest.piod_offs = (void *)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, uintptr_t 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 = (void *)(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_pointer(FILE *fp, uintptr_t arg)
1187 {
1188
1189         fprintf(fp, "%p", (void *)arg);
1190 }
1191
1192 static void
1193 print_sockaddr(FILE *fp, struct trussinfo *trussinfo, uintptr_t arg,
1194     socklen_t len)
1195 {
1196         char addr[64];
1197         struct sockaddr_in *lsin;
1198         struct sockaddr_in6 *lsin6;
1199         struct sockaddr_un *sun;
1200         struct sockaddr *sa;
1201         u_char *q;
1202         pid_t pid = trussinfo->curthread->proc->pid;
1203
1204         if (arg == 0) {
1205                 fputs("NULL", fp);
1206                 return;
1207         }
1208         /* If the length is too small, just bail. */
1209         if (len < sizeof(*sa)) {
1210                 print_pointer(fp, arg);
1211                 return;
1212         }
1213
1214         sa = calloc(1, len);
1215         if (get_struct(pid, arg, sa, len) == -1) {
1216                 free(sa);
1217                 print_pointer(fp, arg);
1218                 return;
1219         }
1220
1221         switch (sa->sa_family) {
1222         case AF_INET:
1223                 if (len < sizeof(*lsin))
1224                         goto sockaddr_short;
1225                 lsin = (struct sockaddr_in *)(void *)sa;
1226                 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1227                 fprintf(fp, "{ AF_INET %s:%d }", addr,
1228                     htons(lsin->sin_port));
1229                 break;
1230         case AF_INET6:
1231                 if (len < sizeof(*lsin6))
1232                         goto sockaddr_short;
1233                 lsin6 = (struct sockaddr_in6 *)(void *)sa;
1234                 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1235                     sizeof(addr));
1236                 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1237                     htons(lsin6->sin6_port));
1238                 break;
1239         case AF_UNIX:
1240                 sun = (struct sockaddr_un *)sa;
1241                 fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1242                     (int)(len - offsetof(struct sockaddr_un, sun_path)),
1243                     sun->sun_path);
1244                 break;
1245         default:
1246         sockaddr_short:
1247                 fprintf(fp,
1248                     "{ sa_len = %d, sa_family = %d, sa_data = {",
1249                     (int)sa->sa_len, (int)sa->sa_family);
1250                 for (q = (u_char *)sa->sa_data;
1251                      q < (u_char *)sa + len; q++)
1252                         fprintf(fp, "%s 0x%02x",
1253                             q == (u_char *)sa->sa_data ? "" : ",",
1254                             *q);
1255                 fputs(" } }", fp);
1256         }
1257         free(sa);
1258 }
1259
1260 #define IOV_LIMIT 16
1261
1262 static void
1263 print_iovec(FILE *fp, struct trussinfo *trussinfo, uintptr_t arg, int iovcnt)
1264 {
1265         struct iovec iov[IOV_LIMIT];
1266         size_t max_string = trussinfo->strsize;
1267         char tmp2[max_string + 1], *tmp3;
1268         size_t len;
1269         pid_t pid = trussinfo->curthread->proc->pid;
1270         int i;
1271         bool buf_truncated, iov_truncated;
1272
1273         if (iovcnt <= 0) {
1274                 print_pointer(fp, arg);
1275                 return;
1276         }
1277         if (iovcnt > IOV_LIMIT) {
1278                 iovcnt = IOV_LIMIT;
1279                 iov_truncated = true;
1280         } else {
1281                 iov_truncated = false;
1282         }
1283         if (get_struct(pid, arg, &iov, iovcnt * sizeof(struct iovec)) == -1) {
1284                 print_pointer(fp, arg);
1285                 return;
1286         }
1287
1288         fputs("[", fp);
1289         for (i = 0; i < iovcnt; i++) {
1290                 len = iov[i].iov_len;
1291                 if (len > max_string) {
1292                         len = max_string;
1293                         buf_truncated = true;
1294                 } else {
1295                         buf_truncated = false;
1296                 }
1297                 fprintf(fp, "%s{", (i > 0) ? "," : "");
1298                 if (len && get_struct(pid, (uintptr_t)iov[i].iov_base, &tmp2, len) != -1) {
1299                         tmp3 = malloc(len * 4 + 1);
1300                         while (len) {
1301                                 if (strvisx(tmp3, tmp2, len,
1302                                     VIS_CSTYLE|VIS_TAB|VIS_NL) <=
1303                                     (int)max_string)
1304                                         break;
1305                                 len--;
1306                                 buf_truncated = true;
1307                         }
1308                         fprintf(fp, "\"%s\"%s", tmp3,
1309                             buf_truncated ? "..." : "");
1310                         free(tmp3);
1311                 } else {
1312                         print_pointer(fp, (uintptr_t)iov[i].iov_base);
1313                 }
1314                 fprintf(fp, ",%zu}", iov[i].iov_len);
1315         }
1316         fprintf(fp, "%s%s", iov_truncated ? ",..." : "", "]");
1317 }
1318
1319 static void
1320 print_gen_cmsg(FILE *fp, struct cmsghdr *cmsghdr)
1321 {
1322         u_char *q;
1323
1324         fputs("{", fp);
1325         for (q = CMSG_DATA(cmsghdr);
1326              q < (u_char *)cmsghdr + cmsghdr->cmsg_len; q++) {
1327                 fprintf(fp, "%s0x%02x", q == CMSG_DATA(cmsghdr) ? "" : ",", *q);
1328         }
1329         fputs("}", fp);
1330 }
1331
1332 static void
1333 print_sctp_initmsg(FILE *fp, struct sctp_initmsg *init)
1334 {
1335         fprintf(fp, "{out=%u,", init->sinit_num_ostreams);
1336         fprintf(fp, "in=%u,", init->sinit_max_instreams);
1337         fprintf(fp, "max_rtx=%u,", init->sinit_max_attempts);
1338         fprintf(fp, "max_rto=%u}", init->sinit_max_init_timeo);
1339 }
1340
1341 static void
1342 print_sctp_sndrcvinfo(FILE *fp, bool receive, struct sctp_sndrcvinfo *info)
1343 {
1344         fprintf(fp, "{sid=%u,", info->sinfo_stream);
1345         if (receive) {
1346                 fprintf(fp, "ssn=%u,", info->sinfo_ssn);
1347         }
1348         fputs("flgs=", fp);
1349         sysdecode_sctp_sinfo_flags(fp, info->sinfo_flags);
1350         fprintf(fp, ",ppid=%u,", ntohl(info->sinfo_ppid));
1351         if (!receive) {
1352                 fprintf(fp, "ctx=%u,", info->sinfo_context);
1353                 fprintf(fp, "ttl=%u,", info->sinfo_timetolive);
1354         }
1355         if (receive) {
1356                 fprintf(fp, "tsn=%u,", info->sinfo_tsn);
1357                 fprintf(fp, "cumtsn=%u,", info->sinfo_cumtsn);
1358         }
1359         fprintf(fp, "id=%u}", info->sinfo_assoc_id);
1360 }
1361
1362 static void
1363 print_sctp_sndinfo(FILE *fp, struct sctp_sndinfo *info)
1364 {
1365         fprintf(fp, "{sid=%u,", info->snd_sid);
1366         fputs("flgs=", fp);
1367         print_mask_arg(sysdecode_sctp_snd_flags, fp, info->snd_flags);
1368         fprintf(fp, ",ppid=%u,", ntohl(info->snd_ppid));
1369         fprintf(fp, "ctx=%u,", info->snd_context);
1370         fprintf(fp, "id=%u}", info->snd_assoc_id);
1371 }
1372
1373 static void
1374 print_sctp_rcvinfo(FILE *fp, struct sctp_rcvinfo *info)
1375 {
1376         fprintf(fp, "{sid=%u,", info->rcv_sid);
1377         fprintf(fp, "ssn=%u,", info->rcv_ssn);
1378         fputs("flgs=", fp);
1379         print_mask_arg(sysdecode_sctp_rcv_flags, fp, info->rcv_flags);
1380         fprintf(fp, ",ppid=%u,", ntohl(info->rcv_ppid));
1381         fprintf(fp, "tsn=%u,", info->rcv_tsn);
1382         fprintf(fp, "cumtsn=%u,", info->rcv_cumtsn);
1383         fprintf(fp, "ctx=%u,", info->rcv_context);
1384         fprintf(fp, "id=%u}", info->rcv_assoc_id);
1385 }
1386
1387 static void
1388 print_sctp_nxtinfo(FILE *fp, struct sctp_nxtinfo *info)
1389 {
1390         fprintf(fp, "{sid=%u,", info->nxt_sid);
1391         fputs("flgs=", fp);
1392         print_mask_arg(sysdecode_sctp_nxt_flags, fp, info->nxt_flags);
1393         fprintf(fp, ",ppid=%u,", ntohl(info->nxt_ppid));
1394         fprintf(fp, "len=%u,", info->nxt_length);
1395         fprintf(fp, "id=%u}", info->nxt_assoc_id);
1396 }
1397
1398 static void
1399 print_sctp_prinfo(FILE *fp, struct sctp_prinfo *info)
1400 {
1401         fputs("{pol=", fp);
1402         print_integer_arg(sysdecode_sctp_pr_policy, fp, info->pr_policy);
1403         fprintf(fp, ",val=%u}", info->pr_value);
1404 }
1405
1406 static void
1407 print_sctp_authinfo(FILE *fp, struct sctp_authinfo *info)
1408 {
1409         fprintf(fp, "{num=%u}", info->auth_keynumber);
1410 }
1411
1412 static void
1413 print_sctp_ipv4_addr(FILE *fp, struct in_addr *addr)
1414 {
1415         char buf[INET_ADDRSTRLEN];
1416         const char *s;
1417
1418         s = inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN);
1419         if (s != NULL)
1420                 fprintf(fp, "{addr=%s}", s);
1421         else
1422                 fputs("{addr=???}", fp);
1423 }
1424
1425 static void
1426 print_sctp_ipv6_addr(FILE *fp, struct in6_addr *addr)
1427 {
1428         char buf[INET6_ADDRSTRLEN];
1429         const char *s;
1430
1431         s = inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN);
1432         if (s != NULL)
1433                 fprintf(fp, "{addr=%s}", s);
1434         else
1435                 fputs("{addr=???}", fp);
1436 }
1437
1438 static void
1439 print_sctp_cmsg(FILE *fp, bool receive, struct cmsghdr *cmsghdr)
1440 {
1441         void *data;
1442         socklen_t len;
1443
1444         len = cmsghdr->cmsg_len;
1445         data = CMSG_DATA(cmsghdr);
1446         switch (cmsghdr->cmsg_type) {
1447         case SCTP_INIT:
1448                 if (len == CMSG_LEN(sizeof(struct sctp_initmsg)))
1449                         print_sctp_initmsg(fp, (struct sctp_initmsg *)data);
1450                 else
1451                         print_gen_cmsg(fp, cmsghdr);
1452                 break;
1453         case SCTP_SNDRCV:
1454                 if (len == CMSG_LEN(sizeof(struct sctp_sndrcvinfo)))
1455                         print_sctp_sndrcvinfo(fp, receive,
1456                             (struct sctp_sndrcvinfo *)data);
1457                 else
1458                         print_gen_cmsg(fp, cmsghdr);
1459                 break;
1460 #if 0
1461         case SCTP_EXTRCV:
1462                 if (len == CMSG_LEN(sizeof(struct sctp_extrcvinfo)))
1463                         print_sctp_extrcvinfo(fp,
1464                             (struct sctp_extrcvinfo *)data);
1465                 else
1466                         print_gen_cmsg(fp, cmsghdr);
1467                 break;
1468 #endif
1469         case SCTP_SNDINFO:
1470                 if (len == CMSG_LEN(sizeof(struct sctp_sndinfo)))
1471                         print_sctp_sndinfo(fp, (struct sctp_sndinfo *)data);
1472                 else
1473                         print_gen_cmsg(fp, cmsghdr);
1474                 break;
1475         case SCTP_RCVINFO:
1476                 if (len == CMSG_LEN(sizeof(struct sctp_rcvinfo)))
1477                         print_sctp_rcvinfo(fp, (struct sctp_rcvinfo *)data);
1478                 else
1479                         print_gen_cmsg(fp, cmsghdr);
1480                 break;
1481         case SCTP_NXTINFO:
1482                 if (len == CMSG_LEN(sizeof(struct sctp_nxtinfo)))
1483                         print_sctp_nxtinfo(fp, (struct sctp_nxtinfo *)data);
1484                 else
1485                         print_gen_cmsg(fp, cmsghdr);
1486                 break;
1487         case SCTP_PRINFO:
1488                 if (len == CMSG_LEN(sizeof(struct sctp_prinfo)))
1489                         print_sctp_prinfo(fp, (struct sctp_prinfo *)data);
1490                 else
1491                         print_gen_cmsg(fp, cmsghdr);
1492                 break;
1493         case SCTP_AUTHINFO:
1494                 if (len == CMSG_LEN(sizeof(struct sctp_authinfo)))
1495                         print_sctp_authinfo(fp, (struct sctp_authinfo *)data);
1496                 else
1497                         print_gen_cmsg(fp, cmsghdr);
1498                 break;
1499         case SCTP_DSTADDRV4:
1500                 if (len == CMSG_LEN(sizeof(struct in_addr)))
1501                         print_sctp_ipv4_addr(fp, (struct in_addr *)data);
1502                 else
1503                         print_gen_cmsg(fp, cmsghdr);
1504                 break;
1505         case SCTP_DSTADDRV6:
1506                 if (len == CMSG_LEN(sizeof(struct in6_addr)))
1507                         print_sctp_ipv6_addr(fp, (struct in6_addr *)data);
1508                 else
1509                         print_gen_cmsg(fp, cmsghdr);
1510                 break;
1511         default:
1512                 print_gen_cmsg(fp, cmsghdr);
1513         }
1514 }
1515
1516 static void
1517 print_cmsgs(FILE *fp, pid_t pid, bool receive, struct msghdr *msghdr)
1518 {
1519         struct cmsghdr *cmsghdr;
1520         char *cmsgbuf;
1521         const char *temp;
1522         socklen_t len;
1523         int level, type;
1524         bool first;
1525
1526         len = msghdr->msg_controllen;
1527         if (len == 0) {
1528                 fputs("{}", fp);
1529                 return;
1530         }
1531         cmsgbuf = calloc(1, len);
1532         if (get_struct(pid, (uintptr_t)msghdr->msg_control, cmsgbuf, len) == -1) {
1533                 print_pointer(fp, (uintptr_t)msghdr->msg_control);
1534                 free(cmsgbuf);
1535                 return;
1536         }
1537         msghdr->msg_control = cmsgbuf;
1538         first = true;
1539         fputs("{", fp);
1540         for (cmsghdr = CMSG_FIRSTHDR(msghdr);
1541            cmsghdr != NULL;
1542            cmsghdr = CMSG_NXTHDR(msghdr, cmsghdr)) {
1543                 level = cmsghdr->cmsg_level;
1544                 type = cmsghdr->cmsg_type;
1545                 len = cmsghdr->cmsg_len;
1546                 fprintf(fp, "%s{level=", first ? "" : ",");
1547                 print_integer_arg(sysdecode_sockopt_level, fp, level);
1548                 fputs(",type=", fp);
1549                 temp = sysdecode_cmsg_type(level, type);
1550                 if (temp) {
1551                         fputs(temp, fp);
1552                 } else {
1553                         fprintf(fp, "%d", type);
1554                 }
1555                 fputs(",data=", fp);
1556                 switch (level) {
1557                 case IPPROTO_SCTP:
1558                         print_sctp_cmsg(fp, receive, cmsghdr);
1559                         break;
1560                 default:
1561                         print_gen_cmsg(fp, cmsghdr);
1562                         break;
1563                 }
1564                 fputs("}", fp);
1565                 first = false;
1566         }
1567         fputs("}", fp);
1568         free(cmsgbuf);
1569 }
1570
1571 static void
1572 print_sysctl_oid(FILE *fp, int *oid, int len)
1573 {
1574         int i;
1575
1576         for (i = 0; i < len; i++)
1577                 fprintf(fp, ".%d", oid[i]);
1578 }
1579
1580 /*
1581  * Converts a syscall argument into a string.  Said string is
1582  * allocated via malloc(), so needs to be free()'d.  sc is
1583  * a pointer to the syscall description (see above); args is
1584  * an array of all of the system call arguments.
1585  */
1586 char *
1587 print_arg(struct syscall_args *sc, unsigned long *args, register_t *retval,
1588     struct trussinfo *trussinfo)
1589 {
1590         FILE *fp;
1591         char *tmp;
1592         size_t tmplen;
1593         pid_t pid;
1594
1595         fp = open_memstream(&tmp, &tmplen);
1596         pid = trussinfo->curthread->proc->pid;
1597         switch (sc->type & ARG_MASK) {
1598         case Hex:
1599                 fprintf(fp, "0x%x", (int)args[sc->offset]);
1600                 break;
1601         case Octal:
1602                 fprintf(fp, "0%o", (int)args[sc->offset]);
1603                 break;
1604         case Int:
1605                 fprintf(fp, "%d", (int)args[sc->offset]);
1606                 break;
1607         case UInt:
1608                 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1609                 break;
1610         case PUInt: {
1611                 unsigned int val;
1612
1613                 if (get_struct(pid, args[sc->offset], &val,
1614                     sizeof(val)) == 0) 
1615                         fprintf(fp, "{ %u }", val);
1616                 else
1617                         print_pointer(fp, args[sc->offset]);
1618                 break;
1619         }
1620         case LongHex:
1621                 fprintf(fp, "0x%lx", args[sc->offset]);
1622                 break;
1623         case Long:
1624                 fprintf(fp, "%ld", args[sc->offset]);
1625                 break;
1626         case Sizet:
1627                 fprintf(fp, "%zu", (size_t)args[sc->offset]);
1628                 break;
1629         case ShmName:
1630                 /* Handle special SHM_ANON value. */
1631                 if ((char *)args[sc->offset] == SHM_ANON) {
1632                         fprintf(fp, "SHM_ANON");
1633                         break;
1634                 }
1635                 /* FALLTHROUGH */
1636         case Name: {
1637                 /* NULL-terminated string. */
1638                 char *tmp2;
1639
1640                 tmp2 = get_string(pid, args[sc->offset], 0);
1641                 fprintf(fp, "\"%s\"", tmp2);
1642                 free(tmp2);
1643                 break;
1644         }
1645         case BinString: {
1646                 /*
1647                  * Binary block of data that might have printable characters.
1648                  * XXX If type|OUT, assume that the length is the syscall's
1649                  * return value.  Otherwise, assume that the length of the block
1650                  * is in the next syscall argument.
1651                  */
1652                 int max_string = trussinfo->strsize;
1653                 char tmp2[max_string + 1], *tmp3;
1654                 int len;
1655                 int truncated = 0;
1656
1657                 if (sc->type & OUT)
1658                         len = retval[0];
1659                 else
1660                         len = args[sc->offset + 1];
1661
1662                 /*
1663                  * Don't print more than max_string characters, to avoid word
1664                  * wrap.  If we have to truncate put some ... after the string.
1665                  */
1666                 if (len > max_string) {
1667                         len = max_string;
1668                         truncated = 1;
1669                 }
1670                 if (len && get_struct(pid, args[sc->offset], &tmp2, len)
1671                     != -1) {
1672                         tmp3 = malloc(len * 4 + 1);
1673                         while (len) {
1674                                 if (strvisx(tmp3, tmp2, len,
1675                                     VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1676                                         break;
1677                                 len--;
1678                                 truncated = 1;
1679                         }
1680                         fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1681                             "..." : "");
1682                         free(tmp3);
1683                 } else {
1684                         print_pointer(fp, args[sc->offset]);
1685                 }
1686                 break;
1687         }
1688         case ExecArgs:
1689         case ExecEnv:
1690         case StringArray: {
1691                 uintptr_t addr;
1692                 union {
1693                         char *strarray[0];
1694                         char buf[PAGE_SIZE];
1695                 } u;
1696                 char *string;
1697                 size_t len;
1698                 u_int first, i;
1699
1700                 /*
1701                  * Only parse argv[] and environment arrays from exec calls
1702                  * if requested.
1703                  */
1704                 if (((sc->type & ARG_MASK) == ExecArgs &&
1705                     (trussinfo->flags & EXECVEARGS) == 0) ||
1706                     ((sc->type & ARG_MASK) == ExecEnv &&
1707                     (trussinfo->flags & EXECVEENVS) == 0)) {
1708                         print_pointer(fp, args[sc->offset]);
1709                         break;
1710                 }
1711
1712                 /*
1713                  * Read a page of pointers at a time.  Punt if the top-level
1714                  * pointer is not aligned.  Note that the first read is of
1715                  * a partial page.
1716                  */
1717                 addr = args[sc->offset];
1718                 if (addr % sizeof(char *) != 0) {
1719                         print_pointer(fp, args[sc->offset]);
1720                         break;
1721                 }
1722
1723                 len = PAGE_SIZE - (addr & PAGE_MASK);
1724                 if (get_struct(pid, addr, u.buf, len) == -1) {
1725                         print_pointer(fp, args[sc->offset]);
1726                         break;
1727                 }
1728
1729                 fputc('[', fp);
1730                 first = 1;
1731                 i = 0;
1732                 while (u.strarray[i] != NULL) {
1733                         string = get_string(pid, (uintptr_t)u.strarray[i], 0);
1734                         fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1735                         free(string);
1736                         first = 0;
1737
1738                         i++;
1739                         if (i == len / sizeof(char *)) {
1740                                 addr += len;
1741                                 len = PAGE_SIZE;
1742                                 if (get_struct(pid, addr, u.buf, len) ==
1743                                     -1) {
1744                                         fprintf(fp, ", <inval>");
1745                                         break;
1746                                 }
1747                                 i = 0;
1748                         }
1749                 }
1750                 fputs(" ]", fp);
1751                 break;
1752         }
1753 #ifdef __LP64__
1754         case Quad:
1755                 fprintf(fp, "%ld", args[sc->offset]);
1756                 break;
1757         case QuadHex:
1758                 fprintf(fp, "0x%lx", args[sc->offset]);
1759                 break;
1760 #else
1761         case Quad:
1762         case QuadHex: {
1763                 unsigned long long ll;
1764
1765 #if _BYTE_ORDER == _LITTLE_ENDIAN
1766                 ll = (unsigned long long)args[sc->offset + 1] << 32 |
1767                     args[sc->offset];
1768 #else
1769                 ll = (unsigned long long)args[sc->offset] << 32 |
1770                     args[sc->offset + 1];
1771 #endif
1772                 if ((sc->type & ARG_MASK) == Quad)
1773                         fprintf(fp, "%lld", ll);
1774                 else
1775                         fprintf(fp, "0x%llx", ll);
1776                 break;
1777         }
1778 #endif
1779         case PQuadHex: {
1780                 uint64_t val;
1781
1782                 if (get_struct(pid, args[sc->offset], &val,
1783                     sizeof(val)) == 0) 
1784                         fprintf(fp, "{ 0x%jx }", (uintmax_t)val);
1785                 else
1786                         print_pointer(fp, args[sc->offset]);
1787                 break;
1788         }
1789         case Ptr:
1790                 print_pointer(fp, args[sc->offset]);
1791                 break;
1792         case Readlinkres: {
1793                 char *tmp2;
1794
1795                 if (retval[0] == -1)
1796                         break;
1797                 tmp2 = get_string(pid, args[sc->offset], retval[0]);
1798                 fprintf(fp, "\"%s\"", tmp2);
1799                 free(tmp2);
1800                 break;
1801         }
1802         case Ioctl: {
1803                 const char *temp;
1804                 unsigned long cmd;
1805
1806                 cmd = args[sc->offset];
1807                 temp = sysdecode_ioctlname(cmd);
1808                 if (temp)
1809                         fputs(temp, fp);
1810                 else {
1811                         fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1812                             cmd, cmd & IOC_OUT ? "R" : "",
1813                             cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1814                             isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1815                             cmd & 0xFF, IOCPARM_LEN(cmd));
1816                 }
1817                 break;
1818         }
1819         case Timespec: {
1820                 struct timespec ts;
1821
1822                 if (get_struct(pid, args[sc->offset], &ts, sizeof(ts)) != -1)
1823                         fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1824                             ts.tv_nsec);
1825                 else
1826                         print_pointer(fp, args[sc->offset]);
1827                 break;
1828         }
1829         case Timespec2: {
1830                 struct timespec ts[2];
1831                 const char *sep;
1832                 unsigned int i;
1833
1834                 if (get_struct(pid, args[sc->offset], &ts, sizeof(ts)) != -1) {
1835                         fputs("{ ", fp);
1836                         sep = "";
1837                         for (i = 0; i < nitems(ts); i++) {
1838                                 fputs(sep, fp);
1839                                 sep = ", ";
1840                                 switch (ts[i].tv_nsec) {
1841                                 case UTIME_NOW:
1842                                         fprintf(fp, "UTIME_NOW");
1843                                         break;
1844                                 case UTIME_OMIT:
1845                                         fprintf(fp, "UTIME_OMIT");
1846                                         break;
1847                                 default:
1848                                         fprintf(fp, "%jd.%09ld",
1849                                             (intmax_t)ts[i].tv_sec,
1850                                             ts[i].tv_nsec);
1851                                         break;
1852                                 }
1853                         }
1854                         fputs(" }", fp);
1855                 } else
1856                         print_pointer(fp, args[sc->offset]);
1857                 break;
1858         }
1859         case Timeval: {
1860                 struct timeval tv;
1861
1862                 if (get_struct(pid, args[sc->offset], &tv, sizeof(tv)) != -1)
1863                         fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1864                             tv.tv_usec);
1865                 else
1866                         print_pointer(fp, args[sc->offset]);
1867                 break;
1868         }
1869         case Timeval2: {
1870                 struct timeval tv[2];
1871
1872                 if (get_struct(pid, args[sc->offset], &tv, sizeof(tv)) != -1)
1873                         fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1874                             (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1875                             (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1876                 else
1877                         print_pointer(fp, args[sc->offset]);
1878                 break;
1879         }
1880         case Itimerval: {
1881                 struct itimerval itv;
1882
1883                 if (get_struct(pid, args[sc->offset], &itv, sizeof(itv)) != -1)
1884                         fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1885                             (intmax_t)itv.it_interval.tv_sec,
1886                             itv.it_interval.tv_usec,
1887                             (intmax_t)itv.it_value.tv_sec,
1888                             itv.it_value.tv_usec);
1889                 else
1890                         print_pointer(fp, args[sc->offset]);
1891                 break;
1892         }
1893         case LinuxSockArgs:
1894         {
1895                 struct linux_socketcall_args largs;
1896
1897                 if (get_struct(pid, args[sc->offset], (void *)&largs,
1898                     sizeof(largs)) != -1)
1899                         fprintf(fp, "{ %s, 0x%lx }",
1900                             lookup(linux_socketcall_ops, largs.what, 10),
1901                             (long unsigned int)largs.args);
1902                 else
1903                         print_pointer(fp, args[sc->offset]);
1904                 break;
1905         }
1906         case Pollfd: {
1907                 /*
1908                  * XXX: A Pollfd argument expects the /next/ syscall argument
1909                  * to be the number of fds in the array. This matches the poll
1910                  * syscall.
1911                  */
1912                 struct pollfd *pfd;
1913                 int numfds = args[sc->offset + 1];
1914                 size_t bytes = sizeof(struct pollfd) * numfds;
1915                 int i;
1916
1917                 if ((pfd = malloc(bytes)) == NULL)
1918                         err(1, "Cannot malloc %zu bytes for pollfd array",
1919                             bytes);
1920                 if (get_struct(pid, args[sc->offset], pfd, bytes) != -1) {
1921                         fputs("{", fp);
1922                         for (i = 0; i < numfds; i++) {
1923                                 fprintf(fp, " %d/%s", pfd[i].fd,
1924                                     xlookup_bits(poll_flags, pfd[i].events));
1925                         }
1926                         fputs(" }", fp);
1927                 } else {
1928                         print_pointer(fp, args[sc->offset]);
1929                 }
1930                 free(pfd);
1931                 break;
1932         }
1933         case Fd_set: {
1934                 /*
1935                  * XXX: A Fd_set argument expects the /first/ syscall argument
1936                  * to be the number of fds in the array.  This matches the
1937                  * select syscall.
1938                  */
1939                 fd_set *fds;
1940                 int numfds = args[0];
1941                 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1942                 int i;
1943
1944                 if ((fds = malloc(bytes)) == NULL)
1945                         err(1, "Cannot malloc %zu bytes for fd_set array",
1946                             bytes);
1947                 if (get_struct(pid, args[sc->offset], fds, bytes) != -1) {
1948                         fputs("{", fp);
1949                         for (i = 0; i < numfds; i++) {
1950                                 if (FD_ISSET(i, fds))
1951                                         fprintf(fp, " %d", i);
1952                         }
1953                         fputs(" }", fp);
1954                 } else
1955                         print_pointer(fp, args[sc->offset]);
1956                 free(fds);
1957                 break;
1958         }
1959         case Signal:
1960                 fputs(strsig2(args[sc->offset]), fp);
1961                 break;
1962         case Sigset: {
1963                 long sig;
1964                 sigset_t ss;
1965                 int i, first;
1966
1967                 sig = args[sc->offset];
1968                 if (get_struct(pid, args[sc->offset], (void *)&ss,
1969                     sizeof(ss)) == -1) {
1970                         print_pointer(fp, args[sc->offset]);
1971                         break;
1972                 }
1973                 fputs("{ ", fp);
1974                 first = 1;
1975                 for (i = 1; i < sys_nsig; i++) {
1976                         if (sigismember(&ss, i)) {
1977                                 fprintf(fp, "%s%s", !first ? "|" : "",
1978                                     strsig2(i));
1979                                 first = 0;
1980                         }
1981                 }
1982                 if (!first)
1983                         fputc(' ', fp);
1984                 fputc('}', fp);
1985                 break;
1986         }
1987         case Sigprocmask:
1988                 print_integer_arg(sysdecode_sigprocmask_how, fp,
1989                     args[sc->offset]);
1990                 break;
1991         case Fcntlflag:
1992                 /* XXX: Output depends on the value of the previous argument. */
1993                 if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
1994                         sysdecode_fcntl_arg(fp, args[sc->offset - 1],
1995                             args[sc->offset], 16);
1996                 break;
1997         case Open:
1998                 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
1999                 break;
2000         case Fcntl:
2001                 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
2002                 break;
2003         case Mprot:
2004                 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
2005                 break;
2006         case Mmapflags:
2007                 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
2008                 break;
2009         case Whence:
2010                 print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
2011                 break;
2012         case Sockdomain:
2013                 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
2014                 break;
2015         case Socktype:
2016                 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
2017                 break;
2018         case Shutdown:
2019                 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
2020                 break;
2021         case Resource:
2022                 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
2023                 break;
2024         case RusageWho:
2025                 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]);
2026                 break;
2027         case Pathconf:
2028                 print_integer_arg(sysdecode_pathconf_name, fp, args[sc->offset]);
2029                 break;
2030         case Rforkflags:
2031                 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
2032                 break;
2033         case Sockaddr: {
2034                 socklen_t len;
2035
2036                 if (args[sc->offset] == 0) {
2037                         fputs("NULL", fp);
2038                         break;
2039                 }
2040
2041                 /*
2042                  * Extract the address length from the next argument.  If
2043                  * this is an output sockaddr (OUT is set), then the
2044                  * next argument is a pointer to a socklen_t.  Otherwise
2045                  * the next argument contains a socklen_t by value.
2046                  */
2047                 if (sc->type & OUT) {
2048                         if (get_struct(pid, args[sc->offset + 1], &len,
2049                             sizeof(len)) == -1) {
2050                                 print_pointer(fp, args[sc->offset]);
2051                                 break;
2052                         }
2053                 } else
2054                         len = args[sc->offset + 1];
2055
2056                 print_sockaddr(fp, trussinfo, args[sc->offset], len);
2057                 break;
2058         }
2059         case Sigaction: {
2060                 struct sigaction sa;
2061
2062                 if (get_struct(pid, args[sc->offset], &sa, sizeof(sa)) != -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                         print_pointer(fp, 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, 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                         print_pointer(fp, 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, 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                         print_pointer(fp, args[sc->offset]);
2153                 }
2154                 free(ke11);
2155                 break;
2156         }
2157         case Stat: {
2158                 struct stat st;
2159
2160                 if (get_struct(pid, 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                         print_pointer(fp, args[sc->offset]);
2171                 }
2172                 break;
2173         }
2174         case Stat11: {
2175                 struct freebsd11_stat st;
2176
2177                 if (get_struct(pid, 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                         print_pointer(fp, args[sc->offset]);
2188                 }
2189                 break;
2190         }
2191         case StatFs: {
2192                 unsigned int i;
2193                 struct statfs buf;
2194
2195                 if (get_struct(pid, 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                         print_pointer(fp, args[sc->offset]);
2212                 break;
2213         }
2214
2215         case Rusage: {
2216                 struct rusage ru;
2217
2218                 if (get_struct(pid, 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                         print_pointer(fp, args[sc->offset]);
2227                 break;
2228         }
2229         case Rlimit: {
2230                 struct rlimit rl;
2231
2232                 if (get_struct(pid, 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                         print_pointer(fp, args[sc->offset]);
2238                 break;
2239         }
2240         case ExitStatus: {
2241                 int status;
2242
2243                 if (get_struct(pid, 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                         print_pointer(fp, 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, 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, args[sc->offset],
2366                     (void *)utrace_addr, len) != -1)
2367                         print_utrace(fp, utrace_addr, len);
2368                 else
2369                         print_pointer(fp, 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, 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                         print_pointer(fp, 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, args[sc->offset], &rights,
2403                             sizeof(rights)) == -1) {
2404                                 print_pointer(fp, 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, args[sc->offset], &rights,
2487                     sizeof(rights)) != -1) {
2488                         fputs("{ ", fp);
2489                         sysdecode_cap_rights(fp, &rights);
2490                         fputs(" }", fp);
2491                 } else
2492                         print_pointer(fp, 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, args[sc->offset], &sp, sizeof(sp)) != -1)
2541                         fprintf(fp, "{ %d }", sp.sched_priority);
2542                 else
2543                         print_pointer(fp, args[sc->offset]);
2544                 break;
2545         }
2546         case PSig: {
2547                 int sig;
2548
2549                 if (get_struct(pid, args[sc->offset], &sig, sizeof(sig)) == 0)
2550                         fprintf(fp, "{ %s }", strsig2(sig));
2551                 else
2552                         print_pointer(fp, args[sc->offset]);
2553                 break;
2554         }
2555         case Siginfo: {
2556                 siginfo_t si;
2557
2558                 if (get_struct(pid, args[sc->offset], &si, sizeof(si)) != -1) {
2559                         fprintf(fp, "{ signo=%s", strsig2(si.si_signo));
2560                         decode_siginfo(fp, &si);
2561                         fprintf(fp, " }");
2562                 } else
2563                         print_pointer(fp, args[sc->offset]);
2564                 break;
2565         }
2566         case Iovec:
2567                 /*
2568                  * Print argument as an array of struct iovec, where the next
2569                  * syscall argument is the number of elements of the array.
2570                  */
2571
2572                 print_iovec(fp, trussinfo, args[sc->offset],
2573                     (int)args[sc->offset + 1]);
2574                 break;
2575         case Sctpsndrcvinfo: {
2576                 struct sctp_sndrcvinfo info;
2577
2578                 if (get_struct(pid, args[sc->offset],
2579                     &info, sizeof(struct sctp_sndrcvinfo)) == -1) {
2580                         print_pointer(fp, args[sc->offset]);
2581                         break;
2582                 }
2583                 print_sctp_sndrcvinfo(fp, sc->type & OUT, &info);
2584                 break;
2585         }
2586         case Msghdr: {
2587                 struct msghdr msghdr;
2588
2589                 if (get_struct(pid, args[sc->offset],
2590                     &msghdr, sizeof(struct msghdr)) == -1) {
2591                         print_pointer(fp, args[sc->offset]);
2592                         break;
2593                 }
2594                 fputs("{", fp);
2595                 print_sockaddr(fp, trussinfo, (uintptr_t)msghdr.msg_name, msghdr.msg_namelen);
2596                 fprintf(fp, ",%d,", msghdr.msg_namelen);
2597                 print_iovec(fp, trussinfo, (uintptr_t)msghdr.msg_iov, msghdr.msg_iovlen);
2598                 fprintf(fp, ",%d,", msghdr.msg_iovlen);
2599                 print_cmsgs(fp, pid, sc->type & OUT, &msghdr);
2600                 fprintf(fp, ",%u,", msghdr.msg_controllen);
2601                 print_mask_arg(sysdecode_msg_flags, fp, msghdr.msg_flags);
2602                 fputs("}", fp);
2603                 break;
2604         }
2605
2606         case CloudABIAdvice:
2607                 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
2608                 break;
2609         case CloudABIClockID:
2610                 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2611                 break;
2612         case CloudABIFDSFlags:
2613                 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2614                 break;
2615         case CloudABIFDStat: {
2616                 cloudabi_fdstat_t fds;
2617                 if (get_struct(pid, args[sc->offset], &fds, sizeof(fds))
2618                     != -1) {
2619                         fprintf(fp, "{ %s, ",
2620                             xlookup(cloudabi_filetype, fds.fs_filetype));
2621                         fprintf(fp, "%s, ... }",
2622                             xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2623                 } else
2624                         print_pointer(fp, args[sc->offset]);
2625                 break;
2626         }
2627         case CloudABIFileStat: {
2628                 cloudabi_filestat_t fsb;
2629                 if (get_struct(pid, args[sc->offset], &fsb, sizeof(fsb))
2630                     != -1)
2631                         fprintf(fp, "{ %s, %ju }",
2632                             xlookup(cloudabi_filetype, fsb.st_filetype),
2633                             (uintmax_t)fsb.st_size);
2634                 else
2635                         print_pointer(fp, args[sc->offset]);
2636                 break;
2637         }
2638         case CloudABIFileType:
2639                 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2640                 break;
2641         case CloudABIFSFlags:
2642                 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2643                 break;
2644         case CloudABILookup:
2645                 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2646                         fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2647                             (int)args[sc->offset]);
2648                 else
2649                         fprintf(fp, "%d", (int)args[sc->offset]);
2650                 break;
2651         case CloudABIMFlags:
2652                 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2653                 break;
2654         case CloudABIMProt:
2655                 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2656                 break;
2657         case CloudABIMSFlags:
2658                 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2659                 break;
2660         case CloudABIOFlags:
2661                 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2662                 break;
2663         case CloudABISDFlags:
2664                 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2665                 break;
2666         case CloudABISignal:
2667                 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2668                 break;
2669         case CloudABITimestamp:
2670                 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2671                     args[sc->offset] % 1000000000);
2672                 break;
2673         case CloudABIULFlags:
2674                 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2675                 break;
2676         case CloudABIWhence:
2677                 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2678                 break;
2679
2680         default:
2681                 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2682         }
2683         fclose(fp);
2684         return (tmp);
2685 }
2686
2687 /*
2688  * Print (to outfile) the system call and its arguments.
2689  */
2690 void
2691 print_syscall(struct trussinfo *trussinfo)
2692 {
2693         struct threadinfo *t;
2694         const char *name;
2695         char **s_args;
2696         int i, len, nargs;
2697
2698         t = trussinfo->curthread;
2699
2700         name = t->cs.sc->name;
2701         nargs = t->cs.nargs;
2702         s_args = t->cs.s_args;
2703
2704         len = print_line_prefix(trussinfo);
2705         len += fprintf(trussinfo->outfile, "%s(", name);
2706
2707         for (i = 0; i < nargs; i++) {
2708                 if (s_args[i] != NULL)
2709                         len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2710                 else
2711                         len += fprintf(trussinfo->outfile,
2712                             "<missing argument>");
2713                 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2714                     "," : "");
2715         }
2716         len += fprintf(trussinfo->outfile, ")");
2717         for (i = 0; i < 6 - (len / 8); i++)
2718                 fprintf(trussinfo->outfile, "\t");
2719 }
2720
2721 void
2722 print_syscall_ret(struct trussinfo *trussinfo, int error, register_t *retval)
2723 {
2724         struct timespec timediff;
2725         struct threadinfo *t;
2726         struct syscall *sc;
2727
2728         t = trussinfo->curthread;
2729         sc = t->cs.sc;
2730         if (trussinfo->flags & COUNTONLY) {
2731                 timespecsub(&t->after, &t->before, &timediff);
2732                 timespecadd(&sc->time, &timediff, &sc->time);
2733                 sc->ncalls++;
2734                 if (error != 0)
2735                         sc->nerror++;
2736                 return;
2737         }
2738
2739         print_syscall(trussinfo);
2740         fflush(trussinfo->outfile);
2741
2742         if (retval == NULL) {
2743                 /*
2744                  * This system call resulted in the current thread's exit,
2745                  * so there is no return value or error to display.
2746                  */
2747                 fprintf(trussinfo->outfile, "\n");
2748                 return;
2749         }
2750
2751         if (error == ERESTART)
2752                 fprintf(trussinfo->outfile, " ERESTART\n");
2753         else if (error == EJUSTRETURN)
2754                 fprintf(trussinfo->outfile, " EJUSTRETURN\n");
2755         else if (error != 0) {
2756                 fprintf(trussinfo->outfile, " ERR#%d '%s'\n",
2757                     sysdecode_freebsd_to_abi_errno(t->proc->abi->abi, error),
2758                     strerror(error));
2759         }
2760 #ifndef __LP64__
2761         else if (sc->ret_type == 2) {
2762                 off_t off;
2763
2764 #if _BYTE_ORDER == _LITTLE_ENDIAN
2765                 off = (off_t)retval[1] << 32 | retval[0];
2766 #else
2767                 off = (off_t)retval[0] << 32 | retval[1];
2768 #endif
2769                 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2770                     (intmax_t)off);
2771         }
2772 #endif
2773         else
2774                 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n",
2775                     (intmax_t)retval[0], (intmax_t)retval[0]);
2776 }
2777
2778 void
2779 print_summary(struct trussinfo *trussinfo)
2780 {
2781         struct timespec total = {0, 0};
2782         struct syscall *sc;
2783         int ncall, nerror;
2784
2785         fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2786             "syscall", "seconds", "calls", "errors");
2787         ncall = nerror = 0;
2788         STAILQ_FOREACH(sc, &syscalls, entries)
2789                 if (sc->ncalls) {
2790                         fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2791                             sc->name, (intmax_t)sc->time.tv_sec,
2792                             sc->time.tv_nsec, sc->ncalls, sc->nerror);
2793                         timespecadd(&total, &sc->time, &total);
2794                         ncall += sc->ncalls;
2795                         nerror += sc->nerror;
2796                 }
2797         fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2798             "", "-------------", "-------", "-------");
2799         fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2800             "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);
2801 }