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