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