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