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