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