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