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