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