]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/truss/syscalls.c
MFV: r362286
[FreeBSD/FreeBSD.git] / usr.bin / truss / syscalls.c
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright 1997 Sean Eric Fagan
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Sean Eric Fagan
17  * 4. Neither the name of the author may be used to endorse or promote
18  *    products derived from this software without specific prior written
19  *    permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 /*
38  * This file has routines used to print out system calls and their
39  * arguments.
40  */
41
42 #include <sys/capsicum.h>
43 #include <sys/types.h>
44 #define _WANT_FREEBSD11_KEVENT
45 #include <sys/event.h>
46 #include <sys/ioccom.h>
47 #include <sys/mman.h>
48 #include <sys/mount.h>
49 #include <sys/ptrace.h>
50 #include <sys/resource.h>
51 #include <sys/socket.h>
52 #define _WANT_FREEBSD11_STAT
53 #include <sys/stat.h>
54 #include <sys/sysctl.h>
55 #include <sys/time.h>
56 #include <sys/un.h>
57 #include <sys/wait.h>
58 #include <netinet/in.h>
59 #include <netinet/sctp.h>
60 #include <arpa/inet.h>
61
62 #include <assert.h>
63 #include <ctype.h>
64 #include <err.h>
65 #define _WANT_KERNEL_ERRNO
66 #include <errno.h>
67 #include <fcntl.h>
68 #include <poll.h>
69 #include <sched.h>
70 #include <signal.h>
71 #include <stdbool.h>
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75 #include <sysdecode.h>
76 #include <unistd.h>
77 #include <vis.h>
78
79 #include <contrib/cloudabi/cloudabi_types_common.h>
80
81 #include "truss.h"
82 #include "extern.h"
83 #include "syscall.h"
84
85 /*
86  * This should probably be in its own file, sorted alphabetically.
87  */
88 static struct syscall decoded_syscalls[] = {
89         /* Native ABI */
90         { .name = "__acl_aclcheck_fd", .ret_type = 1, .nargs = 3,
91           .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
92         { .name = "__acl_aclcheck_file", .ret_type = 1, .nargs = 3,
93           .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
94         { .name = "__acl_aclcheck_link", .ret_type = 1, .nargs = 3,
95           .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
96         { .name = "__acl_delete_fd", .ret_type = 1, .nargs = 2,
97           .args = { { Int, 0 }, { Acltype, 1 } } },
98         { .name = "__acl_delete_file", .ret_type = 1, .nargs = 2,
99           .args = { { Name, 0 }, { Acltype, 1 } } },
100         { .name = "__acl_delete_link", .ret_type = 1, .nargs = 2,
101           .args = { { Name, 0 }, { Acltype, 1 } } },
102         { .name = "__acl_get_fd", .ret_type = 1, .nargs = 3,
103           .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
104         { .name = "__acl_get_file", .ret_type = 1, .nargs = 3,
105           .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
106         { .name = "__acl_get_link", .ret_type = 1, .nargs = 3,
107           .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
108         { .name = "__acl_set_fd", .ret_type = 1, .nargs = 3,
109           .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
110         { .name = "__acl_set_file", .ret_type = 1, .nargs = 3,
111           .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
112         { .name = "__acl_set_link", .ret_type = 1, .nargs = 3,
113           .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
114         { .name = "__cap_rights_get", .ret_type = 1, .nargs = 3,
115           .args = { { Int, 0 }, { Int, 1 }, { CapRights | OUT, 2 } } },
116         { .name = "__getcwd", .ret_type = 1, .nargs = 2,
117           .args = { { Name | OUT, 0 }, { Int, 1 } } },
118         { .name = "__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 };
686 static STAILQ_HEAD(, syscall) syscalls;
687
688 /* Xlat idea taken from strace */
689 struct xlat {
690         int val;
691         const char *str;
692 };
693
694 #define X(a)    { a, #a },
695 #define XEND    { 0, NULL }
696
697 static 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
703 static 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
708 static 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
720 static 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
726 static 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
732 static 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
738 static struct xlat cloudabi_fdsflags[] = {
739         X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
740         XEND
741 };
742
743 static 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
752 static 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
758 static struct xlat cloudabi_mflags[] = {
759         X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
760         XEND
761 };
762
763 static struct xlat cloudabi_mprot[] = {
764         X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
765         XEND
766 };
767
768 static struct xlat cloudabi_msflags[] = {
769         X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
770         XEND
771 };
772
773 static struct xlat cloudabi_oflags[] = {
774         X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
775         XEND
776 };
777
778 static struct xlat cloudabi_sdflags[] = {
779         X(SHUT_RD) X(SHUT_WR)
780         XEND
781 };
782
783 static 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
792 static struct xlat cloudabi_ulflags[] = {
793         X(UNLINK_REMOVEDIR)
794         XEND
795 };
796
797 static 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  */
809 static const char *
810 lookup(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
834 static const char *
835 xlookup(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  */
846 static char *
847 xlookup_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
879 static void
880 print_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
891 static void
892 print_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
902 static void
903 print_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  */
922 static void
923 quad_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
961 void
962 init_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
975 static struct syscall *
976 find_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
989 static void
990 add_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  */
1009 struct syscall *
1010 get_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  */
1061 static int
1062 get_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  */
1082 static char *
1083 get_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
1132 static const char *
1133 strsig2(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
1146 static void
1147 print_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
1175 static void
1176 print_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
1193 static void
1194 print_pointer(FILE *fp, uintptr_t arg)
1195 {
1196
1197         fprintf(fp, "%p", (void *)arg);
1198 }
1199
1200 static void
1201 print_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
1270 static void
1271 print_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
1327 static void
1328 print_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
1340 static void
1341 print_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
1349 static void
1350 print_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
1370 static void
1371 print_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
1381 static void
1382 print_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
1395 static void
1396 print_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
1406 static void
1407 print_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
1414 static void
1415 print_sctp_authinfo(FILE *fp, struct sctp_authinfo *info)
1416 {
1417         fprintf(fp, "{num=%u}", info->auth_keynumber);
1418 }
1419
1420 static void
1421 print_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
1433 static void
1434 print_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
1446 static void
1447 print_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
1524 static void
1525 print_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
1579 static void
1580 print_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  */
1594 char *
1595 print_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  */
2701 void
2702 print_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
2732 void
2733 print_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
2789 void
2790 print_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 }