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