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