2 * Copyright 1997 Sean Eric Fagan
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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
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
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
36 * This file has routines used to print out system calls and their
40 #include <sys/capsicum.h>
41 #include <sys/types.h>
42 #include <sys/event.h>
43 #include <sys/ioccom.h>
44 #include <sys/mount.h>
45 #include <sys/ptrace.h>
46 #include <sys/resource.h>
47 #include <sys/socket.h>
48 #define _WANT_FREEBSD11_STAT
52 #include <machine/sysarch.h>
53 #include <netinet/in.h>
54 #include <arpa/inet.h>
67 #include <sysdecode.h>
71 #include <contrib/cloudabi/cloudabi_types_common.h>
78 * This should probably be in its own file, sorted alphabetically.
80 static struct syscall decoded_syscalls[] = {
82 { .name = "__acl_aclcheck_fd", .ret_type = 1, .nargs = 3,
83 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
84 { .name = "__acl_aclcheck_file", .ret_type = 1, .nargs = 3,
85 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
86 { .name = "__acl_aclcheck_link", .ret_type = 1, .nargs = 3,
87 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
88 { .name = "__acl_delete_fd", .ret_type = 1, .nargs = 2,
89 .args = { { Int, 0 }, { Acltype, 1 } } },
90 { .name = "__acl_delete_file", .ret_type = 1, .nargs = 2,
91 .args = { { Name, 0 }, { Acltype, 1 } } },
92 { .name = "__acl_delete_link", .ret_type = 1, .nargs = 2,
93 .args = { { Name, 0 }, { Acltype, 1 } } },
94 { .name = "__acl_get_fd", .ret_type = 1, .nargs = 3,
95 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
96 { .name = "__acl_get_file", .ret_type = 1, .nargs = 3,
97 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
98 { .name = "__acl_get_link", .ret_type = 1, .nargs = 3,
99 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
100 { .name = "__acl_set_fd", .ret_type = 1, .nargs = 3,
101 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
102 { .name = "__acl_set_file", .ret_type = 1, .nargs = 3,
103 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
104 { .name = "__acl_set_link", .ret_type = 1, .nargs = 3,
105 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
106 { .name = "__cap_rights_get", .ret_type = 1, .nargs = 3,
107 .args = { { Int, 0 }, { Int, 1 }, { CapRights | OUT, 2 } } },
108 { .name = "__getcwd", .ret_type = 1, .nargs = 2,
109 .args = { { Name | OUT, 0 }, { Int, 1 } } },
110 { .name = "_umtx_op", .ret_type = 1, .nargs = 5,
111 .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
113 { .name = "accept", .ret_type = 1, .nargs = 3,
114 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
115 { .name = "access", .ret_type = 1, .nargs = 2,
116 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
117 { .name = "bind", .ret_type = 1, .nargs = 3,
118 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
119 { .name = "bindat", .ret_type = 1, .nargs = 4,
120 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
122 { .name = "break", .ret_type = 1, .nargs = 1,
123 .args = { { Ptr, 0 } } },
124 { .name = "cap_fcntls_get", .ret_type = 1, .nargs = 2,
125 .args = { { Int, 0 }, { CapFcntlRights | OUT, 1 } } },
126 { .name = "cap_fcntls_limit", .ret_type = 1, .nargs = 2,
127 .args = { { Int, 0 }, { CapFcntlRights, 1 } } },
128 { .name = "cap_getmode", .ret_type = 1, .nargs = 1,
129 .args = { { PUInt | OUT, 0 } } },
130 { .name = "cap_rights_limit", .ret_type = 1, .nargs = 2,
131 .args = { { Int, 0 }, { CapRights, 1 } } },
132 { .name = "chdir", .ret_type = 1, .nargs = 1,
133 .args = { { Name, 0 } } },
134 { .name = "chflags", .ret_type = 1, .nargs = 2,
135 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
136 { .name = "chflagsat", .ret_type = 1, .nargs = 4,
137 .args = { { Atfd, 0 }, { Name | IN, 1 }, { FileFlags, 2 },
139 { .name = "chmod", .ret_type = 1, .nargs = 2,
140 .args = { { Name, 0 }, { Octal, 1 } } },
141 { .name = "chown", .ret_type = 1, .nargs = 3,
142 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
143 { .name = "chroot", .ret_type = 1, .nargs = 1,
144 .args = { { Name, 0 } } },
145 { .name = "clock_gettime", .ret_type = 1, .nargs = 2,
146 .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
147 { .name = "close", .ret_type = 1, .nargs = 1,
148 .args = { { Int, 0 } } },
149 { .name = "connect", .ret_type = 1, .nargs = 3,
150 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
151 { .name = "connectat", .ret_type = 1, .nargs = 4,
152 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
154 { .name = "dup", .ret_type = 1, .nargs = 1,
155 .args = { { Int, 0 } } },
156 { .name = "dup2", .ret_type = 1, .nargs = 2,
157 .args = { { Int, 0 }, { Int, 1 } } },
158 { .name = "eaccess", .ret_type = 1, .nargs = 2,
159 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
160 { .name = "execve", .ret_type = 1, .nargs = 3,
161 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
162 { ExecEnv | IN, 2 } } },
163 { .name = "exit", .ret_type = 0, .nargs = 1,
164 .args = { { Hex, 0 } } },
165 { .name = "extattr_delete_fd", .ret_type = 1, .nargs = 3,
166 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
167 { .name = "extattr_delete_file", .ret_type = 1, .nargs = 3,
168 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
169 { .name = "extattr_delete_link", .ret_type = 1, .nargs = 3,
170 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
171 { .name = "extattr_get_fd", .ret_type = 1, .nargs = 5,
172 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
173 { BinString | OUT, 3 }, { Sizet, 4 } } },
174 { .name = "extattr_get_file", .ret_type = 1, .nargs = 5,
175 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
176 { BinString | OUT, 3 }, { Sizet, 4 } } },
177 { .name = "extattr_get_link", .ret_type = 1, .nargs = 5,
178 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
179 { BinString | OUT, 3 }, { Sizet, 4 } } },
180 { .name = "extattr_list_fd", .ret_type = 1, .nargs = 4,
181 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
183 { .name = "extattr_list_file", .ret_type = 1, .nargs = 4,
184 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
186 { .name = "extattr_list_link", .ret_type = 1, .nargs = 4,
187 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
189 { .name = "extattr_set_fd", .ret_type = 1, .nargs = 5,
190 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
191 { BinString | IN, 3 }, { Sizet, 4 } } },
192 { .name = "extattr_set_file", .ret_type = 1, .nargs = 5,
193 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
194 { BinString | IN, 3 }, { Sizet, 4 } } },
195 { .name = "extattr_set_link", .ret_type = 1, .nargs = 5,
196 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
197 { BinString | IN, 3 }, { Sizet, 4 } } },
198 { .name = "extattrctl", .ret_type = 1, .nargs = 5,
199 .args = { { Name, 0 }, { Hex, 1 }, { Name, 2 },
200 { Extattrnamespace, 3 }, { Name, 4 } } },
201 { .name = "faccessat", .ret_type = 1, .nargs = 4,
202 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
204 { .name = "fchflags", .ret_type = 1, .nargs = 2,
205 .args = { { Int, 0 }, { FileFlags, 1 } } },
206 { .name = "fchmod", .ret_type = 1, .nargs = 2,
207 .args = { { Int, 0 }, { Octal, 1 } } },
208 { .name = "fchmodat", .ret_type = 1, .nargs = 4,
209 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
210 { .name = "fchown", .ret_type = 1, .nargs = 3,
211 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
212 { .name = "fchownat", .ret_type = 1, .nargs = 5,
213 .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
215 { .name = "fcntl", .ret_type = 1, .nargs = 3,
216 .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
217 { .name = "flock", .ret_type = 1, .nargs = 2,
218 .args = { { Int, 0 }, { Flockop, 1 } } },
219 { .name = "compat11.fstat", .ret_type = 1, .nargs = 2,
220 .args = { { Int, 0 }, { Stat11 | OUT, 1 } } },
221 { .name = "compat11.lstat", .ret_type = 1, .nargs = 2,
222 .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } },
223 { .name = "compat11.stat", .ret_type = 1, .nargs = 2,
224 .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } },
225 { .name = "compat11.stat", .ret_type = 1, .nargs = 2,
226 .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } },
227 { .name = "fstat", .ret_type = 1, .nargs = 2,
228 .args = { { Int, 0 }, { Stat | OUT, 1 } } },
229 { .name = "fstatat", .ret_type = 1, .nargs = 4,
230 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
232 { .name = "fstatfs", .ret_type = 1, .nargs = 2,
233 .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
234 { .name = "ftruncate", .ret_type = 1, .nargs = 2,
235 .args = { { Int | IN, 0 }, { QuadHex | IN, 1 } } },
236 { .name = "futimens", .ret_type = 1, .nargs = 2,
237 .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
238 { .name = "futimes", .ret_type = 1, .nargs = 2,
239 .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
240 { .name = "futimesat", .ret_type = 1, .nargs = 3,
241 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
242 { .name = "getdirentries", .ret_type = 1, .nargs = 4,
243 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
244 { PQuadHex | OUT, 3 } } },
245 { .name = "getfsstat", .ret_type = 1, .nargs = 3,
246 .args = { { Ptr, 0 }, { Long, 1 }, { Getfsstatmode, 2 } } },
247 { .name = "getitimer", .ret_type = 1, .nargs = 2,
248 .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
249 { .name = "getpeername", .ret_type = 1, .nargs = 3,
250 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
251 { .name = "getpgid", .ret_type = 1, .nargs = 1,
252 .args = { { Int, 0 } } },
253 { .name = "getpriority", .ret_type = 1, .nargs = 2,
254 .args = { { Priowhich, 0 }, { Int, 1 } } },
255 { .name = "getrlimit", .ret_type = 1, .nargs = 2,
256 .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
257 { .name = "getrusage", .ret_type = 1, .nargs = 2,
258 .args = { { RusageWho, 0 }, { Rusage | OUT, 1 } } },
259 { .name = "getsid", .ret_type = 1, .nargs = 1,
260 .args = { { Int, 0 } } },
261 { .name = "getsockname", .ret_type = 1, .nargs = 3,
262 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
263 { .name = "getsockopt", .ret_type = 1, .nargs = 5,
264 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
265 { Ptr | OUT, 3 }, { Ptr | OUT, 4 } } },
266 { .name = "gettimeofday", .ret_type = 1, .nargs = 2,
267 .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
268 { .name = "ioctl", .ret_type = 1, .nargs = 3,
269 .args = { { Int, 0 }, { Ioctl, 1 }, { Ptr, 2 } } },
270 { .name = "kevent", .ret_type = 1, .nargs = 6,
271 .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
272 { Int, 4 }, { Timespec, 5 } } },
273 { .name = "kill", .ret_type = 1, .nargs = 2,
274 .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
275 { .name = "kldfind", .ret_type = 1, .nargs = 1,
276 .args = { { Name | IN, 0 } } },
277 { .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
278 .args = { { Int, 0 } } },
279 { .name = "kldload", .ret_type = 1, .nargs = 1,
280 .args = { { Name | IN, 0 } } },
281 { .name = "kldnext", .ret_type = 1, .nargs = 1,
282 .args = { { Int, 0 } } },
283 { .name = "kldstat", .ret_type = 1, .nargs = 2,
284 .args = { { Int, 0 }, { Ptr, 1 } } },
285 { .name = "kldsym", .ret_type = 1, .nargs = 3,
286 .args = { { Int, 0 }, { Kldsymcmd, 1 }, { Ptr, 2 } } },
287 { .name = "kldunload", .ret_type = 1, .nargs = 1,
288 .args = { { Int, 0 } } },
289 { .name = "kldunloadf", .ret_type = 1, .nargs = 2,
290 .args = { { Int, 0 }, { Kldunloadflags, 1 } } },
291 { .name = "kse_release", .ret_type = 0, .nargs = 1,
292 .args = { { Timespec, 0 } } },
293 { .name = "lchflags", .ret_type = 1, .nargs = 2,
294 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
295 { .name = "lchmod", .ret_type = 1, .nargs = 2,
296 .args = { { Name, 0 }, { Octal, 1 } } },
297 { .name = "lchown", .ret_type = 1, .nargs = 3,
298 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
299 { .name = "link", .ret_type = 1, .nargs = 2,
300 .args = { { Name, 0 }, { Name, 1 } } },
301 { .name = "linkat", .ret_type = 1, .nargs = 5,
302 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
304 { .name = "listen", .ret_type = 1, .nargs = 2,
305 .args = { { Int, 0 }, { Int, 1 } } },
306 { .name = "lseek", .ret_type = 2, .nargs = 3,
307 .args = { { Int, 0 }, { QuadHex, 1 }, { Whence, 2 } } },
308 { .name = "lstat", .ret_type = 1, .nargs = 2,
309 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
310 { .name = "lutimes", .ret_type = 1, .nargs = 2,
311 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
312 { .name = "madvise", .ret_type = 1, .nargs = 3,
313 .args = { { Ptr, 0 }, { Sizet, 1 }, { Madvice, 2 } } },
314 { .name = "minherit", .ret_type = 1, .nargs = 3,
315 .args = { { Ptr, 0 }, { Sizet, 1 }, { Minherit, 2 } } },
316 { .name = "mkdir", .ret_type = 1, .nargs = 2,
317 .args = { { Name, 0 }, { Octal, 1 } } },
318 { .name = "mkdirat", .ret_type = 1, .nargs = 3,
319 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
320 { .name = "mkfifo", .ret_type = 1, .nargs = 2,
321 .args = { { Name, 0 }, { Octal, 1 } } },
322 { .name = "mkfifoat", .ret_type = 1, .nargs = 3,
323 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
324 { .name = "mknod", .ret_type = 1, .nargs = 3,
325 .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
326 { .name = "mknodat", .ret_type = 1, .nargs = 4,
327 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
328 { .name = "mlock", .ret_type = 1, .nargs = 2,
329 .args = { { Ptr, 0 }, { Sizet, 1 } } },
330 { .name = "mlockall", .ret_type = 1, .nargs = 1,
331 .args = { { Mlockall, 0 } } },
332 { .name = "mmap", .ret_type = 1, .nargs = 6,
333 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
334 { Int, 4 }, { QuadHex, 5 } } },
335 { .name = "modfind", .ret_type = 1, .nargs = 1,
336 .args = { { Name | IN, 0 } } },
337 { .name = "mount", .ret_type = 1, .nargs = 4,
338 .args = { { Name, 0 }, { Name, 1 }, { Mountflags, 2 }, { Ptr, 3 } } },
339 { .name = "mprotect", .ret_type = 1, .nargs = 3,
340 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 } } },
341 { .name = "msync", .ret_type = 1, .nargs = 3,
342 .args = { { Ptr, 0 }, { Sizet, 1 }, { Msync, 2 } } },
343 { .name = "munlock", .ret_type = 1, .nargs = 2,
344 .args = { { Ptr, 0 }, { Sizet, 1 } } },
345 { .name = "munmap", .ret_type = 1, .nargs = 2,
346 .args = { { Ptr, 0 }, { Sizet, 1 } } },
347 { .name = "nanosleep", .ret_type = 1, .nargs = 1,
348 .args = { { Timespec, 0 } } },
349 { .name = "nmount", .ret_type = 1, .nargs = 3,
350 .args = { { Ptr, 0 }, { UInt, 1 }, { Mountflags, 2 } } },
351 { .name = "open", .ret_type = 1, .nargs = 3,
352 .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
353 { .name = "openat", .ret_type = 1, .nargs = 4,
354 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
356 { .name = "pathconf", .ret_type = 1, .nargs = 2,
357 .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
358 { .name = "pipe", .ret_type = 1, .nargs = 1,
359 .args = { { PipeFds | OUT, 0 } } },
360 { .name = "pipe2", .ret_type = 1, .nargs = 2,
361 .args = { { Ptr, 0 }, { Pipe2, 1 } } },
362 { .name = "poll", .ret_type = 1, .nargs = 3,
363 .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
364 { .name = "posix_fadvise", .ret_type = 1, .nargs = 4,
365 .args = { { Int, 0 }, { QuadHex, 1 }, { QuadHex, 2 },
367 { .name = "posix_openpt", .ret_type = 1, .nargs = 1,
368 .args = { { Open, 0 } } },
369 { .name = "pread", .ret_type = 1, .nargs = 4,
370 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
372 { .name = "procctl", .ret_type = 1, .nargs = 4,
373 .args = { { Idtype, 0 }, { Quad, 1 }, { Procctl, 2 }, { Ptr, 3 } } },
374 { .name = "ptrace", .ret_type = 1, .nargs = 4,
375 .args = { { Ptraceop, 0 }, { Int, 1 }, { Ptr, 2 }, { Int, 3 } } },
376 { .name = "pwrite", .ret_type = 1, .nargs = 4,
377 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
379 { .name = "quotactl", .ret_type = 1, .nargs = 4,
380 .args = { { Name, 0 }, { Quotactlcmd, 1 }, { Int, 2 }, { Ptr, 3 } } },
381 { .name = "read", .ret_type = 1, .nargs = 3,
382 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 } } },
383 { .name = "readlink", .ret_type = 1, .nargs = 3,
384 .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Sizet, 2 } } },
385 { .name = "readlinkat", .ret_type = 1, .nargs = 4,
386 .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
388 { .name = "reboot", .ret_type = 1, .nargs = 1,
389 .args = { { Reboothowto, 0 } } },
390 { .name = "recvfrom", .ret_type = 1, .nargs = 6,
391 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
392 { Msgflags, 3 }, { Sockaddr | OUT, 4 },
393 { Ptr | OUT, 5 } } },
394 { .name = "recvmsg", .ret_type = 1, .nargs = 3,
395 .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
396 { .name = "rename", .ret_type = 1, .nargs = 2,
397 .args = { { Name, 0 }, { Name, 1 } } },
398 { .name = "renameat", .ret_type = 1, .nargs = 4,
399 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
400 { .name = "rfork", .ret_type = 1, .nargs = 1,
401 .args = { { Rforkflags, 0 } } },
402 { .name = "rmdir", .ret_type = 1, .nargs = 1,
403 .args = { { Name, 0 } } },
404 { .name = "rtprio", .ret_type = 1, .nargs = 3,
405 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
406 { .name = "rtprio_thread", .ret_type = 1, .nargs = 3,
407 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
408 { .name = "sched_get_priority_max", .ret_type = 1, .nargs = 1,
409 .args = { { Schedpolicy, 0 } } },
410 { .name = "sched_get_priority_min", .ret_type = 1, .nargs = 1,
411 .args = { { Schedpolicy, 0 } } },
412 { .name = "sched_getparam", .ret_type = 1, .nargs = 2,
413 .args = { { Int, 0 }, { Schedparam | OUT, 1 } } },
414 { .name = "sched_getscheduler", .ret_type = 1, .nargs = 1,
415 .args = { { Int, 0 } } },
416 { .name = "sched_rr_get_interval", .ret_type = 1, .nargs = 2,
417 .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
418 { .name = "sched_setparam", .ret_type = 1, .nargs = 2,
419 .args = { { Int, 0 }, { Schedparam, 1 } } },
420 { .name = "sched_setscheduler", .ret_type = 1, .nargs = 3,
421 .args = { { Int, 0 }, { Schedpolicy, 1 }, { Schedparam, 2 } } },
422 { .name = "sctp_generic_recvmsg", .ret_type = 1, .nargs = 7,
423 .args = { { Int, 0 }, { Ptr | IN, 1 }, { Int, 2 },
424 { Sockaddr | OUT, 3 }, { Ptr | OUT, 4 }, { Ptr | OUT, 5 },
425 { Ptr | OUT, 6 } } },
426 { .name = "sctp_generic_sendmsg", .ret_type = 1, .nargs = 7,
427 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
428 { Sockaddr | IN, 3 }, { Socklent, 4 }, { Ptr | IN, 5 },
430 { .name = "select", .ret_type = 1, .nargs = 5,
431 .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
433 { .name = "sendmsg", .ret_type = 1, .nargs = 3,
434 .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
435 { .name = "sendto", .ret_type = 1, .nargs = 6,
436 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
437 { Msgflags, 3 }, { Sockaddr | IN, 4 },
438 { Socklent | IN, 5 } } },
439 { .name = "setitimer", .ret_type = 1, .nargs = 3,
440 .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
441 { .name = "setpriority", .ret_type = 1, .nargs = 3,
442 .args = { { Priowhich, 0 }, { Int, 1 }, { Int, 2 } } },
443 { .name = "setrlimit", .ret_type = 1, .nargs = 2,
444 .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
445 { .name = "setsockopt", .ret_type = 1, .nargs = 5,
446 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
447 { Ptr | IN, 3 }, { Socklent, 4 } } },
448 { .name = "shutdown", .ret_type = 1, .nargs = 2,
449 .args = { { Int, 0 }, { Shutdown, 1 } } },
450 { .name = "sigaction", .ret_type = 1, .nargs = 3,
451 .args = { { Signal, 0 }, { Sigaction | IN, 1 },
452 { Sigaction | OUT, 2 } } },
453 { .name = "sigpending", .ret_type = 1, .nargs = 1,
454 .args = { { Sigset | OUT, 0 } } },
455 { .name = "sigprocmask", .ret_type = 1, .nargs = 3,
456 .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
457 { .name = "sigqueue", .ret_type = 1, .nargs = 3,
458 .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
459 { .name = "sigreturn", .ret_type = 1, .nargs = 1,
460 .args = { { Ptr, 0 } } },
461 { .name = "sigsuspend", .ret_type = 1, .nargs = 1,
462 .args = { { Sigset | IN, 0 } } },
463 { .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
464 .args = { { Sigset | IN, 0 }, { Ptr, 1 }, { Timespec | IN, 2 } } },
465 { .name = "sigwait", .ret_type = 1, .nargs = 2,
466 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
467 { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
468 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
469 { .name = "socket", .ret_type = 1, .nargs = 3,
470 .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Sockprotocol, 2 } } },
471 { .name = "stat", .ret_type = 1, .nargs = 2,
472 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
473 { .name = "statfs", .ret_type = 1, .nargs = 2,
474 .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } },
475 { .name = "symlink", .ret_type = 1, .nargs = 2,
476 .args = { { Name, 0 }, { Name, 1 } } },
477 { .name = "symlinkat", .ret_type = 1, .nargs = 3,
478 .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } },
479 { .name = "sysarch", .ret_type = 1, .nargs = 2,
480 .args = { { Sysarch, 0 }, { Ptr, 1 } } },
481 { .name = "thr_kill", .ret_type = 1, .nargs = 2,
482 .args = { { Long, 0 }, { Signal, 1 } } },
483 { .name = "thr_self", .ret_type = 1, .nargs = 1,
484 .args = { { Ptr, 0 } } },
485 { .name = "truncate", .ret_type = 1, .nargs = 2,
486 .args = { { Name | IN, 0 }, { QuadHex | IN, 1 } } },
489 { .name = "umount", .ret_type = 1, .nargs = 2,
490 .args = { { Name, 0 }, { Int, 2 } } },
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 },
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 }, { Ptr, 5 } } },
511 { .name = "write", .ret_type = 1, .nargs = 3,
512 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 } } },
515 { .name = "linux_access", .ret_type = 1, .nargs = 2,
516 .args = { { Name, 0 }, { Accessmode, 1 } } },
517 { .name = "linux_execve", .ret_type = 1, .nargs = 3,
518 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
519 { ExecEnv | IN, 2 } } },
520 { .name = "linux_lseek", .ret_type = 2, .nargs = 3,
521 .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
522 { .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
523 .args = { { Name | IN, 0 }, { Int, 1 } } },
524 { .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
525 .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
526 { .name = "linux_newstat", .ret_type = 1, .nargs = 2,
527 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
528 { .name = "linux_open", .ret_type = 1, .nargs = 3,
529 .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
530 { .name = "linux_readlink", .ret_type = 1, .nargs = 3,
531 .args = { { Name, 0 }, { Name | OUT, 1 }, { Sizet, 2 } } },
532 { .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
533 .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
534 { .name = "linux_stat64", .ret_type = 1, .nargs = 2,
535 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
537 /* CloudABI system calls. */
538 { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
539 .args = { { CloudABIClockID, 0 } } },
540 { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
541 .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
542 { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
543 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
544 { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
545 .args = { { Int, 0 } } },
546 { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
547 .args = { { CloudABIFileType, 0 } } },
548 { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
549 .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
550 { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
551 .args = { { Int, 0 } } },
552 { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
553 .args = { { Int, 0 } } },
554 { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
555 .args = { { Int, 0 }, { Int, 1 } } },
556 { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
557 .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
558 { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
559 .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
560 { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
561 .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
562 { ClouduABIFDSFlags, 2 } } },
563 { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
564 .args = { { Int, 0 } } },
565 { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
566 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
567 { CloudABIAdvice, 3 } } },
568 { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
569 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
570 { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
571 .args = { { Int, 0 }, { BinString | IN, 1 },
572 { CloudABIFileType, 3 } } },
573 { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
574 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
575 { Int, 3 }, { BinString | IN, 4 } } },
576 { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
577 .args = { { Int, 0 }, { BinString | IN, 1 },
578 { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
579 { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
580 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
582 { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
583 .args = { { Int, 0 }, { BinString | IN, 1 },
584 { BinString | OUT, 3 }, { Int, 4 } } },
585 { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
586 .args = { { Int, 0 }, { BinString | IN, 1 },
587 { Int, 3 }, { BinString | IN, 4 } } },
588 { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
589 .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
590 { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
591 .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
592 { CloudABIFSFlags, 2 } } },
593 { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
594 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
595 { CloudABIFileStat | OUT, 3 } } },
596 { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
597 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
598 { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
599 { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
600 .args = { { BinString | IN, 0 },
601 { Int, 2 }, { BinString | IN, 3 } } },
602 { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
603 .args = { { Int, 0 }, { BinString | IN, 1 },
604 { CloudABIULFlags, 3 } } },
605 { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
606 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
607 { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
608 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
609 { .name = "cloudabi_sys_mem_lock", .ret_type = 1, .nargs = 2,
610 .args = { { Ptr, 0 }, { Int, 1 } } },
611 { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
612 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
613 { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
614 { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
615 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
616 { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
617 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
618 { .name = "cloudabi_sys_mem_unlock", .ret_type = 1, .nargs = 2,
619 .args = { { Ptr, 0 }, { Int, 1 } } },
620 { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
621 .args = { { Ptr, 0 }, { Int, 1 } } },
622 { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
623 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
624 { IntArray, 3 }, { Int, 4 } } },
625 { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
626 .args = { { Int, 0 } } },
627 { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
628 { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
629 .args = { { CloudABISignal, 0 } } },
630 { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
631 .args = { { BinString | OUT, 0 }, { Int, 1 } } },
632 { .name = "cloudabi_sys_sock_accept", .ret_type = 1, .nargs = 2,
633 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 } } },
634 { .name = "cloudabi_sys_sock_bind", .ret_type = 1, .nargs = 3,
635 .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
636 { .name = "cloudabi_sys_sock_connect", .ret_type = 1, .nargs = 3,
637 .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
638 { .name = "cloudabi_sys_sock_listen", .ret_type = 1, .nargs = 2,
639 .args = { { Int, 0 }, { Int, 1 } } },
640 { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
641 .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
642 { .name = "cloudabi_sys_sock_stat_get", .ret_type = 1, .nargs = 3,
643 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 },
644 { CloudABISSFlags, 2 } } },
645 { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
646 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
647 { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
651 static STAILQ_HEAD(, syscall) syscalls;
653 /* Xlat idea taken from strace */
659 #define X(a) { a, #a },
660 #define XEND { 0, NULL }
662 static struct xlat kevent_filters[] = {
663 X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
664 X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
665 X(EVFILT_PROCDESC) X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER)
666 X(EVFILT_SENDFILE) XEND
669 static struct xlat kevent_flags[] = {
670 X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
671 X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH) X(EV_FORCEONESHOT)
672 X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
675 static struct xlat kevent_user_ffctrl[] = {
676 X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
680 static struct xlat kevent_rdwr_fflags[] = {
681 X(NOTE_LOWAT) X(NOTE_FILE_POLL) XEND
684 static struct xlat kevent_vnode_fflags[] = {
685 X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB)
686 X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND
689 static struct xlat kevent_proc_fflags[] = {
690 X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR)
694 static struct xlat kevent_timer_fflags[] = {
695 X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS)
699 static struct xlat poll_flags[] = {
700 X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
701 X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
702 X(POLLWRBAND) X(POLLINIGNEOF) XEND
705 static struct xlat sigaction_flags[] = {
706 X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
707 X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
710 static struct xlat pathconf_arg[] = {
711 X(_PC_LINK_MAX) X(_PC_MAX_CANON) X(_PC_MAX_INPUT)
712 X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF)
713 X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE)
714 X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO)
715 X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS)
716 X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE)
717 X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
718 X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
719 X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
720 X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND
723 static struct xlat at_flags[] = {
724 X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW)
728 static struct xlat sysarch_ops[] = {
729 #if defined(__i386__) || defined(__amd64__)
730 X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM)
731 X(I386_VM86) X(I386_GET_FSBASE) X(I386_SET_FSBASE) X(I386_GET_GSBASE)
732 X(I386_SET_GSBASE) X(I386_GET_XFPUSTATE) X(AMD64_GET_FSBASE)
733 X(AMD64_SET_FSBASE) X(AMD64_GET_GSBASE) X(AMD64_SET_GSBASE)
734 X(AMD64_GET_XFPUSTATE)
739 static struct xlat linux_socketcall_ops[] = {
740 X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
741 X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
742 X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
743 X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
744 X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
749 #define X(a) { CLOUDABI_##a, #a },
751 static struct xlat cloudabi_advice[] = {
752 X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
753 X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
757 static struct xlat cloudabi_clockid[] = {
758 X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
759 X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
763 static struct xlat cloudabi_errno[] = {
764 X(E2BIG) X(EACCES) X(EADDRINUSE) X(EADDRNOTAVAIL)
765 X(EAFNOSUPPORT) X(EAGAIN) X(EALREADY) X(EBADF) X(EBADMSG)
766 X(EBUSY) X(ECANCELED) X(ECHILD) X(ECONNABORTED) X(ECONNREFUSED)
767 X(ECONNRESET) X(EDEADLK) X(EDESTADDRREQ) X(EDOM) X(EDQUOT)
768 X(EEXIST) X(EFAULT) X(EFBIG) X(EHOSTUNREACH) X(EIDRM) X(EILSEQ)
769 X(EINPROGRESS) X(EINTR) X(EINVAL) X(EIO) X(EISCONN) X(EISDIR)
770 X(ELOOP) X(EMFILE) X(EMLINK) X(EMSGSIZE) X(EMULTIHOP)
771 X(ENAMETOOLONG) X(ENETDOWN) X(ENETRESET) X(ENETUNREACH)
772 X(ENFILE) X(ENOBUFS) X(ENODEV) X(ENOENT) X(ENOEXEC) X(ENOLCK)
773 X(ENOLINK) X(ENOMEM) X(ENOMSG) X(ENOPROTOOPT) X(ENOSPC)
774 X(ENOSYS) X(ENOTCONN) X(ENOTDIR) X(ENOTEMPTY) X(ENOTRECOVERABLE)
775 X(ENOTSOCK) X(ENOTSUP) X(ENOTTY) X(ENXIO) X(EOVERFLOW)
776 X(EOWNERDEAD) X(EPERM) X(EPIPE) X(EPROTO) X(EPROTONOSUPPORT)
777 X(EPROTOTYPE) X(ERANGE) X(EROFS) X(ESPIPE) X(ESRCH) X(ESTALE)
778 X(ETIMEDOUT) X(ETXTBSY) X(EXDEV) X(ENOTCAPABLE)
782 static struct xlat cloudabi_fdflags[] = {
783 X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
784 X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
788 static struct xlat cloudabi_fdsflags[] = {
789 X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
793 static struct xlat cloudabi_filetype[] = {
794 X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
795 X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
796 X(FILETYPE_FIFO) X(FILETYPE_POLL) X(FILETYPE_PROCESS)
797 X(FILETYPE_REGULAR_FILE) X(FILETYPE_SHARED_MEMORY)
798 X(FILETYPE_SOCKET_DGRAM) X(FILETYPE_SOCKET_SEQPACKET)
799 X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK)
803 static struct xlat cloudabi_fsflags[] = {
804 X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
805 X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
809 static struct xlat cloudabi_mflags[] = {
810 X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
814 static struct xlat cloudabi_mprot[] = {
815 X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
819 static struct xlat cloudabi_msflags[] = {
820 X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
824 static struct xlat cloudabi_oflags[] = {
825 X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
829 static struct xlat cloudabi_sa_family[] = {
830 X(AF_UNSPEC) X(AF_INET) X(AF_INET6) X(AF_UNIX)
834 static struct xlat cloudabi_sdflags[] = {
835 X(SHUT_RD) X(SHUT_WR)
839 static struct xlat cloudabi_signal[] = {
840 X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
841 X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
842 X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
843 X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
844 X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
848 static struct xlat cloudabi_ssflags[] = {
849 X(SOCKSTAT_CLEAR_ERROR)
853 static struct xlat cloudabi_ssstate[] = {
854 X(SOCKSTATE_ACCEPTCONN)
858 static struct xlat cloudabi_ulflags[] = {
863 static struct xlat cloudabi_whence[] = {
864 X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
872 * Searches an xlat array for a value, and returns it if found. Otherwise
873 * return a string representation.
876 lookup(struct xlat *xlat, int val, int base)
880 for (; xlat->str != NULL; xlat++)
881 if (xlat->val == val)
885 sprintf(tmp, "0%o", val);
888 sprintf(tmp, "0x%x", val);
891 sprintf(tmp, "%u", val);
894 errx(1,"Unknown lookup base");
901 xlookup(struct xlat *xlat, int val)
904 return (lookup(xlat, val, 16));
908 * Searches an xlat array containing bitfield values. Remaining bits
909 * set after removing the known ones are printed at the end:
913 xlookup_bits(struct xlat *xlat, int val)
916 static char str[512];
920 for (; xlat->str != NULL; xlat++) {
921 if ((xlat->val & rem) == xlat->val) {
923 * Don't print the "all-bits-zero" string unless all
924 * bits are really zero.
926 if (xlat->val == 0 && val != 0)
928 len += sprintf(str + len, "%s|", xlat->str);
934 * If we have leftover bits or didn't match anything, print
938 len += sprintf(str + len, "0x%x", rem);
939 if (len && str[len - 1] == '|')
946 print_integer_arg(const char *(*decoder)(int), FILE *fp, int value)
950 str = decoder(value);
954 fprintf(fp, "%d", value);
958 print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value)
962 if (!decoder(fp, value, &rem))
963 fprintf(fp, "0x%x", rem);
965 fprintf(fp, "|0x%x", rem);
969 print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), FILE *fp,
974 if (!decoder(fp, value, &rem))
975 fprintf(fp, "0x%x", rem);
977 fprintf(fp, "|0x%x", rem);
982 * Add argument padding to subsequent system calls afater a Quad
983 * syscall arguments as needed. This used to be done by hand in the
984 * decoded_syscalls table which was ugly and error prone. It is
985 * simpler to do the fixup of offsets at initalization time than when
986 * decoding arguments.
989 quad_fixup(struct syscall *sc)
996 for (i = 0; i < sc->nargs; i++) {
997 /* This arg type is a dummy that doesn't use offset. */
998 if ((sc->args[i].type & ARG_MASK) == PipeFds)
1001 assert(prev < sc->args[i].offset);
1002 prev = sc->args[i].offset;
1003 sc->args[i].offset += offset;
1004 switch (sc->args[i].type & ARG_MASK) {
1009 * 64-bit arguments on 32-bit powerpc must be
1010 * 64-bit aligned. If the current offset is
1011 * not aligned, the calling convention inserts
1012 * a 32-bit pad argument that should be skipped.
1014 if (sc->args[i].offset % 2 == 1) {
1015 sc->args[i].offset++;
1032 STAILQ_INIT(&syscalls);
1033 for (sc = decoded_syscalls; sc->name != NULL; sc++) {
1037 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
1041 static struct syscall *
1042 find_syscall(struct procabi *abi, u_int number)
1044 struct extra_syscall *es;
1046 if (number < nitems(abi->syscalls))
1047 return (abi->syscalls[number]);
1048 STAILQ_FOREACH(es, &abi->extra_syscalls, entries) {
1049 if (es->number == number)
1056 add_syscall(struct procabi *abi, u_int number, struct syscall *sc)
1058 struct extra_syscall *es;
1060 if (number < nitems(abi->syscalls)) {
1061 assert(abi->syscalls[number] == NULL);
1062 abi->syscalls[number] = sc;
1064 es = malloc(sizeof(*es));
1066 es->number = number;
1067 STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries);
1072 * If/when the list gets big, it might be desirable to do it
1073 * as a hash table or binary search.
1076 get_syscall(struct threadinfo *t, u_int number, u_int nargs)
1083 sc = find_syscall(t->proc->abi, number);
1087 name = sysdecode_syscallname(t->proc->abi->abi, number);
1089 asprintf(&new_name, "#%d", number);
1093 STAILQ_FOREACH(sc, &syscalls, entries) {
1094 if (strcmp(name, sc->name) == 0) {
1095 add_syscall(t->proc->abi, number, sc);
1101 /* It is unknown. Add it into the list. */
1103 fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
1107 sc = calloc(1, sizeof(struct syscall));
1109 if (new_name != NULL)
1113 for (i = 0; i < nargs; i++) {
1114 sc->args[i].offset = i;
1115 /* Treat all unknown arguments as LongHex. */
1116 sc->args[i].type = LongHex;
1118 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
1119 add_syscall(t->proc->abi, number, sc);
1125 * Copy a fixed amount of bytes from the process.
1128 get_struct(pid_t pid, void *offset, void *buf, int len)
1130 struct ptrace_io_desc iorequest;
1132 iorequest.piod_op = PIOD_READ_D;
1133 iorequest.piod_offs = offset;
1134 iorequest.piod_addr = buf;
1135 iorequest.piod_len = len;
1136 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
1141 #define MAXSIZE 4096
1144 * Copy a string from the process. Note that it is
1145 * expected to be a C string, but if max is set, it will
1146 * only get that much.
1149 get_string(pid_t pid, void *addr, int max)
1151 struct ptrace_io_desc iorequest;
1153 size_t offset, size, totalsize;
1159 /* Read up to the end of the current page. */
1160 size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE);
1165 buf = malloc(totalsize);
1169 iorequest.piod_op = PIOD_READ_D;
1170 iorequest.piod_offs = (char *)addr + offset;
1171 iorequest.piod_addr = buf + offset;
1172 iorequest.piod_len = size;
1173 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
1177 if (memchr(buf + offset, '\0', size) != NULL)
1180 if (totalsize < MAXSIZE && max == 0) {
1181 size = MAXSIZE - totalsize;
1182 if (size > PAGE_SIZE)
1184 nbuf = realloc(buf, totalsize + size);
1186 buf[totalsize - 1] = '\0';
1192 buf[totalsize - 1] = '\0';
1201 static char tmp[32];
1202 const char *signame;
1204 signame = sysdecode_signal(sig);
1205 if (signame == NULL) {
1206 snprintf(tmp, sizeof(tmp), "%d", sig);
1213 print_kevent(FILE *fp, struct kevent *ke, int input)
1216 switch (ke->filter) {
1222 case EVFILT_PROCDESC:
1223 fprintf(fp, "%ju", (uintmax_t)ke->ident);
1226 fputs(strsig2(ke->ident), fp);
1229 fprintf(fp, "%p", (void *)ke->ident);
1231 fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter),
1232 xlookup_bits(kevent_flags, ke->flags));
1233 switch (ke->filter) {
1236 fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp);
1239 fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp);
1242 case EVFILT_PROCDESC:
1243 fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp);
1246 fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp);
1251 ctrl = ke->fflags & NOTE_FFCTRLMASK;
1252 data = ke->fflags & NOTE_FFLAGSMASK;
1254 fputs(xlookup(kevent_user_ffctrl, ctrl), fp);
1255 if (ke->fflags & NOTE_TRIGGER)
1256 fputs("|NOTE_TRIGGER", fp);
1258 fprintf(fp, "|%#x", data);
1260 fprintf(fp, "%#x", data);
1265 fprintf(fp, "%#x", ke->fflags);
1267 fprintf(fp, ",%#jx,%p", (uintmax_t)ke->data, ke->udata);
1271 print_utrace(FILE *fp, void *utrace_addr, size_t len)
1273 unsigned char *utrace_buffer;
1276 if (sysdecode_utrace(fp, utrace_addr, len)) {
1281 utrace_buffer = utrace_addr;
1282 fprintf(fp, "%zu:", len);
1284 fprintf(fp, " %02x", *utrace_buffer++);
1289 * Converts a syscall argument into a string. Said string is
1290 * allocated via malloc(), so needs to be free()'d. sc is
1291 * a pointer to the syscall description (see above); args is
1292 * an array of all of the system call arguments.
1295 print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
1296 struct trussinfo *trussinfo)
1303 fp = open_memstream(&tmp, &tmplen);
1304 pid = trussinfo->curthread->proc->pid;
1305 switch (sc->type & ARG_MASK) {
1307 fprintf(fp, "0x%x", (int)args[sc->offset]);
1310 fprintf(fp, "0%o", (int)args[sc->offset]);
1313 fprintf(fp, "%d", (int)args[sc->offset]);
1316 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1321 if (get_struct(pid, (void *)args[sc->offset], &val,
1323 fprintf(fp, "{ %u }", val);
1325 fprintf(fp, "0x%lx", args[sc->offset]);
1329 fprintf(fp, "0x%lx", args[sc->offset]);
1332 fprintf(fp, "%ld", args[sc->offset]);
1335 fprintf(fp, "%zu", (size_t)args[sc->offset]);
1338 /* NULL-terminated string. */
1341 tmp2 = get_string(pid, (void*)args[sc->offset], 0);
1342 fprintf(fp, "\"%s\"", tmp2);
1348 * Binary block of data that might have printable characters.
1349 * XXX If type|OUT, assume that the length is the syscall's
1350 * return value. Otherwise, assume that the length of the block
1351 * is in the next syscall argument.
1353 int max_string = trussinfo->strsize;
1354 char tmp2[max_string + 1], *tmp3;
1361 len = args[sc->offset + 1];
1364 * Don't print more than max_string characters, to avoid word
1365 * wrap. If we have to truncate put some ... after the string.
1367 if (len > max_string) {
1371 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
1373 tmp3 = malloc(len * 4 + 1);
1375 if (strvisx(tmp3, tmp2, len,
1376 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1381 fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1385 fprintf(fp, "0x%lx", args[sc->offset]);
1395 char buf[PAGE_SIZE];
1402 * Only parse argv[] and environment arrays from exec calls
1405 if (((sc->type & ARG_MASK) == ExecArgs &&
1406 (trussinfo->flags & EXECVEARGS) == 0) ||
1407 ((sc->type & ARG_MASK) == ExecEnv &&
1408 (trussinfo->flags & EXECVEENVS) == 0)) {
1409 fprintf(fp, "0x%lx", args[sc->offset]);
1414 * Read a page of pointers at a time. Punt if the top-level
1415 * pointer is not aligned. Note that the first read is of
1418 addr = args[sc->offset];
1419 if (addr % sizeof(char *) != 0) {
1420 fprintf(fp, "0x%lx", args[sc->offset]);
1424 len = PAGE_SIZE - (addr & PAGE_MASK);
1425 if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
1426 fprintf(fp, "0x%lx", args[sc->offset]);
1433 while (u.strarray[i] != NULL) {
1434 string = get_string(pid, u.strarray[i], 0);
1435 fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1440 if (i == len / sizeof(char *)) {
1443 if (get_struct(pid, (void *)addr, u.buf, len) ==
1445 fprintf(fp, ", <inval>");
1456 fprintf(fp, "%ld", args[sc->offset]);
1459 fprintf(fp, "0x%lx", args[sc->offset]);
1464 unsigned long long ll;
1466 #if _BYTE_ORDER == _LITTLE_ENDIAN
1467 ll = (unsigned long long)args[sc->offset + 1] << 32 |
1470 ll = (unsigned long long)args[sc->offset] << 32 |
1471 args[sc->offset + 1];
1473 if ((sc->type & ARG_MASK) == Quad)
1474 fprintf(fp, "%lld", ll);
1476 fprintf(fp, "0x%llx", ll);
1483 if (get_struct(pid, (void *)args[sc->offset], &val,
1485 fprintf(fp, "{ 0x%jx }", (uintmax_t)val);
1487 fprintf(fp, "0x%lx", args[sc->offset]);
1491 fprintf(fp, "0x%lx", args[sc->offset]);
1496 if (retval[0] == -1)
1498 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
1499 fprintf(fp, "\"%s\"", tmp2);
1507 cmd = args[sc->offset];
1508 temp = sysdecode_ioctlname(cmd);
1512 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1513 cmd, cmd & IOC_OUT ? "R" : "",
1514 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1515 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1516 cmd & 0xFF, IOCPARM_LEN(cmd));
1523 if (get_struct(pid, (void *)args[sc->offset], &ts,
1525 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1528 fprintf(fp, "0x%lx", args[sc->offset]);
1532 struct timespec ts[2];
1536 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
1540 for (i = 0; i < nitems(ts); i++) {
1543 switch (ts[i].tv_nsec) {
1545 fprintf(fp, "UTIME_NOW");
1548 fprintf(fp, "UTIME_OMIT");
1551 fprintf(fp, "%jd.%09ld",
1552 (intmax_t)ts[i].tv_sec,
1559 fprintf(fp, "0x%lx", args[sc->offset]);
1565 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1567 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1570 fprintf(fp, "0x%lx", args[sc->offset]);
1574 struct timeval tv[2];
1576 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1578 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1579 (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1580 (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1582 fprintf(fp, "0x%lx", args[sc->offset]);
1586 struct itimerval itv;
1588 if (get_struct(pid, (void *)args[sc->offset], &itv,
1590 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1591 (intmax_t)itv.it_interval.tv_sec,
1592 itv.it_interval.tv_usec,
1593 (intmax_t)itv.it_value.tv_sec,
1594 itv.it_value.tv_usec);
1596 fprintf(fp, "0x%lx", args[sc->offset]);
1601 struct linux_socketcall_args largs;
1603 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
1604 sizeof(largs)) != -1)
1605 fprintf(fp, "{ %s, 0x%lx }",
1606 lookup(linux_socketcall_ops, largs.what, 10),
1607 (long unsigned int)largs.args);
1609 fprintf(fp, "0x%lx", args[sc->offset]);
1614 * XXX: A Pollfd argument expects the /next/ syscall argument
1615 * to be the number of fds in the array. This matches the poll
1619 int numfds = args[sc->offset + 1];
1620 size_t bytes = sizeof(struct pollfd) * numfds;
1623 if ((pfd = malloc(bytes)) == NULL)
1624 err(1, "Cannot malloc %zu bytes for pollfd array",
1626 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
1629 for (i = 0; i < numfds; i++) {
1630 fprintf(fp, " %d/%s", pfd[i].fd,
1631 xlookup_bits(poll_flags, pfd[i].events));
1635 fprintf(fp, "0x%lx", args[sc->offset]);
1642 * XXX: A Fd_set argument expects the /first/ syscall argument
1643 * to be the number of fds in the array. This matches the
1647 int numfds = args[0];
1648 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1651 if ((fds = malloc(bytes)) == NULL)
1652 err(1, "Cannot malloc %zu bytes for fd_set array",
1654 if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
1657 for (i = 0; i < numfds; i++) {
1658 if (FD_ISSET(i, fds))
1659 fprintf(fp, " %d", i);
1663 fprintf(fp, "0x%lx", args[sc->offset]);
1668 fputs(strsig2(args[sc->offset]), fp);
1675 sig = args[sc->offset];
1676 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
1677 sizeof(ss)) == -1) {
1678 fprintf(fp, "0x%lx", args[sc->offset]);
1683 for (i = 1; i < sys_nsig; i++) {
1684 if (sigismember(&ss, i)) {
1685 fprintf(fp, "%s%s", !first ? "|" : "",
1696 print_integer_arg(sysdecode_sigprocmask_how, fp,
1700 /* XXX: Output depends on the value of the previous argument. */
1701 if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
1702 sysdecode_fcntl_arg(fp, args[sc->offset - 1],
1703 args[sc->offset], 16);
1706 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
1709 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
1712 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
1715 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
1718 print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
1721 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
1724 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
1727 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
1730 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
1733 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]);
1736 fputs(xlookup(pathconf_arg, args[sc->offset]), fp);
1739 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
1743 struct sockaddr_in *lsin;
1744 struct sockaddr_in6 *lsin6;
1745 struct sockaddr_un *sun;
1746 struct sockaddr *sa;
1750 if (args[sc->offset] == 0) {
1756 * Extract the address length from the next argument. If
1757 * this is an output sockaddr (OUT is set), then the
1758 * next argument is a pointer to a socklen_t. Otherwise
1759 * the next argument contains a socklen_t by value.
1761 if (sc->type & OUT) {
1762 if (get_struct(pid, (void *)args[sc->offset + 1],
1763 &len, sizeof(len)) == -1) {
1764 fprintf(fp, "0x%lx", args[sc->offset]);
1768 len = args[sc->offset + 1];
1770 /* If the length is too small, just bail. */
1771 if (len < sizeof(*sa)) {
1772 fprintf(fp, "0x%lx", args[sc->offset]);
1776 sa = calloc(1, len);
1777 if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) {
1779 fprintf(fp, "0x%lx", args[sc->offset]);
1783 switch (sa->sa_family) {
1785 if (len < sizeof(*lsin))
1786 goto sockaddr_short;
1787 lsin = (struct sockaddr_in *)(void *)sa;
1788 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1789 fprintf(fp, "{ AF_INET %s:%d }", addr,
1790 htons(lsin->sin_port));
1793 if (len < sizeof(*lsin6))
1794 goto sockaddr_short;
1795 lsin6 = (struct sockaddr_in6 *)(void *)sa;
1796 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1798 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1799 htons(lsin6->sin6_port));
1802 sun = (struct sockaddr_un *)sa;
1803 fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1804 (int)(len - offsetof(struct sockaddr_un, sun_path)),
1810 "{ sa_len = %d, sa_family = %d, sa_data = {",
1811 (int)sa->sa_len, (int)sa->sa_family);
1812 for (q = (u_char *)sa->sa_data;
1813 q < (u_char *)sa + len; q++)
1814 fprintf(fp, "%s 0x%02x",
1815 q == (u_char *)sa->sa_data ? "" : ",",
1823 struct sigaction sa;
1825 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
1828 if (sa.sa_handler == SIG_DFL)
1829 fputs("SIG_DFL", fp);
1830 else if (sa.sa_handler == SIG_IGN)
1831 fputs("SIG_IGN", fp);
1833 fprintf(fp, "%p", sa.sa_handler);
1834 fprintf(fp, " %s ss_t }",
1835 xlookup_bits(sigaction_flags, sa.sa_flags));
1837 fprintf(fp, "0x%lx", args[sc->offset]);
1842 * XXX XXX: The size of the array is determined by either the
1843 * next syscall argument, or by the syscall return value,
1844 * depending on which argument number we are. This matches the
1845 * kevent syscall, but luckily that's the only syscall that uses
1853 if (sc->offset == 1)
1854 numevents = args[sc->offset+1];
1855 else if (sc->offset == 3 && retval[0] != -1)
1856 numevents = retval[0];
1858 if (numevents >= 0) {
1859 bytes = sizeof(struct kevent) * numevents;
1860 if ((ke = malloc(bytes)) == NULL)
1862 "Cannot malloc %zu bytes for kevent array",
1866 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
1869 for (i = 0; i < numevents; i++) {
1871 print_kevent(fp, &ke[i], sc->offset == 1);
1875 fprintf(fp, "0x%lx", args[sc->offset]);
1883 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1887 strmode(st.st_mode, mode);
1889 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1890 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1891 (long)st.st_blksize);
1893 fprintf(fp, "0x%lx", args[sc->offset]);
1898 struct freebsd11_stat st;
1900 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1904 strmode(st.st_mode, mode);
1906 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1907 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1908 (long)st.st_blksize);
1910 fprintf(fp, "0x%lx", args[sc->offset]);
1918 if (get_struct(pid, (void *)args[sc->offset], &buf,
1919 sizeof(buf)) != -1) {
1922 bzero(fsid, sizeof(fsid));
1923 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
1924 for (i = 0; i < sizeof(buf.f_fsid); i++)
1925 snprintf(&fsid[i*2],
1926 sizeof(fsid) - (i*2), "%02x",
1927 ((u_char *)&buf.f_fsid)[i]);
1930 "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
1931 "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
1932 buf.f_mntfromname, fsid);
1934 fprintf(fp, "0x%lx", args[sc->offset]);
1941 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
1944 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
1945 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
1946 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
1947 ru.ru_inblock, ru.ru_oublock);
1949 fprintf(fp, "0x%lx", args[sc->offset]);
1955 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
1957 fprintf(fp, "{ cur=%ju,max=%ju }",
1958 rl.rlim_cur, rl.rlim_max);
1960 fprintf(fp, "0x%lx", args[sc->offset]);
1966 if (get_struct(pid, (void *)args[sc->offset], &status,
1967 sizeof(status)) != -1) {
1969 if (WIFCONTINUED(status))
1970 fputs("CONTINUED", fp);
1971 else if (WIFEXITED(status))
1972 fprintf(fp, "EXITED,val=%d",
1973 WEXITSTATUS(status));
1974 else if (WIFSIGNALED(status))
1975 fprintf(fp, "SIGNALED,sig=%s%s",
1976 strsig2(WTERMSIG(status)),
1977 WCOREDUMP(status) ? ",cored" : "");
1979 fprintf(fp, "STOPPED,sig=%s",
1980 strsig2(WTERMSIG(status)));
1983 fprintf(fp, "0x%lx", args[sc->offset]);
1987 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]);
1990 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]);
1993 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]);
1996 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]);
1999 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]);
2002 fputs(xlookup_bits(at_flags, args[sc->offset]), fp);
2005 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]);
2008 fputs(xlookup(sysarch_ops, args[sc->offset]), fp);
2012 * The pipe() system call in the kernel returns its
2013 * two file descriptors via return values. However,
2014 * the interface exposed by libc is that pipe()
2015 * accepts a pointer to an array of descriptors.
2016 * Format the output to match the libc API by printing
2017 * the returned file descriptors as a fake argument.
2019 * Overwrite the first retval to signal a successful
2022 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
2029 len = args[sc->offset + 1];
2030 utrace_addr = calloc(1, len);
2031 if (get_struct(pid, (void *)args[sc->offset],
2032 (void *)utrace_addr, len) != -1)
2033 print_utrace(fp, utrace_addr, len);
2035 fprintf(fp, "0x%lx", args[sc->offset]);
2040 int descriptors[16];
2041 unsigned long i, ndescriptors;
2044 ndescriptors = args[sc->offset + 1];
2046 if (ndescriptors > nitems(descriptors)) {
2047 ndescriptors = nitems(descriptors);
2050 if (get_struct(pid, (void *)args[sc->offset],
2051 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
2053 for (i = 0; i < ndescriptors; i++)
2054 fprintf(fp, i == 0 ? " %d" : ", %d",
2056 fprintf(fp, truncated ? ", ... }" : " }");
2058 fprintf(fp, "0x%lx", args[sc->offset]);
2062 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]);
2064 case CapFcntlRights: {
2067 if (sc->type & OUT) {
2068 if (get_struct(pid, (void *)args[sc->offset], &rights,
2069 sizeof(rights)) == -1) {
2070 fprintf(fp, "0x%lx", args[sc->offset]);
2074 rights = args[sc->offset];
2075 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights);
2079 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]);
2084 if (!sysdecode_fileflags(fp, args[sc->offset], &rem))
2085 fprintf(fp, "0x%x", rem);
2087 fprintf(fp, "|0x%x", rem);
2091 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]);
2094 print_integer_arg(sysdecode_getfsstat_mode, fp,
2098 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]);
2100 case Kldunloadflags:
2101 print_integer_arg(sysdecode_kldunload_flags, fp,
2105 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]);
2108 fprintf(fp, "%u", (socklen_t)args[sc->offset]);
2110 case Sockprotocol: {
2112 int domain, protocol;
2114 domain = args[sc->offset - 2];
2115 protocol = args[sc->offset];
2116 if (protocol == 0) {
2119 temp = sysdecode_socket_protocol(domain, protocol);
2123 fprintf(fp, "%d", protocol);
2129 print_integer_arg(sysdecode_sockopt_level, fp,
2136 level = args[sc->offset - 1];
2137 name = args[sc->offset];
2138 temp = sysdecode_sockopt_name(level, name);
2142 fprintf(fp, "%d", name);
2147 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]);
2150 cap_rights_t rights;
2152 if (get_struct(pid, (void *)args[sc->offset], &rights,
2153 sizeof(rights)) != -1) {
2155 sysdecode_cap_rights(fp, &rights);
2158 fprintf(fp, "0x%lx", args[sc->offset]);
2162 print_integer_arg(sysdecode_acltype, fp, args[sc->offset]);
2164 case Extattrnamespace:
2165 print_integer_arg(sysdecode_extattrnamespace, fp,
2169 print_integer_arg(sysdecode_minherit_inherit, fp,
2173 print_mask_arg(sysdecode_mlockall_flags, fp, args[sc->offset]);
2176 print_mask_arg(sysdecode_mount_flags, fp, args[sc->offset]);
2179 print_mask_arg(sysdecode_msync_flags, fp, args[sc->offset]);
2182 print_integer_arg(sysdecode_prio_which, fp, args[sc->offset]);
2185 print_integer_arg(sysdecode_ptrace_request, fp,
2189 if (!sysdecode_quotactl_cmd(fp, args[sc->offset]))
2190 fprintf(fp, "%#x", (int)args[sc->offset]);
2193 print_mask_arg(sysdecode_reboot_howto, fp, args[sc->offset]);
2196 print_integer_arg(sysdecode_rtprio_function, fp,
2200 print_integer_arg(sysdecode_scheduler_policy, fp,
2204 struct sched_param sp;
2206 if (get_struct(pid, (void *)args[sc->offset], &sp,
2208 fprintf(fp, "{ %d }", sp.sched_priority);
2210 fprintf(fp, "0x%lx", args[sc->offset]);
2214 case CloudABIAdvice:
2215 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
2217 case CloudABIClockID:
2218 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2220 case ClouduABIFDSFlags:
2221 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2223 case CloudABIFDStat: {
2224 cloudabi_fdstat_t fds;
2225 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds))
2227 fprintf(fp, "{ %s, ",
2228 xlookup(cloudabi_filetype, fds.fs_filetype));
2229 fprintf(fp, "%s, ... }",
2230 xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2232 fprintf(fp, "0x%lx", args[sc->offset]);
2235 case CloudABIFileStat: {
2236 cloudabi_filestat_t fsb;
2237 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb))
2239 fprintf(fp, "{ %s, %ju }",
2240 xlookup(cloudabi_filetype, fsb.st_filetype),
2241 (uintmax_t)fsb.st_size);
2243 fprintf(fp, "0x%lx", args[sc->offset]);
2246 case CloudABIFileType:
2247 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2249 case CloudABIFSFlags:
2250 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2252 case CloudABILookup:
2253 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2254 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2255 (int)args[sc->offset]);
2257 fprintf(fp, "%d", (int)args[sc->offset]);
2259 case CloudABIMFlags:
2260 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2263 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2265 case CloudABIMSFlags:
2266 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2268 case CloudABIOFlags:
2269 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2271 case CloudABISDFlags:
2272 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2274 case CloudABISignal:
2275 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2277 case CloudABISockStat: {
2278 cloudabi_sockstat_t ss;
2279 if (get_struct(pid, (void *)args[sc->offset], &ss, sizeof(ss))
2281 fprintf(fp, "{ %s, ", xlookup(
2282 cloudabi_sa_family, ss.ss_sockname.sa_family));
2283 fprintf(fp, "%s, ", xlookup(
2284 cloudabi_sa_family, ss.ss_peername.sa_family));
2285 fprintf(fp, "%s, ", xlookup(
2286 cloudabi_errno, ss.ss_error));
2287 fprintf(fp, "%s }", xlookup_bits(
2288 cloudabi_ssstate, ss.ss_state));
2290 fprintf(fp, "0x%lx", args[sc->offset]);
2293 case CloudABISSFlags:
2294 fputs(xlookup_bits(cloudabi_ssflags, args[sc->offset]), fp);
2296 case CloudABITimestamp:
2297 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2298 args[sc->offset] % 1000000000);
2300 case CloudABIULFlags:
2301 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2303 case CloudABIWhence:
2304 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2308 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2315 * Print (to outfile) the system call and its arguments.
2318 print_syscall(struct trussinfo *trussinfo)
2320 struct threadinfo *t;
2325 t = trussinfo->curthread;
2327 name = t->cs.sc->name;
2328 nargs = t->cs.nargs;
2329 s_args = t->cs.s_args;
2331 len = print_line_prefix(trussinfo);
2332 len += fprintf(trussinfo->outfile, "%s(", name);
2334 for (i = 0; i < nargs; i++) {
2335 if (s_args[i] != NULL)
2336 len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2338 len += fprintf(trussinfo->outfile,
2339 "<missing argument>");
2340 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2343 len += fprintf(trussinfo->outfile, ")");
2344 for (i = 0; i < 6 - (len / 8); i++)
2345 fprintf(trussinfo->outfile, "\t");
2349 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
2351 struct timespec timediff;
2352 struct threadinfo *t;
2356 t = trussinfo->curthread;
2358 if (trussinfo->flags & COUNTONLY) {
2359 timespecsubt(&t->after, &t->before, &timediff);
2360 timespecadd(&sc->time, &timediff, &sc->time);
2367 print_syscall(trussinfo);
2368 fflush(trussinfo->outfile);
2370 if (retval == NULL) {
2372 * This system call resulted in the current thread's exit,
2373 * so there is no return value or error to display.
2375 fprintf(trussinfo->outfile, "\n");
2380 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi,
2382 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
2383 error == INT_MAX ? "Unknown error" : strerror(error));
2386 else if (sc->ret_type == 2) {
2389 #if _BYTE_ORDER == _LITTLE_ENDIAN
2390 off = (off_t)retval[1] << 32 | retval[0];
2392 off = (off_t)retval[0] << 32 | retval[1];
2394 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2399 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
2404 print_summary(struct trussinfo *trussinfo)
2406 struct timespec total = {0, 0};
2410 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2411 "syscall", "seconds", "calls", "errors");
2413 STAILQ_FOREACH(sc, &syscalls, entries)
2415 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2416 sc->name, (intmax_t)sc->time.tv_sec,
2417 sc->time.tv_nsec, sc->ncalls, sc->nerror);
2418 timespecadd(&total, &sc->time, &total);
2419 ncall += sc->ncalls;
2420 nerror += sc->nerror;
2422 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2423 "", "-------------", "-------", "-------");
2424 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2425 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);