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