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