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