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