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