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