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