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 = "compat11.fstat", .ret_type = 1, .nargs = 2,
150 .args = { { Int, 0 }, { Stat11 | OUT, 1 } } },
151 { .name = "compat11.fstatat", .ret_type = 1, .nargs = 4,
152 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat11 | OUT, 2 },
154 { .name = "compat11.lstat", .ret_type = 1, .nargs = 2,
155 .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } },
156 { .name = "compat11.stat", .ret_type = 1, .nargs = 2,
157 .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } },
158 { .name = "connect", .ret_type = 1, .nargs = 3,
159 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
160 { .name = "connectat", .ret_type = 1, .nargs = 4,
161 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
163 { .name = "dup", .ret_type = 1, .nargs = 1,
164 .args = { { Int, 0 } } },
165 { .name = "dup2", .ret_type = 1, .nargs = 2,
166 .args = { { Int, 0 }, { Int, 1 } } },
167 { .name = "eaccess", .ret_type = 1, .nargs = 2,
168 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
169 { .name = "execve", .ret_type = 1, .nargs = 3,
170 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
171 { ExecEnv | IN, 2 } } },
172 { .name = "exit", .ret_type = 0, .nargs = 1,
173 .args = { { Hex, 0 } } },
174 { .name = "extattr_delete_fd", .ret_type = 1, .nargs = 3,
175 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
176 { .name = "extattr_delete_file", .ret_type = 1, .nargs = 3,
177 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
178 { .name = "extattr_delete_link", .ret_type = 1, .nargs = 3,
179 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
180 { .name = "extattr_get_fd", .ret_type = 1, .nargs = 5,
181 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
182 { BinString | OUT, 3 }, { Sizet, 4 } } },
183 { .name = "extattr_get_file", .ret_type = 1, .nargs = 5,
184 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
185 { BinString | OUT, 3 }, { Sizet, 4 } } },
186 { .name = "extattr_get_link", .ret_type = 1, .nargs = 5,
187 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
188 { BinString | OUT, 3 }, { Sizet, 4 } } },
189 { .name = "extattr_list_fd", .ret_type = 1, .nargs = 4,
190 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
192 { .name = "extattr_list_file", .ret_type = 1, .nargs = 4,
193 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
195 { .name = "extattr_list_link", .ret_type = 1, .nargs = 4,
196 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
198 { .name = "extattr_set_fd", .ret_type = 1, .nargs = 5,
199 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
200 { BinString | IN, 3 }, { Sizet, 4 } } },
201 { .name = "extattr_set_file", .ret_type = 1, .nargs = 5,
202 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
203 { BinString | IN, 3 }, { Sizet, 4 } } },
204 { .name = "extattr_set_link", .ret_type = 1, .nargs = 5,
205 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
206 { BinString | IN, 3 }, { Sizet, 4 } } },
207 { .name = "extattrctl", .ret_type = 1, .nargs = 5,
208 .args = { { Name, 0 }, { Hex, 1 }, { Name, 2 },
209 { Extattrnamespace, 3 }, { Name, 4 } } },
210 { .name = "faccessat", .ret_type = 1, .nargs = 4,
211 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
213 { .name = "fchflags", .ret_type = 1, .nargs = 2,
214 .args = { { Int, 0 }, { FileFlags, 1 } } },
215 { .name = "fchmod", .ret_type = 1, .nargs = 2,
216 .args = { { Int, 0 }, { Octal, 1 } } },
217 { .name = "fchmodat", .ret_type = 1, .nargs = 4,
218 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
219 { .name = "fchown", .ret_type = 1, .nargs = 3,
220 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
221 { .name = "fchownat", .ret_type = 1, .nargs = 5,
222 .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
224 { .name = "fcntl", .ret_type = 1, .nargs = 3,
225 .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
226 { .name = "flock", .ret_type = 1, .nargs = 2,
227 .args = { { Int, 0 }, { Flockop, 1 } } },
228 { .name = "fstat", .ret_type = 1, .nargs = 2,
229 .args = { { Int, 0 }, { Stat | OUT, 1 } } },
230 { .name = "fstatat", .ret_type = 1, .nargs = 4,
231 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
233 { .name = "fstatfs", .ret_type = 1, .nargs = 2,
234 .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
235 { .name = "ftruncate", .ret_type = 1, .nargs = 2,
236 .args = { { Int | IN, 0 }, { QuadHex | IN, 1 } } },
237 { .name = "futimens", .ret_type = 1, .nargs = 2,
238 .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
239 { .name = "futimes", .ret_type = 1, .nargs = 2,
240 .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
241 { .name = "futimesat", .ret_type = 1, .nargs = 3,
242 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
243 { .name = "getdirentries", .ret_type = 1, .nargs = 4,
244 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
245 { PQuadHex | OUT, 3 } } },
246 { .name = "getfsstat", .ret_type = 1, .nargs = 3,
247 .args = { { Ptr, 0 }, { Long, 1 }, { Getfsstatmode, 2 } } },
248 { .name = "getitimer", .ret_type = 1, .nargs = 2,
249 .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
250 { .name = "getpeername", .ret_type = 1, .nargs = 3,
251 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
252 { .name = "getpgid", .ret_type = 1, .nargs = 1,
253 .args = { { Int, 0 } } },
254 { .name = "getpriority", .ret_type = 1, .nargs = 2,
255 .args = { { Priowhich, 0 }, { Int, 1 } } },
256 { .name = "getrlimit", .ret_type = 1, .nargs = 2,
257 .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
258 { .name = "getrusage", .ret_type = 1, .nargs = 2,
259 .args = { { RusageWho, 0 }, { Rusage | OUT, 1 } } },
260 { .name = "getsid", .ret_type = 1, .nargs = 1,
261 .args = { { Int, 0 } } },
262 { .name = "getsockname", .ret_type = 1, .nargs = 3,
263 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
264 { .name = "getsockopt", .ret_type = 1, .nargs = 5,
265 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
266 { Ptr | OUT, 3 }, { Ptr | OUT, 4 } } },
267 { .name = "gettimeofday", .ret_type = 1, .nargs = 2,
268 .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
269 { .name = "ioctl", .ret_type = 1, .nargs = 3,
270 .args = { { Int, 0 }, { Ioctl, 1 }, { Ptr, 2 } } },
271 { .name = "kevent", .ret_type = 1, .nargs = 6,
272 .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
273 { Int, 4 }, { Timespec, 5 } } },
274 { .name = "kill", .ret_type = 1, .nargs = 2,
275 .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
276 { .name = "kldfind", .ret_type = 1, .nargs = 1,
277 .args = { { Name | IN, 0 } } },
278 { .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
279 .args = { { Int, 0 } } },
280 { .name = "kldload", .ret_type = 1, .nargs = 1,
281 .args = { { Name | IN, 0 } } },
282 { .name = "kldnext", .ret_type = 1, .nargs = 1,
283 .args = { { Int, 0 } } },
284 { .name = "kldstat", .ret_type = 1, .nargs = 2,
285 .args = { { Int, 0 }, { Ptr, 1 } } },
286 { .name = "kldsym", .ret_type = 1, .nargs = 3,
287 .args = { { Int, 0 }, { Kldsymcmd, 1 }, { Ptr, 2 } } },
288 { .name = "kldunload", .ret_type = 1, .nargs = 1,
289 .args = { { Int, 0 } } },
290 { .name = "kldunloadf", .ret_type = 1, .nargs = 2,
291 .args = { { Int, 0 }, { Kldunloadflags, 1 } } },
292 { .name = "kse_release", .ret_type = 0, .nargs = 1,
293 .args = { { Timespec, 0 } } },
294 { .name = "lchflags", .ret_type = 1, .nargs = 2,
295 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
296 { .name = "lchmod", .ret_type = 1, .nargs = 2,
297 .args = { { Name, 0 }, { Octal, 1 } } },
298 { .name = "lchown", .ret_type = 1, .nargs = 3,
299 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
300 { .name = "link", .ret_type = 1, .nargs = 2,
301 .args = { { Name, 0 }, { Name, 1 } } },
302 { .name = "linkat", .ret_type = 1, .nargs = 5,
303 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
305 { .name = "listen", .ret_type = 1, .nargs = 2,
306 .args = { { Int, 0 }, { Int, 1 } } },
307 { .name = "lseek", .ret_type = 2, .nargs = 3,
308 .args = { { Int, 0 }, { QuadHex, 1 }, { Whence, 2 } } },
309 { .name = "lstat", .ret_type = 1, .nargs = 2,
310 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
311 { .name = "lutimes", .ret_type = 1, .nargs = 2,
312 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
313 { .name = "madvise", .ret_type = 1, .nargs = 3,
314 .args = { { Ptr, 0 }, { Sizet, 1 }, { Madvice, 2 } } },
315 { .name = "minherit", .ret_type = 1, .nargs = 3,
316 .args = { { Ptr, 0 }, { Sizet, 1 }, { Minherit, 2 } } },
317 { .name = "mkdir", .ret_type = 1, .nargs = 2,
318 .args = { { Name, 0 }, { Octal, 1 } } },
319 { .name = "mkdirat", .ret_type = 1, .nargs = 3,
320 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
321 { .name = "mkfifo", .ret_type = 1, .nargs = 2,
322 .args = { { Name, 0 }, { Octal, 1 } } },
323 { .name = "mkfifoat", .ret_type = 1, .nargs = 3,
324 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
325 { .name = "mknod", .ret_type = 1, .nargs = 3,
326 .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
327 { .name = "mknodat", .ret_type = 1, .nargs = 4,
328 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
329 { .name = "mlock", .ret_type = 1, .nargs = 2,
330 .args = { { Ptr, 0 }, { Sizet, 1 } } },
331 { .name = "mlockall", .ret_type = 1, .nargs = 1,
332 .args = { { Mlockall, 0 } } },
333 { .name = "mmap", .ret_type = 1, .nargs = 6,
334 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
335 { Int, 4 }, { QuadHex, 5 } } },
336 { .name = "modfind", .ret_type = 1, .nargs = 1,
337 .args = { { Name | IN, 0 } } },
338 { .name = "mount", .ret_type = 1, .nargs = 4,
339 .args = { { Name, 0 }, { Name, 1 }, { Mountflags, 2 }, { Ptr, 3 } } },
340 { .name = "mprotect", .ret_type = 1, .nargs = 3,
341 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 } } },
342 { .name = "msync", .ret_type = 1, .nargs = 3,
343 .args = { { Ptr, 0 }, { Sizet, 1 }, { Msync, 2 } } },
344 { .name = "munlock", .ret_type = 1, .nargs = 2,
345 .args = { { Ptr, 0 }, { Sizet, 1 } } },
346 { .name = "munmap", .ret_type = 1, .nargs = 2,
347 .args = { { Ptr, 0 }, { Sizet, 1 } } },
348 { .name = "nanosleep", .ret_type = 1, .nargs = 1,
349 .args = { { Timespec, 0 } } },
350 { .name = "nmount", .ret_type = 1, .nargs = 3,
351 .args = { { Ptr, 0 }, { UInt, 1 }, { Mountflags, 2 } } },
352 { .name = "open", .ret_type = 1, .nargs = 3,
353 .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
354 { .name = "openat", .ret_type = 1, .nargs = 4,
355 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
357 { .name = "pathconf", .ret_type = 1, .nargs = 2,
358 .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
359 { .name = "pipe", .ret_type = 1, .nargs = 1,
360 .args = { { PipeFds | OUT, 0 } } },
361 { .name = "pipe2", .ret_type = 1, .nargs = 2,
362 .args = { { Ptr, 0 }, { Pipe2, 1 } } },
363 { .name = "poll", .ret_type = 1, .nargs = 3,
364 .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
365 { .name = "posix_fadvise", .ret_type = 1, .nargs = 4,
366 .args = { { Int, 0 }, { QuadHex, 1 }, { QuadHex, 2 },
368 { .name = "posix_openpt", .ret_type = 1, .nargs = 1,
369 .args = { { Open, 0 } } },
370 { .name = "pread", .ret_type = 1, .nargs = 4,
371 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
373 { .name = "procctl", .ret_type = 1, .nargs = 4,
374 .args = { { Idtype, 0 }, { Quad, 1 }, { Procctl, 2 }, { Ptr, 3 } } },
375 { .name = "ptrace", .ret_type = 1, .nargs = 4,
376 .args = { { Ptraceop, 0 }, { Int, 1 }, { Ptr, 2 }, { Int, 3 } } },
377 { .name = "pwrite", .ret_type = 1, .nargs = 4,
378 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
380 { .name = "quotactl", .ret_type = 1, .nargs = 4,
381 .args = { { Name, 0 }, { Quotactlcmd, 1 }, { Int, 2 }, { Ptr, 3 } } },
382 { .name = "read", .ret_type = 1, .nargs = 3,
383 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 } } },
384 { .name = "readlink", .ret_type = 1, .nargs = 3,
385 .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Sizet, 2 } } },
386 { .name = "readlinkat", .ret_type = 1, .nargs = 4,
387 .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
389 { .name = "reboot", .ret_type = 1, .nargs = 1,
390 .args = { { Reboothowto, 0 } } },
391 { .name = "recvfrom", .ret_type = 1, .nargs = 6,
392 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
393 { Msgflags, 3 }, { Sockaddr | OUT, 4 },
394 { Ptr | OUT, 5 } } },
395 { .name = "recvmsg", .ret_type = 1, .nargs = 3,
396 .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
397 { .name = "rename", .ret_type = 1, .nargs = 2,
398 .args = { { Name, 0 }, { Name, 1 } } },
399 { .name = "renameat", .ret_type = 1, .nargs = 4,
400 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
401 { .name = "rfork", .ret_type = 1, .nargs = 1,
402 .args = { { Rforkflags, 0 } } },
403 { .name = "rmdir", .ret_type = 1, .nargs = 1,
404 .args = { { Name, 0 } } },
405 { .name = "rtprio", .ret_type = 1, .nargs = 3,
406 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
407 { .name = "rtprio_thread", .ret_type = 1, .nargs = 3,
408 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
409 { .name = "sched_get_priority_max", .ret_type = 1, .nargs = 1,
410 .args = { { Schedpolicy, 0 } } },
411 { .name = "sched_get_priority_min", .ret_type = 1, .nargs = 1,
412 .args = { { Schedpolicy, 0 } } },
413 { .name = "sched_getparam", .ret_type = 1, .nargs = 2,
414 .args = { { Int, 0 }, { Schedparam | OUT, 1 } } },
415 { .name = "sched_getscheduler", .ret_type = 1, .nargs = 1,
416 .args = { { Int, 0 } } },
417 { .name = "sched_rr_get_interval", .ret_type = 1, .nargs = 2,
418 .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
419 { .name = "sched_setparam", .ret_type = 1, .nargs = 2,
420 .args = { { Int, 0 }, { Schedparam, 1 } } },
421 { .name = "sched_setscheduler", .ret_type = 1, .nargs = 3,
422 .args = { { Int, 0 }, { Schedpolicy, 1 }, { Schedparam, 2 } } },
423 { .name = "sctp_generic_recvmsg", .ret_type = 1, .nargs = 7,
424 .args = { { Int, 0 }, { Ptr | IN, 1 }, { Int, 2 },
425 { Sockaddr | OUT, 3 }, { Ptr | OUT, 4 }, { Ptr | OUT, 5 },
426 { Ptr | OUT, 6 } } },
427 { .name = "sctp_generic_sendmsg", .ret_type = 1, .nargs = 7,
428 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
429 { Sockaddr | IN, 3 }, { Socklent, 4 }, { Ptr | IN, 5 },
431 { .name = "select", .ret_type = 1, .nargs = 5,
432 .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
434 { .name = "sendmsg", .ret_type = 1, .nargs = 3,
435 .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
436 { .name = "sendto", .ret_type = 1, .nargs = 6,
437 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
438 { Msgflags, 3 }, { Sockaddr | IN, 4 },
439 { Socklent | IN, 5 } } },
440 { .name = "setitimer", .ret_type = 1, .nargs = 3,
441 .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
442 { .name = "setpriority", .ret_type = 1, .nargs = 3,
443 .args = { { Priowhich, 0 }, { Int, 1 }, { Int, 2 } } },
444 { .name = "setrlimit", .ret_type = 1, .nargs = 2,
445 .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
446 { .name = "setsockopt", .ret_type = 1, .nargs = 5,
447 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
448 { Ptr | IN, 3 }, { Socklent, 4 } } },
449 { .name = "shutdown", .ret_type = 1, .nargs = 2,
450 .args = { { Int, 0 }, { Shutdown, 1 } } },
451 { .name = "sigaction", .ret_type = 1, .nargs = 3,
452 .args = { { Signal, 0 }, { Sigaction | IN, 1 },
453 { Sigaction | OUT, 2 } } },
454 { .name = "sigpending", .ret_type = 1, .nargs = 1,
455 .args = { { Sigset | OUT, 0 } } },
456 { .name = "sigprocmask", .ret_type = 1, .nargs = 3,
457 .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
458 { .name = "sigqueue", .ret_type = 1, .nargs = 3,
459 .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
460 { .name = "sigreturn", .ret_type = 1, .nargs = 1,
461 .args = { { Ptr, 0 } } },
462 { .name = "sigsuspend", .ret_type = 1, .nargs = 1,
463 .args = { { Sigset | IN, 0 } } },
464 { .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
465 .args = { { Sigset | IN, 0 }, { Ptr, 1 }, { Timespec | IN, 2 } } },
466 { .name = "sigwait", .ret_type = 1, .nargs = 2,
467 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
468 { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
469 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
470 { .name = "socket", .ret_type = 1, .nargs = 3,
471 .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Sockprotocol, 2 } } },
472 { .name = "stat", .ret_type = 1, .nargs = 2,
473 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
474 { .name = "statfs", .ret_type = 1, .nargs = 2,
475 .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } },
476 { .name = "symlink", .ret_type = 1, .nargs = 2,
477 .args = { { Name, 0 }, { Name, 1 } } },
478 { .name = "symlinkat", .ret_type = 1, .nargs = 3,
479 .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } },
480 { .name = "sysarch", .ret_type = 1, .nargs = 2,
481 .args = { { Sysarch, 0 }, { Ptr, 1 } } },
482 { .name = "thr_kill", .ret_type = 1, .nargs = 2,
483 .args = { { Long, 0 }, { Signal, 1 } } },
484 { .name = "thr_self", .ret_type = 1, .nargs = 1,
485 .args = { { Ptr, 0 } } },
486 { .name = "truncate", .ret_type = 1, .nargs = 2,
487 .args = { { Name | IN, 0 }, { QuadHex | IN, 1 } } },
490 { .name = "umount", .ret_type = 1, .nargs = 2,
491 .args = { { Name, 0 }, { Int, 2 } } },
493 { .name = "unlink", .ret_type = 1, .nargs = 1,
494 .args = { { Name, 0 } } },
495 { .name = "unlinkat", .ret_type = 1, .nargs = 3,
496 .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
497 { .name = "unmount", .ret_type = 1, .nargs = 2,
498 .args = { { Name, 0 }, { Mountflags, 1 } } },
499 { .name = "utimensat", .ret_type = 1, .nargs = 4,
500 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
502 { .name = "utimes", .ret_type = 1, .nargs = 2,
503 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
504 { .name = "utrace", .ret_type = 1, .nargs = 1,
505 .args = { { Utrace, 0 } } },
506 { .name = "wait4", .ret_type = 1, .nargs = 4,
507 .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
508 { Rusage | OUT, 3 } } },
509 { .name = "wait6", .ret_type = 1, .nargs = 6,
510 .args = { { Idtype, 0 }, { Quad, 1 }, { ExitStatus | OUT, 2 },
511 { Waitoptions, 3 }, { Rusage | OUT, 4 }, { Ptr, 5 } } },
512 { .name = "write", .ret_type = 1, .nargs = 3,
513 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 } } },
516 { .name = "linux_access", .ret_type = 1, .nargs = 2,
517 .args = { { Name, 0 }, { Accessmode, 1 } } },
518 { .name = "linux_execve", .ret_type = 1, .nargs = 3,
519 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
520 { ExecEnv | IN, 2 } } },
521 { .name = "linux_lseek", .ret_type = 2, .nargs = 3,
522 .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
523 { .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
524 .args = { { Name | IN, 0 }, { Int, 1 } } },
525 { .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
526 .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
527 { .name = "linux_newstat", .ret_type = 1, .nargs = 2,
528 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
529 { .name = "linux_open", .ret_type = 1, .nargs = 3,
530 .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
531 { .name = "linux_readlink", .ret_type = 1, .nargs = 3,
532 .args = { { Name, 0 }, { Name | OUT, 1 }, { Sizet, 2 } } },
533 { .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
534 .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
535 { .name = "linux_stat64", .ret_type = 1, .nargs = 2,
536 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
538 /* CloudABI system calls. */
539 { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
540 .args = { { CloudABIClockID, 0 } } },
541 { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
542 .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
543 { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
544 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
545 { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
546 .args = { { Int, 0 } } },
547 { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
548 .args = { { CloudABIFileType, 0 } } },
549 { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
550 .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
551 { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
552 .args = { { Int, 0 } } },
553 { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
554 .args = { { Int, 0 } } },
555 { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
556 .args = { { Int, 0 }, { Int, 1 } } },
557 { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
558 .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
559 { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
560 .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
561 { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
562 .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
563 { ClouduABIFDSFlags, 2 } } },
564 { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
565 .args = { { Int, 0 } } },
566 { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
567 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
568 { CloudABIAdvice, 3 } } },
569 { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
570 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
571 { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
572 .args = { { Int, 0 }, { BinString | IN, 1 },
573 { CloudABIFileType, 3 } } },
574 { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
575 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
576 { Int, 3 }, { BinString | IN, 4 } } },
577 { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
578 .args = { { Int, 0 }, { BinString | IN, 1 },
579 { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
580 { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
581 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
583 { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
584 .args = { { Int, 0 }, { BinString | IN, 1 },
585 { BinString | OUT, 3 }, { Int, 4 } } },
586 { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
587 .args = { { Int, 0 }, { BinString | IN, 1 },
588 { Int, 3 }, { BinString | IN, 4 } } },
589 { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
590 .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
591 { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
592 .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
593 { CloudABIFSFlags, 2 } } },
594 { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
595 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
596 { CloudABIFileStat | OUT, 3 } } },
597 { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
598 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
599 { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
600 { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
601 .args = { { BinString | IN, 0 },
602 { Int, 2 }, { BinString | IN, 3 } } },
603 { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
604 .args = { { Int, 0 }, { BinString | IN, 1 },
605 { CloudABIULFlags, 3 } } },
606 { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
607 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
608 { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
609 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
610 { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
611 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
612 { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
613 { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
614 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
615 { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
616 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
617 { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
618 .args = { { Ptr, 0 }, { Int, 1 } } },
619 { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
620 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
621 { IntArray, 3 }, { Int, 4 } } },
622 { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
623 .args = { { Int, 0 } } },
624 { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
625 { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
626 .args = { { CloudABISignal, 0 } } },
627 { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
628 .args = { { BinString | OUT, 0 }, { Int, 1 } } },
629 { .name = "cloudabi_sys_sock_accept", .ret_type = 1, .nargs = 2,
630 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 } } },
631 { .name = "cloudabi_sys_sock_bind", .ret_type = 1, .nargs = 3,
632 .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
633 { .name = "cloudabi_sys_sock_connect", .ret_type = 1, .nargs = 3,
634 .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
635 { .name = "cloudabi_sys_sock_listen", .ret_type = 1, .nargs = 2,
636 .args = { { Int, 0 }, { Int, 1 } } },
637 { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
638 .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
639 { .name = "cloudabi_sys_sock_stat_get", .ret_type = 1, .nargs = 3,
640 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 },
641 { CloudABISSFlags, 2 } } },
642 { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
643 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
644 { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
648 static STAILQ_HEAD(, syscall) syscalls;
650 /* Xlat idea taken from strace */
656 #define X(a) { a, #a },
657 #define XEND { 0, NULL }
659 static struct xlat kevent_filters[] = {
660 X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
661 X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
662 X(EVFILT_PROCDESC) X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER)
663 X(EVFILT_SENDFILE) XEND
666 static struct xlat kevent_flags[] = {
667 X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
668 X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH) X(EV_FORCEONESHOT)
669 X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
672 static struct xlat kevent_user_ffctrl[] = {
673 X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
677 static struct xlat kevent_rdwr_fflags[] = {
678 X(NOTE_LOWAT) X(NOTE_FILE_POLL) XEND
681 static struct xlat kevent_vnode_fflags[] = {
682 X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB)
683 X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND
686 static struct xlat kevent_proc_fflags[] = {
687 X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR)
691 static struct xlat kevent_timer_fflags[] = {
692 X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS)
696 static struct xlat poll_flags[] = {
697 X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
698 X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
699 X(POLLWRBAND) X(POLLINIGNEOF) XEND
702 static struct xlat sigaction_flags[] = {
703 X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
704 X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
707 static struct xlat pathconf_arg[] = {
708 X(_PC_LINK_MAX) X(_PC_MAX_CANON) X(_PC_MAX_INPUT)
709 X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF)
710 X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE)
711 X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO)
712 X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS)
713 X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE)
714 X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
715 X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
716 X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
717 X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND
720 static struct xlat at_flags[] = {
721 X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW)
725 static struct xlat sysarch_ops[] = {
726 #if defined(__i386__) || defined(__amd64__)
727 X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM)
728 X(I386_VM86) X(I386_GET_FSBASE) X(I386_SET_FSBASE) X(I386_GET_GSBASE)
729 X(I386_SET_GSBASE) X(I386_GET_XFPUSTATE) X(AMD64_GET_FSBASE)
730 X(AMD64_SET_FSBASE) X(AMD64_GET_GSBASE) X(AMD64_SET_GSBASE)
731 X(AMD64_GET_XFPUSTATE)
736 static struct xlat linux_socketcall_ops[] = {
737 X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
738 X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
739 X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
740 X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
741 X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
746 #define X(a) { CLOUDABI_##a, #a },
748 static struct xlat cloudabi_advice[] = {
749 X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
750 X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
754 static struct xlat cloudabi_clockid[] = {
755 X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
756 X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
760 static struct xlat cloudabi_errno[] = {
761 X(E2BIG) X(EACCES) X(EADDRINUSE) X(EADDRNOTAVAIL)
762 X(EAFNOSUPPORT) X(EAGAIN) X(EALREADY) X(EBADF) X(EBADMSG)
763 X(EBUSY) X(ECANCELED) X(ECHILD) X(ECONNABORTED) X(ECONNREFUSED)
764 X(ECONNRESET) X(EDEADLK) X(EDESTADDRREQ) X(EDOM) X(EDQUOT)
765 X(EEXIST) X(EFAULT) X(EFBIG) X(EHOSTUNREACH) X(EIDRM) X(EILSEQ)
766 X(EINPROGRESS) X(EINTR) X(EINVAL) X(EIO) X(EISCONN) X(EISDIR)
767 X(ELOOP) X(EMFILE) X(EMLINK) X(EMSGSIZE) X(EMULTIHOP)
768 X(ENAMETOOLONG) X(ENETDOWN) X(ENETRESET) X(ENETUNREACH)
769 X(ENFILE) X(ENOBUFS) X(ENODEV) X(ENOENT) X(ENOEXEC) X(ENOLCK)
770 X(ENOLINK) X(ENOMEM) X(ENOMSG) X(ENOPROTOOPT) X(ENOSPC)
771 X(ENOSYS) X(ENOTCONN) X(ENOTDIR) X(ENOTEMPTY) X(ENOTRECOVERABLE)
772 X(ENOTSOCK) X(ENOTSUP) X(ENOTTY) X(ENXIO) X(EOVERFLOW)
773 X(EOWNERDEAD) X(EPERM) X(EPIPE) X(EPROTO) X(EPROTONOSUPPORT)
774 X(EPROTOTYPE) X(ERANGE) X(EROFS) X(ESPIPE) X(ESRCH) X(ESTALE)
775 X(ETIMEDOUT) X(ETXTBSY) X(EXDEV) X(ENOTCAPABLE)
779 static struct xlat cloudabi_fdflags[] = {
780 X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
781 X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
785 static struct xlat cloudabi_fdsflags[] = {
786 X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
790 static struct xlat cloudabi_filetype[] = {
791 X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
792 X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
793 X(FILETYPE_FIFO) X(FILETYPE_POLL) X(FILETYPE_PROCESS)
794 X(FILETYPE_REGULAR_FILE) X(FILETYPE_SHARED_MEMORY)
795 X(FILETYPE_SOCKET_DGRAM) X(FILETYPE_SOCKET_STREAM)
796 X(FILETYPE_SYMBOLIC_LINK)
800 static struct xlat cloudabi_fsflags[] = {
801 X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
802 X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
806 static struct xlat cloudabi_mflags[] = {
807 X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
811 static struct xlat cloudabi_mprot[] = {
812 X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
816 static struct xlat cloudabi_msflags[] = {
817 X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
821 static struct xlat cloudabi_oflags[] = {
822 X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
826 static struct xlat cloudabi_sdflags[] = {
827 X(SHUT_RD) X(SHUT_WR)
831 static struct xlat cloudabi_signal[] = {
832 X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
833 X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
834 X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
835 X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
836 X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
840 static struct xlat cloudabi_ssflags[] = {
841 X(SOCKSTAT_CLEAR_ERROR)
845 static struct xlat cloudabi_ssstate[] = {
846 X(SOCKSTATE_ACCEPTCONN)
850 static struct xlat cloudabi_ulflags[] = {
855 static struct xlat cloudabi_whence[] = {
856 X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
864 * Searches an xlat array for a value, and returns it if found. Otherwise
865 * return a string representation.
868 lookup(struct xlat *xlat, int val, int base)
872 for (; xlat->str != NULL; xlat++)
873 if (xlat->val == val)
877 sprintf(tmp, "0%o", val);
880 sprintf(tmp, "0x%x", val);
883 sprintf(tmp, "%u", val);
886 errx(1,"Unknown lookup base");
893 xlookup(struct xlat *xlat, int val)
896 return (lookup(xlat, val, 16));
900 * Searches an xlat array containing bitfield values. Remaining bits
901 * set after removing the known ones are printed at the end:
905 xlookup_bits(struct xlat *xlat, int val)
908 static char str[512];
912 for (; xlat->str != NULL; xlat++) {
913 if ((xlat->val & rem) == xlat->val) {
915 * Don't print the "all-bits-zero" string unless all
916 * bits are really zero.
918 if (xlat->val == 0 && val != 0)
920 len += sprintf(str + len, "%s|", xlat->str);
926 * If we have leftover bits or didn't match anything, print
930 len += sprintf(str + len, "0x%x", rem);
931 if (len && str[len - 1] == '|')
938 print_integer_arg(const char *(*decoder)(int), FILE *fp, int value)
942 str = decoder(value);
946 fprintf(fp, "%d", value);
950 print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value)
954 if (!decoder(fp, value, &rem))
955 fprintf(fp, "0x%x", rem);
957 fprintf(fp, "|0x%x", rem);
961 print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), FILE *fp,
966 if (!decoder(fp, value, &rem))
967 fprintf(fp, "0x%x", rem);
969 fprintf(fp, "|0x%x", rem);
974 * Add argument padding to subsequent system calls afater a Quad
975 * syscall arguments as needed. This used to be done by hand in the
976 * decoded_syscalls table which was ugly and error prone. It is
977 * simpler to do the fixup of offsets at initalization time than when
978 * decoding arguments.
981 quad_fixup(struct syscall *sc)
988 for (i = 0; i < sc->nargs; i++) {
989 /* This arg type is a dummy that doesn't use offset. */
990 if ((sc->args[i].type & ARG_MASK) == PipeFds)
993 assert(prev < sc->args[i].offset);
994 prev = sc->args[i].offset;
995 sc->args[i].offset += offset;
996 switch (sc->args[i].type & ARG_MASK) {
1001 * 64-bit arguments on 32-bit powerpc must be
1002 * 64-bit aligned. If the current offset is
1003 * not aligned, the calling convention inserts
1004 * a 32-bit pad argument that should be skipped.
1006 if (sc->args[i].offset % 2 == 1) {
1007 sc->args[i].offset++;
1024 STAILQ_INIT(&syscalls);
1025 for (sc = decoded_syscalls; sc->name != NULL; sc++) {
1029 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
1033 static struct syscall *
1034 find_syscall(struct procabi *abi, u_int number)
1036 struct extra_syscall *es;
1038 if (number < nitems(abi->syscalls))
1039 return (abi->syscalls[number]);
1040 STAILQ_FOREACH(es, &abi->extra_syscalls, entries) {
1041 if (es->number == number)
1048 add_syscall(struct procabi *abi, u_int number, struct syscall *sc)
1050 struct extra_syscall *es;
1052 if (number < nitems(abi->syscalls)) {
1053 assert(abi->syscalls[number] == NULL);
1054 abi->syscalls[number] = sc;
1056 es = malloc(sizeof(*es));
1058 es->number = number;
1059 STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries);
1064 * If/when the list gets big, it might be desirable to do it
1065 * as a hash table or binary search.
1068 get_syscall(struct threadinfo *t, u_int number, u_int nargs)
1075 sc = find_syscall(t->proc->abi, number);
1079 name = sysdecode_syscallname(t->proc->abi->abi, number);
1081 asprintf(&new_name, "#%d", number);
1085 STAILQ_FOREACH(sc, &syscalls, entries) {
1086 if (strcmp(name, sc->name) == 0) {
1087 add_syscall(t->proc->abi, number, sc);
1093 /* It is unknown. Add it into the list. */
1095 fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
1099 sc = calloc(1, sizeof(struct syscall));
1101 if (new_name != NULL)
1105 for (i = 0; i < nargs; i++) {
1106 sc->args[i].offset = i;
1107 /* Treat all unknown arguments as LongHex. */
1108 sc->args[i].type = LongHex;
1110 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
1111 add_syscall(t->proc->abi, number, sc);
1117 * Copy a fixed amount of bytes from the process.
1120 get_struct(pid_t pid, void *offset, void *buf, int len)
1122 struct ptrace_io_desc iorequest;
1124 iorequest.piod_op = PIOD_READ_D;
1125 iorequest.piod_offs = offset;
1126 iorequest.piod_addr = buf;
1127 iorequest.piod_len = len;
1128 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
1133 #define MAXSIZE 4096
1136 * Copy a string from the process. Note that it is
1137 * expected to be a C string, but if max is set, it will
1138 * only get that much.
1141 get_string(pid_t pid, void *addr, int max)
1143 struct ptrace_io_desc iorequest;
1145 size_t offset, size, totalsize;
1151 /* Read up to the end of the current page. */
1152 size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE);
1157 buf = malloc(totalsize);
1161 iorequest.piod_op = PIOD_READ_D;
1162 iorequest.piod_offs = (char *)addr + offset;
1163 iorequest.piod_addr = buf + offset;
1164 iorequest.piod_len = size;
1165 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
1169 if (memchr(buf + offset, '\0', size) != NULL)
1172 if (totalsize < MAXSIZE && max == 0) {
1173 size = MAXSIZE - totalsize;
1174 if (size > PAGE_SIZE)
1176 nbuf = realloc(buf, totalsize + size);
1178 buf[totalsize - 1] = '\0';
1184 buf[totalsize - 1] = '\0';
1193 static char tmp[32];
1194 const char *signame;
1196 signame = sysdecode_signal(sig);
1197 if (signame == NULL) {
1198 snprintf(tmp, sizeof(tmp), "%d", sig);
1205 print_kevent(FILE *fp, struct kevent *ke, int input)
1208 switch (ke->filter) {
1214 case EVFILT_PROCDESC:
1215 fprintf(fp, "%ju", (uintmax_t)ke->ident);
1218 fputs(strsig2(ke->ident), fp);
1221 fprintf(fp, "%p", (void *)ke->ident);
1223 fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter),
1224 xlookup_bits(kevent_flags, ke->flags));
1225 switch (ke->filter) {
1228 fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp);
1231 fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp);
1234 case EVFILT_PROCDESC:
1235 fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp);
1238 fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp);
1243 ctrl = ke->fflags & NOTE_FFCTRLMASK;
1244 data = ke->fflags & NOTE_FFLAGSMASK;
1246 fputs(xlookup(kevent_user_ffctrl, ctrl), fp);
1247 if (ke->fflags & NOTE_TRIGGER)
1248 fputs("|NOTE_TRIGGER", fp);
1250 fprintf(fp, "|%#x", data);
1252 fprintf(fp, "%#x", data);
1257 fprintf(fp, "%#x", ke->fflags);
1259 fprintf(fp, ",%#jx,%p", (uintmax_t)ke->data, ke->udata);
1263 print_utrace(FILE *fp, void *utrace_addr, size_t len)
1265 unsigned char *utrace_buffer;
1268 if (sysdecode_utrace(fp, utrace_addr, len)) {
1273 utrace_buffer = utrace_addr;
1274 fprintf(fp, "%zu:", len);
1276 fprintf(fp, " %02x", *utrace_buffer++);
1281 * Converts a syscall argument into a string. Said string is
1282 * allocated via malloc(), so needs to be free()'d. sc is
1283 * a pointer to the syscall description (see above); args is
1284 * an array of all of the system call arguments.
1287 print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
1288 struct trussinfo *trussinfo)
1295 fp = open_memstream(&tmp, &tmplen);
1296 pid = trussinfo->curthread->proc->pid;
1297 switch (sc->type & ARG_MASK) {
1299 fprintf(fp, "0x%x", (int)args[sc->offset]);
1302 fprintf(fp, "0%o", (int)args[sc->offset]);
1305 fprintf(fp, "%d", (int)args[sc->offset]);
1308 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1313 if (get_struct(pid, (void *)args[sc->offset], &val,
1315 fprintf(fp, "{ %u }", val);
1317 fprintf(fp, "0x%lx", args[sc->offset]);
1321 fprintf(fp, "0x%lx", args[sc->offset]);
1324 fprintf(fp, "%ld", args[sc->offset]);
1327 fprintf(fp, "%zu", (size_t)args[sc->offset]);
1330 /* NULL-terminated string. */
1333 tmp2 = get_string(pid, (void*)args[sc->offset], 0);
1334 fprintf(fp, "\"%s\"", tmp2);
1340 * Binary block of data that might have printable characters.
1341 * XXX If type|OUT, assume that the length is the syscall's
1342 * return value. Otherwise, assume that the length of the block
1343 * is in the next syscall argument.
1345 int max_string = trussinfo->strsize;
1346 char tmp2[max_string + 1], *tmp3;
1353 len = args[sc->offset + 1];
1356 * Don't print more than max_string characters, to avoid word
1357 * wrap. If we have to truncate put some ... after the string.
1359 if (len > max_string) {
1363 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
1365 tmp3 = malloc(len * 4 + 1);
1367 if (strvisx(tmp3, tmp2, len,
1368 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1373 fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1377 fprintf(fp, "0x%lx", args[sc->offset]);
1387 char buf[PAGE_SIZE];
1394 * Only parse argv[] and environment arrays from exec calls
1397 if (((sc->type & ARG_MASK) == ExecArgs &&
1398 (trussinfo->flags & EXECVEARGS) == 0) ||
1399 ((sc->type & ARG_MASK) == ExecEnv &&
1400 (trussinfo->flags & EXECVEENVS) == 0)) {
1401 fprintf(fp, "0x%lx", args[sc->offset]);
1406 * Read a page of pointers at a time. Punt if the top-level
1407 * pointer is not aligned. Note that the first read is of
1410 addr = args[sc->offset];
1411 if (addr % sizeof(char *) != 0) {
1412 fprintf(fp, "0x%lx", args[sc->offset]);
1416 len = PAGE_SIZE - (addr & PAGE_MASK);
1417 if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
1418 fprintf(fp, "0x%lx", args[sc->offset]);
1425 while (u.strarray[i] != NULL) {
1426 string = get_string(pid, u.strarray[i], 0);
1427 fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1432 if (i == len / sizeof(char *)) {
1435 if (get_struct(pid, (void *)addr, u.buf, len) ==
1437 fprintf(fp, ", <inval>");
1448 fprintf(fp, "%ld", args[sc->offset]);
1451 fprintf(fp, "0x%lx", args[sc->offset]);
1456 unsigned long long ll;
1458 #if _BYTE_ORDER == _LITTLE_ENDIAN
1459 ll = (unsigned long long)args[sc->offset + 1] << 32 |
1462 ll = (unsigned long long)args[sc->offset] << 32 |
1463 args[sc->offset + 1];
1465 if ((sc->type & ARG_MASK) == Quad)
1466 fprintf(fp, "%lld", ll);
1468 fprintf(fp, "0x%llx", ll);
1475 if (get_struct(pid, (void *)args[sc->offset], &val,
1477 fprintf(fp, "{ 0x%jx }", (uintmax_t)val);
1479 fprintf(fp, "0x%lx", args[sc->offset]);
1483 fprintf(fp, "0x%lx", args[sc->offset]);
1488 if (retval[0] == -1)
1490 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
1491 fprintf(fp, "\"%s\"", tmp2);
1499 cmd = args[sc->offset];
1500 temp = sysdecode_ioctlname(cmd);
1504 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1505 cmd, cmd & IOC_OUT ? "R" : "",
1506 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1507 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1508 cmd & 0xFF, IOCPARM_LEN(cmd));
1515 if (get_struct(pid, (void *)args[sc->offset], &ts,
1517 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1520 fprintf(fp, "0x%lx", args[sc->offset]);
1524 struct timespec ts[2];
1528 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
1532 for (i = 0; i < nitems(ts); i++) {
1535 switch (ts[i].tv_nsec) {
1537 fprintf(fp, "UTIME_NOW");
1540 fprintf(fp, "UTIME_OMIT");
1543 fprintf(fp, "%jd.%09ld",
1544 (intmax_t)ts[i].tv_sec,
1551 fprintf(fp, "0x%lx", args[sc->offset]);
1557 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1559 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1562 fprintf(fp, "0x%lx", args[sc->offset]);
1566 struct timeval tv[2];
1568 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1570 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1571 (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1572 (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1574 fprintf(fp, "0x%lx", args[sc->offset]);
1578 struct itimerval itv;
1580 if (get_struct(pid, (void *)args[sc->offset], &itv,
1582 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1583 (intmax_t)itv.it_interval.tv_sec,
1584 itv.it_interval.tv_usec,
1585 (intmax_t)itv.it_value.tv_sec,
1586 itv.it_value.tv_usec);
1588 fprintf(fp, "0x%lx", args[sc->offset]);
1593 struct linux_socketcall_args largs;
1595 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
1596 sizeof(largs)) != -1)
1597 fprintf(fp, "{ %s, 0x%lx }",
1598 lookup(linux_socketcall_ops, largs.what, 10),
1599 (long unsigned int)largs.args);
1601 fprintf(fp, "0x%lx", args[sc->offset]);
1606 * XXX: A Pollfd argument expects the /next/ syscall argument
1607 * to be the number of fds in the array. This matches the poll
1611 int numfds = args[sc->offset + 1];
1612 size_t bytes = sizeof(struct pollfd) * numfds;
1615 if ((pfd = malloc(bytes)) == NULL)
1616 err(1, "Cannot malloc %zu bytes for pollfd array",
1618 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
1621 for (i = 0; i < numfds; i++) {
1622 fprintf(fp, " %d/%s", pfd[i].fd,
1623 xlookup_bits(poll_flags, pfd[i].events));
1627 fprintf(fp, "0x%lx", args[sc->offset]);
1634 * XXX: A Fd_set argument expects the /first/ syscall argument
1635 * to be the number of fds in the array. This matches the
1639 int numfds = args[0];
1640 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1643 if ((fds = malloc(bytes)) == NULL)
1644 err(1, "Cannot malloc %zu bytes for fd_set array",
1646 if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
1649 for (i = 0; i < numfds; i++) {
1650 if (FD_ISSET(i, fds))
1651 fprintf(fp, " %d", i);
1655 fprintf(fp, "0x%lx", args[sc->offset]);
1660 fputs(strsig2(args[sc->offset]), fp);
1667 sig = args[sc->offset];
1668 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
1669 sizeof(ss)) == -1) {
1670 fprintf(fp, "0x%lx", args[sc->offset]);
1675 for (i = 1; i < sys_nsig; i++) {
1676 if (sigismember(&ss, i)) {
1677 fprintf(fp, "%s%s", !first ? "|" : "",
1688 print_integer_arg(sysdecode_sigprocmask_how, fp,
1692 /* XXX: Output depends on the value of the previous argument. */
1693 if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
1694 sysdecode_fcntl_arg(fp, args[sc->offset - 1],
1695 args[sc->offset], 16);
1698 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
1701 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
1704 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
1707 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
1710 print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
1713 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
1716 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
1719 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
1722 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
1725 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]);
1728 fputs(xlookup(pathconf_arg, args[sc->offset]), fp);
1731 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
1735 struct sockaddr_in *lsin;
1736 struct sockaddr_in6 *lsin6;
1737 struct sockaddr_un *sun;
1738 struct sockaddr *sa;
1742 if (args[sc->offset] == 0) {
1748 * Extract the address length from the next argument. If
1749 * this is an output sockaddr (OUT is set), then the
1750 * next argument is a pointer to a socklen_t. Otherwise
1751 * the next argument contains a socklen_t by value.
1753 if (sc->type & OUT) {
1754 if (get_struct(pid, (void *)args[sc->offset + 1],
1755 &len, sizeof(len)) == -1) {
1756 fprintf(fp, "0x%lx", args[sc->offset]);
1760 len = args[sc->offset + 1];
1762 /* If the length is too small, just bail. */
1763 if (len < sizeof(*sa)) {
1764 fprintf(fp, "0x%lx", args[sc->offset]);
1768 sa = calloc(1, len);
1769 if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) {
1771 fprintf(fp, "0x%lx", args[sc->offset]);
1775 switch (sa->sa_family) {
1777 if (len < sizeof(*lsin))
1778 goto sockaddr_short;
1779 lsin = (struct sockaddr_in *)(void *)sa;
1780 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1781 fprintf(fp, "{ AF_INET %s:%d }", addr,
1782 htons(lsin->sin_port));
1785 if (len < sizeof(*lsin6))
1786 goto sockaddr_short;
1787 lsin6 = (struct sockaddr_in6 *)(void *)sa;
1788 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1790 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1791 htons(lsin6->sin6_port));
1794 sun = (struct sockaddr_un *)sa;
1795 fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1796 (int)(len - offsetof(struct sockaddr_un, sun_path)),
1802 "{ sa_len = %d, sa_family = %d, sa_data = {",
1803 (int)sa->sa_len, (int)sa->sa_family);
1804 for (q = (u_char *)sa->sa_data;
1805 q < (u_char *)sa + len; q++)
1806 fprintf(fp, "%s 0x%02x",
1807 q == (u_char *)sa->sa_data ? "" : ",",
1815 struct sigaction sa;
1817 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
1820 if (sa.sa_handler == SIG_DFL)
1821 fputs("SIG_DFL", fp);
1822 else if (sa.sa_handler == SIG_IGN)
1823 fputs("SIG_IGN", fp);
1825 fprintf(fp, "%p", sa.sa_handler);
1826 fprintf(fp, " %s ss_t }",
1827 xlookup_bits(sigaction_flags, sa.sa_flags));
1829 fprintf(fp, "0x%lx", args[sc->offset]);
1834 * XXX XXX: The size of the array is determined by either the
1835 * next syscall argument, or by the syscall return value,
1836 * depending on which argument number we are. This matches the
1837 * kevent syscall, but luckily that's the only syscall that uses
1845 if (sc->offset == 1)
1846 numevents = args[sc->offset+1];
1847 else if (sc->offset == 3 && retval[0] != -1)
1848 numevents = retval[0];
1850 if (numevents >= 0) {
1851 bytes = sizeof(struct kevent) * numevents;
1852 if ((ke = malloc(bytes)) == NULL)
1854 "Cannot malloc %zu bytes for kevent array",
1858 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
1861 for (i = 0; i < numevents; i++) {
1863 print_kevent(fp, &ke[i], sc->offset == 1);
1867 fprintf(fp, "0x%lx", args[sc->offset]);
1875 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1879 strmode(st.st_mode, mode);
1881 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1882 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1883 (long)st.st_blksize);
1885 fprintf(fp, "0x%lx", args[sc->offset]);
1890 struct freebsd11_stat st;
1892 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1896 strmode(st.st_mode, mode);
1898 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1899 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1900 (long)st.st_blksize);
1902 fprintf(fp, "0x%lx", args[sc->offset]);
1910 if (get_struct(pid, (void *)args[sc->offset], &buf,
1911 sizeof(buf)) != -1) {
1914 bzero(fsid, sizeof(fsid));
1915 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
1916 for (i = 0; i < sizeof(buf.f_fsid); i++)
1917 snprintf(&fsid[i*2],
1918 sizeof(fsid) - (i*2), "%02x",
1919 ((u_char *)&buf.f_fsid)[i]);
1922 "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
1923 "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
1924 buf.f_mntfromname, fsid);
1926 fprintf(fp, "0x%lx", args[sc->offset]);
1933 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
1936 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
1937 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
1938 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
1939 ru.ru_inblock, ru.ru_oublock);
1941 fprintf(fp, "0x%lx", args[sc->offset]);
1947 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
1949 fprintf(fp, "{ cur=%ju,max=%ju }",
1950 rl.rlim_cur, rl.rlim_max);
1952 fprintf(fp, "0x%lx", args[sc->offset]);
1958 if (get_struct(pid, (void *)args[sc->offset], &status,
1959 sizeof(status)) != -1) {
1961 if (WIFCONTINUED(status))
1962 fputs("CONTINUED", fp);
1963 else if (WIFEXITED(status))
1964 fprintf(fp, "EXITED,val=%d",
1965 WEXITSTATUS(status));
1966 else if (WIFSIGNALED(status))
1967 fprintf(fp, "SIGNALED,sig=%s%s",
1968 strsig2(WTERMSIG(status)),
1969 WCOREDUMP(status) ? ",cored" : "");
1971 fprintf(fp, "STOPPED,sig=%s",
1972 strsig2(WTERMSIG(status)));
1975 fprintf(fp, "0x%lx", args[sc->offset]);
1979 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]);
1982 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]);
1985 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]);
1988 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]);
1991 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]);
1994 fputs(xlookup_bits(at_flags, args[sc->offset]), fp);
1997 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]);
2000 fputs(xlookup(sysarch_ops, args[sc->offset]), fp);
2004 * The pipe() system call in the kernel returns its
2005 * two file descriptors via return values. However,
2006 * the interface exposed by libc is that pipe()
2007 * accepts a pointer to an array of descriptors.
2008 * Format the output to match the libc API by printing
2009 * the returned file descriptors as a fake argument.
2011 * Overwrite the first retval to signal a successful
2014 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
2021 len = args[sc->offset + 1];
2022 utrace_addr = calloc(1, len);
2023 if (get_struct(pid, (void *)args[sc->offset],
2024 (void *)utrace_addr, len) != -1)
2025 print_utrace(fp, utrace_addr, len);
2027 fprintf(fp, "0x%lx", args[sc->offset]);
2032 int descriptors[16];
2033 unsigned long i, ndescriptors;
2036 ndescriptors = args[sc->offset + 1];
2038 if (ndescriptors > nitems(descriptors)) {
2039 ndescriptors = nitems(descriptors);
2042 if (get_struct(pid, (void *)args[sc->offset],
2043 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
2045 for (i = 0; i < ndescriptors; i++)
2046 fprintf(fp, i == 0 ? " %d" : ", %d",
2048 fprintf(fp, truncated ? ", ... }" : " }");
2050 fprintf(fp, "0x%lx", args[sc->offset]);
2054 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]);
2056 case CapFcntlRights: {
2059 if (sc->type & OUT) {
2060 if (get_struct(pid, (void *)args[sc->offset], &rights,
2061 sizeof(rights)) == -1) {
2062 fprintf(fp, "0x%lx", args[sc->offset]);
2066 rights = args[sc->offset];
2067 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights);
2071 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]);
2076 if (!sysdecode_fileflags(fp, args[sc->offset], &rem))
2077 fprintf(fp, "0x%x", rem);
2079 fprintf(fp, "|0x%x", rem);
2083 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]);
2086 print_integer_arg(sysdecode_getfsstat_mode, fp,
2090 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]);
2092 case Kldunloadflags:
2093 print_integer_arg(sysdecode_kldunload_flags, fp,
2097 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]);
2100 fprintf(fp, "%u", (socklen_t)args[sc->offset]);
2102 case Sockprotocol: {
2104 int domain, protocol;
2106 domain = args[sc->offset - 2];
2107 protocol = args[sc->offset];
2108 if (protocol == 0) {
2111 temp = sysdecode_socket_protocol(domain, protocol);
2115 fprintf(fp, "%d", protocol);
2121 print_integer_arg(sysdecode_sockopt_level, fp,
2128 level = args[sc->offset - 1];
2129 name = args[sc->offset];
2130 temp = sysdecode_sockopt_name(level, name);
2134 fprintf(fp, "%d", name);
2139 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]);
2142 cap_rights_t rights;
2144 if (get_struct(pid, (void *)args[sc->offset], &rights,
2145 sizeof(rights)) != -1) {
2147 sysdecode_cap_rights(fp, &rights);
2150 fprintf(fp, "0x%lx", args[sc->offset]);
2154 print_integer_arg(sysdecode_acltype, fp, args[sc->offset]);
2156 case Extattrnamespace:
2157 print_integer_arg(sysdecode_extattrnamespace, fp,
2161 print_integer_arg(sysdecode_minherit_inherit, fp,
2165 print_mask_arg(sysdecode_mlockall_flags, fp, args[sc->offset]);
2168 print_mask_arg(sysdecode_mount_flags, fp, args[sc->offset]);
2171 print_mask_arg(sysdecode_msync_flags, fp, args[sc->offset]);
2174 print_integer_arg(sysdecode_prio_which, fp, args[sc->offset]);
2177 print_integer_arg(sysdecode_ptrace_request, fp,
2181 if (!sysdecode_quotactl_cmd(fp, args[sc->offset]))
2182 fprintf(fp, "%#x", (int)args[sc->offset]);
2185 print_mask_arg(sysdecode_reboot_howto, fp, args[sc->offset]);
2188 print_integer_arg(sysdecode_rtprio_function, fp,
2192 print_integer_arg(sysdecode_scheduler_policy, fp,
2196 struct sched_param sp;
2198 if (get_struct(pid, (void *)args[sc->offset], &sp,
2200 fprintf(fp, "{ %d }", sp.sched_priority);
2202 fprintf(fp, "0x%lx", args[sc->offset]);
2206 case CloudABIAdvice:
2207 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
2209 case CloudABIClockID:
2210 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2212 case ClouduABIFDSFlags:
2213 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2215 case CloudABIFDStat: {
2216 cloudabi_fdstat_t fds;
2217 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds))
2219 fprintf(fp, "{ %s, ",
2220 xlookup(cloudabi_filetype, fds.fs_filetype));
2221 fprintf(fp, "%s, ... }",
2222 xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2224 fprintf(fp, "0x%lx", args[sc->offset]);
2227 case CloudABIFileStat: {
2228 cloudabi_filestat_t fsb;
2229 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb))
2231 fprintf(fp, "{ %s, %ju }",
2232 xlookup(cloudabi_filetype, fsb.st_filetype),
2233 (uintmax_t)fsb.st_size);
2235 fprintf(fp, "0x%lx", args[sc->offset]);
2238 case CloudABIFileType:
2239 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2241 case CloudABIFSFlags:
2242 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2244 case CloudABILookup:
2245 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2246 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2247 (int)args[sc->offset]);
2249 fprintf(fp, "%d", (int)args[sc->offset]);
2251 case CloudABIMFlags:
2252 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2255 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2257 case CloudABIMSFlags:
2258 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2260 case CloudABIOFlags:
2261 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2263 case CloudABISDFlags:
2264 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2266 case CloudABISignal:
2267 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2269 case CloudABISockStat: {
2270 cloudabi_sockstat_t ss;
2271 if (get_struct(pid, (void *)args[sc->offset], &ss, sizeof(ss))
2273 fprintf(fp, "%s, ", xlookup(
2274 cloudabi_errno, ss.ss_error));
2275 fprintf(fp, "%s }", xlookup_bits(
2276 cloudabi_ssstate, ss.ss_state));
2278 fprintf(fp, "0x%lx", args[sc->offset]);
2281 case CloudABISSFlags:
2282 fputs(xlookup_bits(cloudabi_ssflags, args[sc->offset]), fp);
2284 case CloudABITimestamp:
2285 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2286 args[sc->offset] % 1000000000);
2288 case CloudABIULFlags:
2289 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2291 case CloudABIWhence:
2292 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2296 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2303 * Print (to outfile) the system call and its arguments.
2306 print_syscall(struct trussinfo *trussinfo)
2308 struct threadinfo *t;
2313 t = trussinfo->curthread;
2315 name = t->cs.sc->name;
2316 nargs = t->cs.nargs;
2317 s_args = t->cs.s_args;
2319 len = print_line_prefix(trussinfo);
2320 len += fprintf(trussinfo->outfile, "%s(", name);
2322 for (i = 0; i < nargs; i++) {
2323 if (s_args[i] != NULL)
2324 len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2326 len += fprintf(trussinfo->outfile,
2327 "<missing argument>");
2328 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2331 len += fprintf(trussinfo->outfile, ")");
2332 for (i = 0; i < 6 - (len / 8); i++)
2333 fprintf(trussinfo->outfile, "\t");
2337 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
2339 struct timespec timediff;
2340 struct threadinfo *t;
2344 t = trussinfo->curthread;
2346 if (trussinfo->flags & COUNTONLY) {
2347 timespecsubt(&t->after, &t->before, &timediff);
2348 timespecadd(&sc->time, &timediff, &sc->time);
2355 print_syscall(trussinfo);
2356 fflush(trussinfo->outfile);
2358 if (retval == NULL) {
2360 * This system call resulted in the current thread's exit,
2361 * so there is no return value or error to display.
2363 fprintf(trussinfo->outfile, "\n");
2368 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi,
2370 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
2371 error == INT_MAX ? "Unknown error" : strerror(error));
2374 else if (sc->ret_type == 2) {
2377 #if _BYTE_ORDER == _LITTLE_ENDIAN
2378 off = (off_t)retval[1] << 32 | retval[0];
2380 off = (off_t)retval[0] << 32 | retval[1];
2382 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2387 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
2392 print_summary(struct trussinfo *trussinfo)
2394 struct timespec total = {0, 0};
2398 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2399 "syscall", "seconds", "calls", "errors");
2401 STAILQ_FOREACH(sc, &syscalls, entries)
2403 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2404 sc->name, (intmax_t)sc->time.tv_sec,
2405 sc->time.tv_nsec, sc->ncalls, sc->nerror);
2406 timespecadd(&total, &sc->time, &total);
2407 ncall += sc->ncalls;
2408 nerror += sc->nerror;
2410 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2411 "", "-------------", "-------", "-------");
2412 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2413 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);