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