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.lstat", .ret_type = 1, .nargs = 2,
152 .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } },
153 { .name = "compat11.stat", .ret_type = 1, .nargs = 2,
154 .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } },
155 { .name = "connect", .ret_type = 1, .nargs = 3,
156 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
157 { .name = "connectat", .ret_type = 1, .nargs = 4,
158 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
160 { .name = "dup", .ret_type = 1, .nargs = 1,
161 .args = { { Int, 0 } } },
162 { .name = "dup2", .ret_type = 1, .nargs = 2,
163 .args = { { Int, 0 }, { Int, 1 } } },
164 { .name = "eaccess", .ret_type = 1, .nargs = 2,
165 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
166 { .name = "execve", .ret_type = 1, .nargs = 3,
167 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
168 { ExecEnv | IN, 2 } } },
169 { .name = "exit", .ret_type = 0, .nargs = 1,
170 .args = { { Hex, 0 } } },
171 { .name = "extattr_delete_fd", .ret_type = 1, .nargs = 3,
172 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
173 { .name = "extattr_delete_file", .ret_type = 1, .nargs = 3,
174 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
175 { .name = "extattr_delete_link", .ret_type = 1, .nargs = 3,
176 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
177 { .name = "extattr_get_fd", .ret_type = 1, .nargs = 5,
178 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
179 { BinString | OUT, 3 }, { Sizet, 4 } } },
180 { .name = "extattr_get_file", .ret_type = 1, .nargs = 5,
181 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
182 { BinString | OUT, 3 }, { Sizet, 4 } } },
183 { .name = "extattr_get_link", .ret_type = 1, .nargs = 5,
184 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
185 { BinString | OUT, 3 }, { Sizet, 4 } } },
186 { .name = "extattr_list_fd", .ret_type = 1, .nargs = 4,
187 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
189 { .name = "extattr_list_file", .ret_type = 1, .nargs = 4,
190 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
192 { .name = "extattr_list_link", .ret_type = 1, .nargs = 4,
193 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
195 { .name = "extattr_set_fd", .ret_type = 1, .nargs = 5,
196 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
197 { BinString | IN, 3 }, { Sizet, 4 } } },
198 { .name = "extattr_set_file", .ret_type = 1, .nargs = 5,
199 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
200 { BinString | IN, 3 }, { Sizet, 4 } } },
201 { .name = "extattr_set_link", .ret_type = 1, .nargs = 5,
202 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
203 { BinString | IN, 3 }, { Sizet, 4 } } },
204 { .name = "extattrctl", .ret_type = 1, .nargs = 5,
205 .args = { { Name, 0 }, { Hex, 1 }, { Name, 2 },
206 { Extattrnamespace, 3 }, { Name, 4 } } },
207 { .name = "faccessat", .ret_type = 1, .nargs = 4,
208 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
210 { .name = "fchflags", .ret_type = 1, .nargs = 2,
211 .args = { { Int, 0 }, { FileFlags, 1 } } },
212 { .name = "fchmod", .ret_type = 1, .nargs = 2,
213 .args = { { Int, 0 }, { Octal, 1 } } },
214 { .name = "fchmodat", .ret_type = 1, .nargs = 4,
215 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
216 { .name = "fchown", .ret_type = 1, .nargs = 3,
217 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
218 { .name = "fchownat", .ret_type = 1, .nargs = 5,
219 .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
221 { .name = "fcntl", .ret_type = 1, .nargs = 3,
222 .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
223 { .name = "flock", .ret_type = 1, .nargs = 2,
224 .args = { { Int, 0 }, { Flockop, 1 } } },
225 { .name = "fstat", .ret_type = 1, .nargs = 2,
226 .args = { { Int, 0 }, { Stat | OUT, 1 } } },
227 { .name = "fstatat", .ret_type = 1, .nargs = 4,
228 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
230 { .name = "fstatfs", .ret_type = 1, .nargs = 2,
231 .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
232 { .name = "ftruncate", .ret_type = 1, .nargs = 2,
233 .args = { { Int | IN, 0 }, { QuadHex | IN, 1 } } },
234 { .name = "futimens", .ret_type = 1, .nargs = 2,
235 .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
236 { .name = "futimes", .ret_type = 1, .nargs = 2,
237 .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
238 { .name = "futimesat", .ret_type = 1, .nargs = 3,
239 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
240 { .name = "getdirentries", .ret_type = 1, .nargs = 4,
241 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
242 { PQuadHex | OUT, 3 } } },
243 { .name = "getfsstat", .ret_type = 1, .nargs = 3,
244 .args = { { Ptr, 0 }, { Long, 1 }, { Getfsstatmode, 2 } } },
245 { .name = "getitimer", .ret_type = 1, .nargs = 2,
246 .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
247 { .name = "getpeername", .ret_type = 1, .nargs = 3,
248 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
249 { .name = "getpgid", .ret_type = 1, .nargs = 1,
250 .args = { { Int, 0 } } },
251 { .name = "getpriority", .ret_type = 1, .nargs = 2,
252 .args = { { Priowhich, 0 }, { Int, 1 } } },
253 { .name = "getrlimit", .ret_type = 1, .nargs = 2,
254 .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
255 { .name = "getrusage", .ret_type = 1, .nargs = 2,
256 .args = { { RusageWho, 0 }, { Rusage | OUT, 1 } } },
257 { .name = "getsid", .ret_type = 1, .nargs = 1,
258 .args = { { Int, 0 } } },
259 { .name = "getsockname", .ret_type = 1, .nargs = 3,
260 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
261 { .name = "getsockopt", .ret_type = 1, .nargs = 5,
262 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
263 { Ptr | OUT, 3 }, { Ptr | OUT, 4 } } },
264 { .name = "gettimeofday", .ret_type = 1, .nargs = 2,
265 .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
266 { .name = "ioctl", .ret_type = 1, .nargs = 3,
267 .args = { { Int, 0 }, { Ioctl, 1 }, { Ptr, 2 } } },
268 { .name = "kevent", .ret_type = 1, .nargs = 6,
269 .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
270 { Int, 4 }, { Timespec, 5 } } },
271 { .name = "kill", .ret_type = 1, .nargs = 2,
272 .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
273 { .name = "kldfind", .ret_type = 1, .nargs = 1,
274 .args = { { Name | IN, 0 } } },
275 { .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
276 .args = { { Int, 0 } } },
277 { .name = "kldload", .ret_type = 1, .nargs = 1,
278 .args = { { Name | IN, 0 } } },
279 { .name = "kldnext", .ret_type = 1, .nargs = 1,
280 .args = { { Int, 0 } } },
281 { .name = "kldstat", .ret_type = 1, .nargs = 2,
282 .args = { { Int, 0 }, { Ptr, 1 } } },
283 { .name = "kldsym", .ret_type = 1, .nargs = 3,
284 .args = { { Int, 0 }, { Kldsymcmd, 1 }, { Ptr, 2 } } },
285 { .name = "kldunload", .ret_type = 1, .nargs = 1,
286 .args = { { Int, 0 } } },
287 { .name = "kldunloadf", .ret_type = 1, .nargs = 2,
288 .args = { { Int, 0 }, { Kldunloadflags, 1 } } },
289 { .name = "kse_release", .ret_type = 0, .nargs = 1,
290 .args = { { Timespec, 0 } } },
291 { .name = "lchflags", .ret_type = 1, .nargs = 2,
292 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
293 { .name = "lchmod", .ret_type = 1, .nargs = 2,
294 .args = { { Name, 0 }, { Octal, 1 } } },
295 { .name = "lchown", .ret_type = 1, .nargs = 3,
296 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
297 { .name = "link", .ret_type = 1, .nargs = 2,
298 .args = { { Name, 0 }, { Name, 1 } } },
299 { .name = "linkat", .ret_type = 1, .nargs = 5,
300 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
302 { .name = "listen", .ret_type = 1, .nargs = 2,
303 .args = { { Int, 0 }, { Int, 1 } } },
304 { .name = "lseek", .ret_type = 2, .nargs = 3,
305 .args = { { Int, 0 }, { QuadHex, 1 }, { Whence, 2 } } },
306 { .name = "lstat", .ret_type = 1, .nargs = 2,
307 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
308 { .name = "lutimes", .ret_type = 1, .nargs = 2,
309 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
310 { .name = "madvise", .ret_type = 1, .nargs = 3,
311 .args = { { Ptr, 0 }, { Sizet, 1 }, { Madvice, 2 } } },
312 { .name = "minherit", .ret_type = 1, .nargs = 3,
313 .args = { { Ptr, 0 }, { Sizet, 1 }, { Minherit, 2 } } },
314 { .name = "mkdir", .ret_type = 1, .nargs = 2,
315 .args = { { Name, 0 }, { Octal, 1 } } },
316 { .name = "mkdirat", .ret_type = 1, .nargs = 3,
317 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
318 { .name = "mkfifo", .ret_type = 1, .nargs = 2,
319 .args = { { Name, 0 }, { Octal, 1 } } },
320 { .name = "mkfifoat", .ret_type = 1, .nargs = 3,
321 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
322 { .name = "mknod", .ret_type = 1, .nargs = 3,
323 .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
324 { .name = "mknodat", .ret_type = 1, .nargs = 4,
325 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
326 { .name = "mlock", .ret_type = 1, .nargs = 2,
327 .args = { { Ptr, 0 }, { Sizet, 1 } } },
328 { .name = "mlockall", .ret_type = 1, .nargs = 1,
329 .args = { { Mlockall, 0 } } },
330 { .name = "mmap", .ret_type = 1, .nargs = 6,
331 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
332 { Int, 4 }, { QuadHex, 5 } } },
333 { .name = "modfind", .ret_type = 1, .nargs = 1,
334 .args = { { Name | IN, 0 } } },
335 { .name = "mount", .ret_type = 1, .nargs = 4,
336 .args = { { Name, 0 }, { Name, 1 }, { Mountflags, 2 }, { Ptr, 3 } } },
337 { .name = "mprotect", .ret_type = 1, .nargs = 3,
338 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 } } },
339 { .name = "msync", .ret_type = 1, .nargs = 3,
340 .args = { { Ptr, 0 }, { Sizet, 1 }, { Msync, 2 } } },
341 { .name = "munlock", .ret_type = 1, .nargs = 2,
342 .args = { { Ptr, 0 }, { Sizet, 1 } } },
343 { .name = "munmap", .ret_type = 1, .nargs = 2,
344 .args = { { Ptr, 0 }, { Sizet, 1 } } },
345 { .name = "nanosleep", .ret_type = 1, .nargs = 1,
346 .args = { { Timespec, 0 } } },
347 { .name = "nmount", .ret_type = 1, .nargs = 3,
348 .args = { { Ptr, 0 }, { UInt, 1 }, { Mountflags, 2 } } },
349 { .name = "open", .ret_type = 1, .nargs = 3,
350 .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
351 { .name = "openat", .ret_type = 1, .nargs = 4,
352 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
354 { .name = "pathconf", .ret_type = 1, .nargs = 2,
355 .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
356 { .name = "pipe", .ret_type = 1, .nargs = 1,
357 .args = { { PipeFds | OUT, 0 } } },
358 { .name = "pipe2", .ret_type = 1, .nargs = 2,
359 .args = { { Ptr, 0 }, { Pipe2, 1 } } },
360 { .name = "poll", .ret_type = 1, .nargs = 3,
361 .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
362 { .name = "posix_fadvise", .ret_type = 1, .nargs = 4,
363 .args = { { Int, 0 }, { QuadHex, 1 }, { QuadHex, 2 },
365 { .name = "posix_openpt", .ret_type = 1, .nargs = 1,
366 .args = { { Open, 0 } } },
367 { .name = "pread", .ret_type = 1, .nargs = 4,
368 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
370 { .name = "procctl", .ret_type = 1, .nargs = 4,
371 .args = { { Idtype, 0 }, { Quad, 1 }, { Procctl, 2 }, { Ptr, 3 } } },
372 { .name = "ptrace", .ret_type = 1, .nargs = 4,
373 .args = { { Ptraceop, 0 }, { Int, 1 }, { Ptr, 2 }, { Int, 3 } } },
374 { .name = "pwrite", .ret_type = 1, .nargs = 4,
375 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
377 { .name = "quotactl", .ret_type = 1, .nargs = 4,
378 .args = { { Name, 0 }, { Quotactlcmd, 1 }, { Int, 2 }, { Ptr, 3 } } },
379 { .name = "read", .ret_type = 1, .nargs = 3,
380 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 } } },
381 { .name = "readlink", .ret_type = 1, .nargs = 3,
382 .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Sizet, 2 } } },
383 { .name = "readlinkat", .ret_type = 1, .nargs = 4,
384 .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
386 { .name = "reboot", .ret_type = 1, .nargs = 1,
387 .args = { { Reboothowto, 0 } } },
388 { .name = "recvfrom", .ret_type = 1, .nargs = 6,
389 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
390 { Msgflags, 3 }, { Sockaddr | OUT, 4 },
391 { Ptr | OUT, 5 } } },
392 { .name = "recvmsg", .ret_type = 1, .nargs = 3,
393 .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
394 { .name = "rename", .ret_type = 1, .nargs = 2,
395 .args = { { Name, 0 }, { Name, 1 } } },
396 { .name = "renameat", .ret_type = 1, .nargs = 4,
397 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
398 { .name = "rfork", .ret_type = 1, .nargs = 1,
399 .args = { { Rforkflags, 0 } } },
400 { .name = "rmdir", .ret_type = 1, .nargs = 1,
401 .args = { { Name, 0 } } },
402 { .name = "rtprio", .ret_type = 1, .nargs = 3,
403 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
404 { .name = "rtprio_thread", .ret_type = 1, .nargs = 3,
405 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
406 { .name = "sched_get_priority_max", .ret_type = 1, .nargs = 1,
407 .args = { { Schedpolicy, 0 } } },
408 { .name = "sched_get_priority_min", .ret_type = 1, .nargs = 1,
409 .args = { { Schedpolicy, 0 } } },
410 { .name = "sched_getparam", .ret_type = 1, .nargs = 2,
411 .args = { { Int, 0 }, { Schedparam | OUT, 1 } } },
412 { .name = "sched_getscheduler", .ret_type = 1, .nargs = 1,
413 .args = { { Int, 0 } } },
414 { .name = "sched_rr_get_interval", .ret_type = 1, .nargs = 2,
415 .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
416 { .name = "sched_setparam", .ret_type = 1, .nargs = 2,
417 .args = { { Int, 0 }, { Schedparam, 1 } } },
418 { .name = "sched_setscheduler", .ret_type = 1, .nargs = 3,
419 .args = { { Int, 0 }, { Schedpolicy, 1 }, { Schedparam, 2 } } },
420 { .name = "sctp_generic_recvmsg", .ret_type = 1, .nargs = 7,
421 .args = { { Int, 0 }, { Ptr | IN, 1 }, { Int, 2 },
422 { Sockaddr | OUT, 3 }, { Ptr | OUT, 4 }, { Ptr | OUT, 5 },
423 { Ptr | OUT, 6 } } },
424 { .name = "sctp_generic_sendmsg", .ret_type = 1, .nargs = 7,
425 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
426 { Sockaddr | IN, 3 }, { Socklent, 4 }, { Ptr | IN, 5 },
428 { .name = "select", .ret_type = 1, .nargs = 5,
429 .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
431 { .name = "sendmsg", .ret_type = 1, .nargs = 3,
432 .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
433 { .name = "sendto", .ret_type = 1, .nargs = 6,
434 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
435 { Msgflags, 3 }, { Sockaddr | IN, 4 },
436 { Socklent | IN, 5 } } },
437 { .name = "setitimer", .ret_type = 1, .nargs = 3,
438 .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
439 { .name = "setpriority", .ret_type = 1, .nargs = 3,
440 .args = { { Priowhich, 0 }, { Int, 1 }, { Int, 2 } } },
441 { .name = "setrlimit", .ret_type = 1, .nargs = 2,
442 .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
443 { .name = "setsockopt", .ret_type = 1, .nargs = 5,
444 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
445 { Ptr | IN, 3 }, { Socklent, 4 } } },
446 { .name = "shutdown", .ret_type = 1, .nargs = 2,
447 .args = { { Int, 0 }, { Shutdown, 1 } } },
448 { .name = "sigaction", .ret_type = 1, .nargs = 3,
449 .args = { { Signal, 0 }, { Sigaction | IN, 1 },
450 { Sigaction | OUT, 2 } } },
451 { .name = "sigpending", .ret_type = 1, .nargs = 1,
452 .args = { { Sigset | OUT, 0 } } },
453 { .name = "sigprocmask", .ret_type = 1, .nargs = 3,
454 .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
455 { .name = "sigqueue", .ret_type = 1, .nargs = 3,
456 .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
457 { .name = "sigreturn", .ret_type = 1, .nargs = 1,
458 .args = { { Ptr, 0 } } },
459 { .name = "sigsuspend", .ret_type = 1, .nargs = 1,
460 .args = { { Sigset | IN, 0 } } },
461 { .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
462 .args = { { Sigset | IN, 0 }, { Ptr, 1 }, { Timespec | IN, 2 } } },
463 { .name = "sigwait", .ret_type = 1, .nargs = 2,
464 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
465 { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
466 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
467 { .name = "socket", .ret_type = 1, .nargs = 3,
468 .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Sockprotocol, 2 } } },
469 { .name = "stat", .ret_type = 1, .nargs = 2,
470 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
471 { .name = "statfs", .ret_type = 1, .nargs = 2,
472 .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } },
473 { .name = "symlink", .ret_type = 1, .nargs = 2,
474 .args = { { Name, 0 }, { Name, 1 } } },
475 { .name = "symlinkat", .ret_type = 1, .nargs = 3,
476 .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } },
477 { .name = "sysarch", .ret_type = 1, .nargs = 2,
478 .args = { { Sysarch, 0 }, { Ptr, 1 } } },
479 { .name = "thr_kill", .ret_type = 1, .nargs = 2,
480 .args = { { Long, 0 }, { Signal, 1 } } },
481 { .name = "thr_self", .ret_type = 1, .nargs = 1,
482 .args = { { Ptr, 0 } } },
483 { .name = "truncate", .ret_type = 1, .nargs = 2,
484 .args = { { Name | IN, 0 }, { QuadHex | IN, 1 } } },
487 { .name = "umount", .ret_type = 1, .nargs = 2,
488 .args = { { Name, 0 }, { Int, 2 } } },
490 { .name = "unlink", .ret_type = 1, .nargs = 1,
491 .args = { { Name, 0 } } },
492 { .name = "unlinkat", .ret_type = 1, .nargs = 3,
493 .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
494 { .name = "unmount", .ret_type = 1, .nargs = 2,
495 .args = { { Name, 0 }, { Mountflags, 1 } } },
496 { .name = "utimensat", .ret_type = 1, .nargs = 4,
497 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
499 { .name = "utimes", .ret_type = 1, .nargs = 2,
500 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
501 { .name = "utrace", .ret_type = 1, .nargs = 1,
502 .args = { { Utrace, 0 } } },
503 { .name = "wait4", .ret_type = 1, .nargs = 4,
504 .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
505 { Rusage | OUT, 3 } } },
506 { .name = "wait6", .ret_type = 1, .nargs = 6,
507 .args = { { Idtype, 0 }, { Quad, 1 }, { ExitStatus | OUT, 2 },
508 { Waitoptions, 3 }, { Rusage | OUT, 4 }, { Ptr, 5 } } },
509 { .name = "write", .ret_type = 1, .nargs = 3,
510 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 } } },
513 { .name = "linux_access", .ret_type = 1, .nargs = 2,
514 .args = { { Name, 0 }, { Accessmode, 1 } } },
515 { .name = "linux_execve", .ret_type = 1, .nargs = 3,
516 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
517 { ExecEnv | IN, 2 } } },
518 { .name = "linux_lseek", .ret_type = 2, .nargs = 3,
519 .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
520 { .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
521 .args = { { Name | IN, 0 }, { Int, 1 } } },
522 { .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
523 .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
524 { .name = "linux_newstat", .ret_type = 1, .nargs = 2,
525 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
526 { .name = "linux_open", .ret_type = 1, .nargs = 3,
527 .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
528 { .name = "linux_readlink", .ret_type = 1, .nargs = 3,
529 .args = { { Name, 0 }, { Name | OUT, 1 }, { Sizet, 2 } } },
530 { .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
531 .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
532 { .name = "linux_stat64", .ret_type = 1, .nargs = 2,
533 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
535 /* CloudABI system calls. */
536 { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
537 .args = { { CloudABIClockID, 0 } } },
538 { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
539 .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
540 { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
541 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
542 { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
543 .args = { { Int, 0 } } },
544 { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
545 .args = { { CloudABIFileType, 0 } } },
546 { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
547 .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
548 { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
549 .args = { { Int, 0 } } },
550 { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
551 .args = { { Int, 0 } } },
552 { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
553 .args = { { Int, 0 }, { Int, 1 } } },
554 { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
555 .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
556 { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
557 .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
558 { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
559 .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
560 { ClouduABIFDSFlags, 2 } } },
561 { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
562 .args = { { Int, 0 } } },
563 { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
564 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
565 { CloudABIAdvice, 3 } } },
566 { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
567 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
568 { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
569 .args = { { Int, 0 }, { BinString | IN, 1 },
570 { CloudABIFileType, 3 } } },
571 { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
572 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
573 { Int, 3 }, { BinString | IN, 4 } } },
574 { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
575 .args = { { Int, 0 }, { BinString | IN, 1 },
576 { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
577 { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
578 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
580 { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
581 .args = { { Int, 0 }, { BinString | IN, 1 },
582 { BinString | OUT, 3 }, { Int, 4 } } },
583 { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
584 .args = { { Int, 0 }, { BinString | IN, 1 },
585 { Int, 3 }, { BinString | IN, 4 } } },
586 { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
587 .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
588 { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
589 .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
590 { CloudABIFSFlags, 2 } } },
591 { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
592 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
593 { CloudABIFileStat | OUT, 3 } } },
594 { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
595 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
596 { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
597 { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
598 .args = { { BinString | IN, 0 },
599 { Int, 2 }, { BinString | IN, 3 } } },
600 { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
601 .args = { { Int, 0 }, { BinString | IN, 1 },
602 { CloudABIULFlags, 3 } } },
603 { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
604 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
605 { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
606 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
607 { .name = "cloudabi_sys_mem_lock", .ret_type = 1, .nargs = 2,
608 .args = { { Ptr, 0 }, { Int, 1 } } },
609 { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
610 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
611 { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
612 { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
613 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
614 { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
615 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
616 { .name = "cloudabi_sys_mem_unlock", .ret_type = 1, .nargs = 2,
617 .args = { { Ptr, 0 }, { Int, 1 } } },
618 { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
619 .args = { { Ptr, 0 }, { Int, 1 } } },
620 { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
621 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
622 { IntArray, 3 }, { Int, 4 } } },
623 { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
624 .args = { { Int, 0 } } },
625 { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
626 { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
627 .args = { { CloudABISignal, 0 } } },
628 { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
629 .args = { { BinString | OUT, 0 }, { Int, 1 } } },
630 { .name = "cloudabi_sys_sock_accept", .ret_type = 1, .nargs = 2,
631 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 } } },
632 { .name = "cloudabi_sys_sock_bind", .ret_type = 1, .nargs = 3,
633 .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
634 { .name = "cloudabi_sys_sock_connect", .ret_type = 1, .nargs = 3,
635 .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
636 { .name = "cloudabi_sys_sock_listen", .ret_type = 1, .nargs = 2,
637 .args = { { Int, 0 }, { Int, 1 } } },
638 { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
639 .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
640 { .name = "cloudabi_sys_sock_stat_get", .ret_type = 1, .nargs = 3,
641 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 },
642 { CloudABISSFlags, 2 } } },
643 { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
644 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
645 { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
649 static STAILQ_HEAD(, syscall) syscalls;
651 /* Xlat idea taken from strace */
657 #define X(a) { a, #a },
658 #define XEND { 0, NULL }
660 static struct xlat kevent_filters[] = {
661 X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
662 X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
663 X(EVFILT_PROCDESC) X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER)
664 X(EVFILT_SENDFILE) XEND
667 static struct xlat kevent_flags[] = {
668 X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
669 X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH) X(EV_FORCEONESHOT)
670 X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
673 static struct xlat kevent_user_ffctrl[] = {
674 X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
678 static struct xlat kevent_rdwr_fflags[] = {
679 X(NOTE_LOWAT) X(NOTE_FILE_POLL) XEND
682 static struct xlat kevent_vnode_fflags[] = {
683 X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB)
684 X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND
687 static struct xlat kevent_proc_fflags[] = {
688 X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR)
692 static struct xlat kevent_timer_fflags[] = {
693 X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS)
697 static struct xlat poll_flags[] = {
698 X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
699 X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
700 X(POLLWRBAND) X(POLLINIGNEOF) XEND
703 static struct xlat sigaction_flags[] = {
704 X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
705 X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
708 static struct xlat pathconf_arg[] = {
709 X(_PC_LINK_MAX) X(_PC_MAX_CANON) X(_PC_MAX_INPUT)
710 X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF)
711 X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE)
712 X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO)
713 X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS)
714 X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE)
715 X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
716 X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
717 X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
718 X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND
721 static struct xlat at_flags[] = {
722 X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW)
726 static struct xlat sysarch_ops[] = {
727 #if defined(__i386__) || defined(__amd64__)
728 X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM)
729 X(I386_VM86) X(I386_GET_FSBASE) X(I386_SET_FSBASE) X(I386_GET_GSBASE)
730 X(I386_SET_GSBASE) X(I386_GET_XFPUSTATE) X(AMD64_GET_FSBASE)
731 X(AMD64_SET_FSBASE) X(AMD64_GET_GSBASE) X(AMD64_SET_GSBASE)
732 X(AMD64_GET_XFPUSTATE)
737 static struct xlat linux_socketcall_ops[] = {
738 X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
739 X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
740 X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
741 X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
742 X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
747 #define X(a) { CLOUDABI_##a, #a },
749 static struct xlat cloudabi_advice[] = {
750 X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
751 X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
755 static struct xlat cloudabi_clockid[] = {
756 X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
757 X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
761 static struct xlat cloudabi_errno[] = {
762 X(E2BIG) X(EACCES) X(EADDRINUSE) X(EADDRNOTAVAIL)
763 X(EAFNOSUPPORT) X(EAGAIN) X(EALREADY) X(EBADF) X(EBADMSG)
764 X(EBUSY) X(ECANCELED) X(ECHILD) X(ECONNABORTED) X(ECONNREFUSED)
765 X(ECONNRESET) X(EDEADLK) X(EDESTADDRREQ) X(EDOM) X(EDQUOT)
766 X(EEXIST) X(EFAULT) X(EFBIG) X(EHOSTUNREACH) X(EIDRM) X(EILSEQ)
767 X(EINPROGRESS) X(EINTR) X(EINVAL) X(EIO) X(EISCONN) X(EISDIR)
768 X(ELOOP) X(EMFILE) X(EMLINK) X(EMSGSIZE) X(EMULTIHOP)
769 X(ENAMETOOLONG) X(ENETDOWN) X(ENETRESET) X(ENETUNREACH)
770 X(ENFILE) X(ENOBUFS) X(ENODEV) X(ENOENT) X(ENOEXEC) X(ENOLCK)
771 X(ENOLINK) X(ENOMEM) X(ENOMSG) X(ENOPROTOOPT) X(ENOSPC)
772 X(ENOSYS) X(ENOTCONN) X(ENOTDIR) X(ENOTEMPTY) X(ENOTRECOVERABLE)
773 X(ENOTSOCK) X(ENOTSUP) X(ENOTTY) X(ENXIO) X(EOVERFLOW)
774 X(EOWNERDEAD) X(EPERM) X(EPIPE) X(EPROTO) X(EPROTONOSUPPORT)
775 X(EPROTOTYPE) X(ERANGE) X(EROFS) X(ESPIPE) X(ESRCH) X(ESTALE)
776 X(ETIMEDOUT) X(ETXTBSY) X(EXDEV) X(ENOTCAPABLE)
780 static struct xlat cloudabi_fdflags[] = {
781 X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
782 X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
786 static struct xlat cloudabi_fdsflags[] = {
787 X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
791 static struct xlat cloudabi_filetype[] = {
792 X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
793 X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
794 X(FILETYPE_FIFO) X(FILETYPE_POLL) X(FILETYPE_PROCESS)
795 X(FILETYPE_REGULAR_FILE) X(FILETYPE_SHARED_MEMORY)
796 X(FILETYPE_SOCKET_DGRAM) X(FILETYPE_SOCKET_SEQPACKET)
797 X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK)
801 static struct xlat cloudabi_fsflags[] = {
802 X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
803 X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
807 static struct xlat cloudabi_mflags[] = {
808 X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
812 static struct xlat cloudabi_mprot[] = {
813 X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
817 static struct xlat cloudabi_msflags[] = {
818 X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
822 static struct xlat cloudabi_oflags[] = {
823 X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
827 static struct xlat cloudabi_sa_family[] = {
828 X(AF_UNSPEC) X(AF_INET) X(AF_INET6) X(AF_UNIX)
832 static struct xlat cloudabi_sdflags[] = {
833 X(SHUT_RD) X(SHUT_WR)
837 static struct xlat cloudabi_signal[] = {
838 X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
839 X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
840 X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
841 X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
842 X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
846 static struct xlat cloudabi_ssflags[] = {
847 X(SOCKSTAT_CLEAR_ERROR)
851 static struct xlat cloudabi_ssstate[] = {
852 X(SOCKSTATE_ACCEPTCONN)
856 static struct xlat cloudabi_ulflags[] = {
861 static struct xlat cloudabi_whence[] = {
862 X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
870 * Searches an xlat array for a value, and returns it if found. Otherwise
871 * return a string representation.
874 lookup(struct xlat *xlat, int val, int base)
878 for (; xlat->str != NULL; xlat++)
879 if (xlat->val == val)
883 sprintf(tmp, "0%o", val);
886 sprintf(tmp, "0x%x", val);
889 sprintf(tmp, "%u", val);
892 errx(1,"Unknown lookup base");
899 xlookup(struct xlat *xlat, int val)
902 return (lookup(xlat, val, 16));
906 * Searches an xlat array containing bitfield values. Remaining bits
907 * set after removing the known ones are printed at the end:
911 xlookup_bits(struct xlat *xlat, int val)
914 static char str[512];
918 for (; xlat->str != NULL; xlat++) {
919 if ((xlat->val & rem) == xlat->val) {
921 * Don't print the "all-bits-zero" string unless all
922 * bits are really zero.
924 if (xlat->val == 0 && val != 0)
926 len += sprintf(str + len, "%s|", xlat->str);
932 * If we have leftover bits or didn't match anything, print
936 len += sprintf(str + len, "0x%x", rem);
937 if (len && str[len - 1] == '|')
944 print_integer_arg(const char *(*decoder)(int), FILE *fp, int value)
948 str = decoder(value);
952 fprintf(fp, "%d", value);
956 print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value)
960 if (!decoder(fp, value, &rem))
961 fprintf(fp, "0x%x", rem);
963 fprintf(fp, "|0x%x", rem);
967 print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), FILE *fp,
972 if (!decoder(fp, value, &rem))
973 fprintf(fp, "0x%x", rem);
975 fprintf(fp, "|0x%x", rem);
980 * Add argument padding to subsequent system calls afater a Quad
981 * syscall arguments as needed. This used to be done by hand in the
982 * decoded_syscalls table which was ugly and error prone. It is
983 * simpler to do the fixup of offsets at initalization time than when
984 * decoding arguments.
987 quad_fixup(struct syscall *sc)
994 for (i = 0; i < sc->nargs; i++) {
995 /* This arg type is a dummy that doesn't use offset. */
996 if ((sc->args[i].type & ARG_MASK) == PipeFds)
999 assert(prev < sc->args[i].offset);
1000 prev = sc->args[i].offset;
1001 sc->args[i].offset += offset;
1002 switch (sc->args[i].type & ARG_MASK) {
1007 * 64-bit arguments on 32-bit powerpc must be
1008 * 64-bit aligned. If the current offset is
1009 * not aligned, the calling convention inserts
1010 * a 32-bit pad argument that should be skipped.
1012 if (sc->args[i].offset % 2 == 1) {
1013 sc->args[i].offset++;
1030 STAILQ_INIT(&syscalls);
1031 for (sc = decoded_syscalls; sc->name != NULL; sc++) {
1035 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
1039 static struct syscall *
1040 find_syscall(struct procabi *abi, u_int number)
1042 struct extra_syscall *es;
1044 if (number < nitems(abi->syscalls))
1045 return (abi->syscalls[number]);
1046 STAILQ_FOREACH(es, &abi->extra_syscalls, entries) {
1047 if (es->number == number)
1054 add_syscall(struct procabi *abi, u_int number, struct syscall *sc)
1056 struct extra_syscall *es;
1058 if (number < nitems(abi->syscalls)) {
1059 assert(abi->syscalls[number] == NULL);
1060 abi->syscalls[number] = sc;
1062 es = malloc(sizeof(*es));
1064 es->number = number;
1065 STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries);
1070 * If/when the list gets big, it might be desirable to do it
1071 * as a hash table or binary search.
1074 get_syscall(struct threadinfo *t, u_int number, u_int nargs)
1081 sc = find_syscall(t->proc->abi, number);
1085 name = sysdecode_syscallname(t->proc->abi->abi, number);
1087 asprintf(&new_name, "#%d", number);
1091 STAILQ_FOREACH(sc, &syscalls, entries) {
1092 if (strcmp(name, sc->name) == 0) {
1093 add_syscall(t->proc->abi, number, sc);
1099 /* It is unknown. Add it into the list. */
1101 fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
1105 sc = calloc(1, sizeof(struct syscall));
1107 if (new_name != NULL)
1111 for (i = 0; i < nargs; i++) {
1112 sc->args[i].offset = i;
1113 /* Treat all unknown arguments as LongHex. */
1114 sc->args[i].type = LongHex;
1116 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
1117 add_syscall(t->proc->abi, number, sc);
1123 * Copy a fixed amount of bytes from the process.
1126 get_struct(pid_t pid, void *offset, void *buf, int len)
1128 struct ptrace_io_desc iorequest;
1130 iorequest.piod_op = PIOD_READ_D;
1131 iorequest.piod_offs = offset;
1132 iorequest.piod_addr = buf;
1133 iorequest.piod_len = len;
1134 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
1139 #define MAXSIZE 4096
1142 * Copy a string from the process. Note that it is
1143 * expected to be a C string, but if max is set, it will
1144 * only get that much.
1147 get_string(pid_t pid, void *addr, int max)
1149 struct ptrace_io_desc iorequest;
1151 size_t offset, size, totalsize;
1157 /* Read up to the end of the current page. */
1158 size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE);
1163 buf = malloc(totalsize);
1167 iorequest.piod_op = PIOD_READ_D;
1168 iorequest.piod_offs = (char *)addr + offset;
1169 iorequest.piod_addr = buf + offset;
1170 iorequest.piod_len = size;
1171 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
1175 if (memchr(buf + offset, '\0', size) != NULL)
1178 if (totalsize < MAXSIZE && max == 0) {
1179 size = MAXSIZE - totalsize;
1180 if (size > PAGE_SIZE)
1182 nbuf = realloc(buf, totalsize + size);
1184 buf[totalsize - 1] = '\0';
1190 buf[totalsize - 1] = '\0';
1199 static char tmp[32];
1200 const char *signame;
1202 signame = sysdecode_signal(sig);
1203 if (signame == NULL) {
1204 snprintf(tmp, sizeof(tmp), "%d", sig);
1211 print_kevent(FILE *fp, struct kevent *ke, int input)
1214 switch (ke->filter) {
1220 case EVFILT_PROCDESC:
1221 fprintf(fp, "%ju", (uintmax_t)ke->ident);
1224 fputs(strsig2(ke->ident), fp);
1227 fprintf(fp, "%p", (void *)ke->ident);
1229 fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter),
1230 xlookup_bits(kevent_flags, ke->flags));
1231 switch (ke->filter) {
1234 fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp);
1237 fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp);
1240 case EVFILT_PROCDESC:
1241 fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp);
1244 fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp);
1249 ctrl = ke->fflags & NOTE_FFCTRLMASK;
1250 data = ke->fflags & NOTE_FFLAGSMASK;
1252 fputs(xlookup(kevent_user_ffctrl, ctrl), fp);
1253 if (ke->fflags & NOTE_TRIGGER)
1254 fputs("|NOTE_TRIGGER", fp);
1256 fprintf(fp, "|%#x", data);
1258 fprintf(fp, "%#x", data);
1263 fprintf(fp, "%#x", ke->fflags);
1265 fprintf(fp, ",%#jx,%p", (uintmax_t)ke->data, ke->udata);
1269 print_utrace(FILE *fp, void *utrace_addr, size_t len)
1271 unsigned char *utrace_buffer;
1274 if (sysdecode_utrace(fp, utrace_addr, len)) {
1279 utrace_buffer = utrace_addr;
1280 fprintf(fp, "%zu:", len);
1282 fprintf(fp, " %02x", *utrace_buffer++);
1287 * Converts a syscall argument into a string. Said string is
1288 * allocated via malloc(), so needs to be free()'d. sc is
1289 * a pointer to the syscall description (see above); args is
1290 * an array of all of the system call arguments.
1293 print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
1294 struct trussinfo *trussinfo)
1301 fp = open_memstream(&tmp, &tmplen);
1302 pid = trussinfo->curthread->proc->pid;
1303 switch (sc->type & ARG_MASK) {
1305 fprintf(fp, "0x%x", (int)args[sc->offset]);
1308 fprintf(fp, "0%o", (int)args[sc->offset]);
1311 fprintf(fp, "%d", (int)args[sc->offset]);
1314 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1319 if (get_struct(pid, (void *)args[sc->offset], &val,
1321 fprintf(fp, "{ %u }", val);
1323 fprintf(fp, "0x%lx", args[sc->offset]);
1327 fprintf(fp, "0x%lx", args[sc->offset]);
1330 fprintf(fp, "%ld", args[sc->offset]);
1333 fprintf(fp, "%zu", (size_t)args[sc->offset]);
1336 /* NULL-terminated string. */
1339 tmp2 = get_string(pid, (void*)args[sc->offset], 0);
1340 fprintf(fp, "\"%s\"", tmp2);
1346 * Binary block of data that might have printable characters.
1347 * XXX If type|OUT, assume that the length is the syscall's
1348 * return value. Otherwise, assume that the length of the block
1349 * is in the next syscall argument.
1351 int max_string = trussinfo->strsize;
1352 char tmp2[max_string + 1], *tmp3;
1359 len = args[sc->offset + 1];
1362 * Don't print more than max_string characters, to avoid word
1363 * wrap. If we have to truncate put some ... after the string.
1365 if (len > max_string) {
1369 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
1371 tmp3 = malloc(len * 4 + 1);
1373 if (strvisx(tmp3, tmp2, len,
1374 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1379 fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1383 fprintf(fp, "0x%lx", args[sc->offset]);
1393 char buf[PAGE_SIZE];
1400 * Only parse argv[] and environment arrays from exec calls
1403 if (((sc->type & ARG_MASK) == ExecArgs &&
1404 (trussinfo->flags & EXECVEARGS) == 0) ||
1405 ((sc->type & ARG_MASK) == ExecEnv &&
1406 (trussinfo->flags & EXECVEENVS) == 0)) {
1407 fprintf(fp, "0x%lx", args[sc->offset]);
1412 * Read a page of pointers at a time. Punt if the top-level
1413 * pointer is not aligned. Note that the first read is of
1416 addr = args[sc->offset];
1417 if (addr % sizeof(char *) != 0) {
1418 fprintf(fp, "0x%lx", args[sc->offset]);
1422 len = PAGE_SIZE - (addr & PAGE_MASK);
1423 if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
1424 fprintf(fp, "0x%lx", args[sc->offset]);
1431 while (u.strarray[i] != NULL) {
1432 string = get_string(pid, u.strarray[i], 0);
1433 fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1438 if (i == len / sizeof(char *)) {
1441 if (get_struct(pid, (void *)addr, u.buf, len) ==
1443 fprintf(fp, ", <inval>");
1454 fprintf(fp, "%ld", args[sc->offset]);
1457 fprintf(fp, "0x%lx", args[sc->offset]);
1462 unsigned long long ll;
1464 #if _BYTE_ORDER == _LITTLE_ENDIAN
1465 ll = (unsigned long long)args[sc->offset + 1] << 32 |
1468 ll = (unsigned long long)args[sc->offset] << 32 |
1469 args[sc->offset + 1];
1471 if ((sc->type & ARG_MASK) == Quad)
1472 fprintf(fp, "%lld", ll);
1474 fprintf(fp, "0x%llx", ll);
1481 if (get_struct(pid, (void *)args[sc->offset], &val,
1483 fprintf(fp, "{ 0x%jx }", (uintmax_t)val);
1485 fprintf(fp, "0x%lx", args[sc->offset]);
1489 fprintf(fp, "0x%lx", args[sc->offset]);
1494 if (retval[0] == -1)
1496 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
1497 fprintf(fp, "\"%s\"", tmp2);
1505 cmd = args[sc->offset];
1506 temp = sysdecode_ioctlname(cmd);
1510 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1511 cmd, cmd & IOC_OUT ? "R" : "",
1512 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1513 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1514 cmd & 0xFF, IOCPARM_LEN(cmd));
1521 if (get_struct(pid, (void *)args[sc->offset], &ts,
1523 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1526 fprintf(fp, "0x%lx", args[sc->offset]);
1530 struct timespec ts[2];
1534 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
1538 for (i = 0; i < nitems(ts); i++) {
1541 switch (ts[i].tv_nsec) {
1543 fprintf(fp, "UTIME_NOW");
1546 fprintf(fp, "UTIME_OMIT");
1549 fprintf(fp, "%jd.%09ld",
1550 (intmax_t)ts[i].tv_sec,
1557 fprintf(fp, "0x%lx", args[sc->offset]);
1563 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1565 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1568 fprintf(fp, "0x%lx", args[sc->offset]);
1572 struct timeval tv[2];
1574 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1576 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1577 (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1578 (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1580 fprintf(fp, "0x%lx", args[sc->offset]);
1584 struct itimerval itv;
1586 if (get_struct(pid, (void *)args[sc->offset], &itv,
1588 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1589 (intmax_t)itv.it_interval.tv_sec,
1590 itv.it_interval.tv_usec,
1591 (intmax_t)itv.it_value.tv_sec,
1592 itv.it_value.tv_usec);
1594 fprintf(fp, "0x%lx", args[sc->offset]);
1599 struct linux_socketcall_args largs;
1601 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
1602 sizeof(largs)) != -1)
1603 fprintf(fp, "{ %s, 0x%lx }",
1604 lookup(linux_socketcall_ops, largs.what, 10),
1605 (long unsigned int)largs.args);
1607 fprintf(fp, "0x%lx", args[sc->offset]);
1612 * XXX: A Pollfd argument expects the /next/ syscall argument
1613 * to be the number of fds in the array. This matches the poll
1617 int numfds = args[sc->offset + 1];
1618 size_t bytes = sizeof(struct pollfd) * numfds;
1621 if ((pfd = malloc(bytes)) == NULL)
1622 err(1, "Cannot malloc %zu bytes for pollfd array",
1624 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
1627 for (i = 0; i < numfds; i++) {
1628 fprintf(fp, " %d/%s", pfd[i].fd,
1629 xlookup_bits(poll_flags, pfd[i].events));
1633 fprintf(fp, "0x%lx", args[sc->offset]);
1640 * XXX: A Fd_set argument expects the /first/ syscall argument
1641 * to be the number of fds in the array. This matches the
1645 int numfds = args[0];
1646 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1649 if ((fds = malloc(bytes)) == NULL)
1650 err(1, "Cannot malloc %zu bytes for fd_set array",
1652 if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
1655 for (i = 0; i < numfds; i++) {
1656 if (FD_ISSET(i, fds))
1657 fprintf(fp, " %d", i);
1661 fprintf(fp, "0x%lx", args[sc->offset]);
1666 fputs(strsig2(args[sc->offset]), fp);
1673 sig = args[sc->offset];
1674 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
1675 sizeof(ss)) == -1) {
1676 fprintf(fp, "0x%lx", args[sc->offset]);
1681 for (i = 1; i < sys_nsig; i++) {
1682 if (sigismember(&ss, i)) {
1683 fprintf(fp, "%s%s", !first ? "|" : "",
1694 print_integer_arg(sysdecode_sigprocmask_how, fp,
1698 /* XXX: Output depends on the value of the previous argument. */
1699 if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
1700 sysdecode_fcntl_arg(fp, args[sc->offset - 1],
1701 args[sc->offset], 16);
1704 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
1707 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
1710 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
1713 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
1716 print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
1719 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
1722 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
1725 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
1728 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
1731 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]);
1734 fputs(xlookup(pathconf_arg, args[sc->offset]), fp);
1737 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
1741 struct sockaddr_in *lsin;
1742 struct sockaddr_in6 *lsin6;
1743 struct sockaddr_un *sun;
1744 struct sockaddr *sa;
1748 if (args[sc->offset] == 0) {
1754 * Extract the address length from the next argument. If
1755 * this is an output sockaddr (OUT is set), then the
1756 * next argument is a pointer to a socklen_t. Otherwise
1757 * the next argument contains a socklen_t by value.
1759 if (sc->type & OUT) {
1760 if (get_struct(pid, (void *)args[sc->offset + 1],
1761 &len, sizeof(len)) == -1) {
1762 fprintf(fp, "0x%lx", args[sc->offset]);
1766 len = args[sc->offset + 1];
1768 /* If the length is too small, just bail. */
1769 if (len < sizeof(*sa)) {
1770 fprintf(fp, "0x%lx", args[sc->offset]);
1774 sa = calloc(1, len);
1775 if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) {
1777 fprintf(fp, "0x%lx", args[sc->offset]);
1781 switch (sa->sa_family) {
1783 if (len < sizeof(*lsin))
1784 goto sockaddr_short;
1785 lsin = (struct sockaddr_in *)(void *)sa;
1786 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1787 fprintf(fp, "{ AF_INET %s:%d }", addr,
1788 htons(lsin->sin_port));
1791 if (len < sizeof(*lsin6))
1792 goto sockaddr_short;
1793 lsin6 = (struct sockaddr_in6 *)(void *)sa;
1794 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1796 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1797 htons(lsin6->sin6_port));
1800 sun = (struct sockaddr_un *)sa;
1801 fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1802 (int)(len - offsetof(struct sockaddr_un, sun_path)),
1808 "{ sa_len = %d, sa_family = %d, sa_data = {",
1809 (int)sa->sa_len, (int)sa->sa_family);
1810 for (q = (u_char *)sa->sa_data;
1811 q < (u_char *)sa + len; q++)
1812 fprintf(fp, "%s 0x%02x",
1813 q == (u_char *)sa->sa_data ? "" : ",",
1821 struct sigaction sa;
1823 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
1826 if (sa.sa_handler == SIG_DFL)
1827 fputs("SIG_DFL", fp);
1828 else if (sa.sa_handler == SIG_IGN)
1829 fputs("SIG_IGN", fp);
1831 fprintf(fp, "%p", sa.sa_handler);
1832 fprintf(fp, " %s ss_t }",
1833 xlookup_bits(sigaction_flags, sa.sa_flags));
1835 fprintf(fp, "0x%lx", args[sc->offset]);
1840 * XXX XXX: The size of the array is determined by either the
1841 * next syscall argument, or by the syscall return value,
1842 * depending on which argument number we are. This matches the
1843 * kevent syscall, but luckily that's the only syscall that uses
1851 if (sc->offset == 1)
1852 numevents = args[sc->offset+1];
1853 else if (sc->offset == 3 && retval[0] != -1)
1854 numevents = retval[0];
1856 if (numevents >= 0) {
1857 bytes = sizeof(struct kevent) * numevents;
1858 if ((ke = malloc(bytes)) == NULL)
1860 "Cannot malloc %zu bytes for kevent array",
1864 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
1867 for (i = 0; i < numevents; i++) {
1869 print_kevent(fp, &ke[i], sc->offset == 1);
1873 fprintf(fp, "0x%lx", args[sc->offset]);
1881 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1885 strmode(st.st_mode, mode);
1887 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1888 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1889 (long)st.st_blksize);
1891 fprintf(fp, "0x%lx", args[sc->offset]);
1896 struct freebsd11_stat st;
1898 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1902 strmode(st.st_mode, mode);
1904 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1905 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1906 (long)st.st_blksize);
1908 fprintf(fp, "0x%lx", args[sc->offset]);
1916 if (get_struct(pid, (void *)args[sc->offset], &buf,
1917 sizeof(buf)) != -1) {
1920 bzero(fsid, sizeof(fsid));
1921 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
1922 for (i = 0; i < sizeof(buf.f_fsid); i++)
1923 snprintf(&fsid[i*2],
1924 sizeof(fsid) - (i*2), "%02x",
1925 ((u_char *)&buf.f_fsid)[i]);
1928 "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
1929 "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
1930 buf.f_mntfromname, fsid);
1932 fprintf(fp, "0x%lx", args[sc->offset]);
1939 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
1942 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
1943 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
1944 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
1945 ru.ru_inblock, ru.ru_oublock);
1947 fprintf(fp, "0x%lx", args[sc->offset]);
1953 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
1955 fprintf(fp, "{ cur=%ju,max=%ju }",
1956 rl.rlim_cur, rl.rlim_max);
1958 fprintf(fp, "0x%lx", args[sc->offset]);
1964 if (get_struct(pid, (void *)args[sc->offset], &status,
1965 sizeof(status)) != -1) {
1967 if (WIFCONTINUED(status))
1968 fputs("CONTINUED", fp);
1969 else if (WIFEXITED(status))
1970 fprintf(fp, "EXITED,val=%d",
1971 WEXITSTATUS(status));
1972 else if (WIFSIGNALED(status))
1973 fprintf(fp, "SIGNALED,sig=%s%s",
1974 strsig2(WTERMSIG(status)),
1975 WCOREDUMP(status) ? ",cored" : "");
1977 fprintf(fp, "STOPPED,sig=%s",
1978 strsig2(WTERMSIG(status)));
1981 fprintf(fp, "0x%lx", args[sc->offset]);
1985 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]);
1988 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]);
1991 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]);
1994 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]);
1997 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]);
2000 fputs(xlookup_bits(at_flags, args[sc->offset]), fp);
2003 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]);
2006 fputs(xlookup(sysarch_ops, args[sc->offset]), fp);
2010 * The pipe() system call in the kernel returns its
2011 * two file descriptors via return values. However,
2012 * the interface exposed by libc is that pipe()
2013 * accepts a pointer to an array of descriptors.
2014 * Format the output to match the libc API by printing
2015 * the returned file descriptors as a fake argument.
2017 * Overwrite the first retval to signal a successful
2020 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
2027 len = args[sc->offset + 1];
2028 utrace_addr = calloc(1, len);
2029 if (get_struct(pid, (void *)args[sc->offset],
2030 (void *)utrace_addr, len) != -1)
2031 print_utrace(fp, utrace_addr, len);
2033 fprintf(fp, "0x%lx", args[sc->offset]);
2038 int descriptors[16];
2039 unsigned long i, ndescriptors;
2042 ndescriptors = args[sc->offset + 1];
2044 if (ndescriptors > nitems(descriptors)) {
2045 ndescriptors = nitems(descriptors);
2048 if (get_struct(pid, (void *)args[sc->offset],
2049 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
2051 for (i = 0; i < ndescriptors; i++)
2052 fprintf(fp, i == 0 ? " %d" : ", %d",
2054 fprintf(fp, truncated ? ", ... }" : " }");
2056 fprintf(fp, "0x%lx", args[sc->offset]);
2060 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]);
2062 case CapFcntlRights: {
2065 if (sc->type & OUT) {
2066 if (get_struct(pid, (void *)args[sc->offset], &rights,
2067 sizeof(rights)) == -1) {
2068 fprintf(fp, "0x%lx", args[sc->offset]);
2072 rights = args[sc->offset];
2073 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights);
2077 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]);
2082 if (!sysdecode_fileflags(fp, args[sc->offset], &rem))
2083 fprintf(fp, "0x%x", rem);
2085 fprintf(fp, "|0x%x", rem);
2089 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]);
2092 print_integer_arg(sysdecode_getfsstat_mode, fp,
2096 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]);
2098 case Kldunloadflags:
2099 print_integer_arg(sysdecode_kldunload_flags, fp,
2103 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]);
2106 fprintf(fp, "%u", (socklen_t)args[sc->offset]);
2108 case Sockprotocol: {
2110 int domain, protocol;
2112 domain = args[sc->offset - 2];
2113 protocol = args[sc->offset];
2114 if (protocol == 0) {
2117 temp = sysdecode_socket_protocol(domain, protocol);
2121 fprintf(fp, "%d", protocol);
2127 print_integer_arg(sysdecode_sockopt_level, fp,
2134 level = args[sc->offset - 1];
2135 name = args[sc->offset];
2136 temp = sysdecode_sockopt_name(level, name);
2140 fprintf(fp, "%d", name);
2145 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]);
2148 cap_rights_t rights;
2150 if (get_struct(pid, (void *)args[sc->offset], &rights,
2151 sizeof(rights)) != -1) {
2153 sysdecode_cap_rights(fp, &rights);
2156 fprintf(fp, "0x%lx", args[sc->offset]);
2160 print_integer_arg(sysdecode_acltype, fp, args[sc->offset]);
2162 case Extattrnamespace:
2163 print_integer_arg(sysdecode_extattrnamespace, fp,
2167 print_integer_arg(sysdecode_minherit_inherit, fp,
2171 print_mask_arg(sysdecode_mlockall_flags, fp, args[sc->offset]);
2174 print_mask_arg(sysdecode_mount_flags, fp, args[sc->offset]);
2177 print_mask_arg(sysdecode_msync_flags, fp, args[sc->offset]);
2180 print_integer_arg(sysdecode_prio_which, fp, args[sc->offset]);
2183 print_integer_arg(sysdecode_ptrace_request, fp,
2187 if (!sysdecode_quotactl_cmd(fp, args[sc->offset]))
2188 fprintf(fp, "%#x", (int)args[sc->offset]);
2191 print_mask_arg(sysdecode_reboot_howto, fp, args[sc->offset]);
2194 print_integer_arg(sysdecode_rtprio_function, fp,
2198 print_integer_arg(sysdecode_scheduler_policy, fp,
2202 struct sched_param sp;
2204 if (get_struct(pid, (void *)args[sc->offset], &sp,
2206 fprintf(fp, "{ %d }", sp.sched_priority);
2208 fprintf(fp, "0x%lx", args[sc->offset]);
2212 case CloudABIAdvice:
2213 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
2215 case CloudABIClockID:
2216 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2218 case ClouduABIFDSFlags:
2219 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2221 case CloudABIFDStat: {
2222 cloudabi_fdstat_t fds;
2223 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds))
2225 fprintf(fp, "{ %s, ",
2226 xlookup(cloudabi_filetype, fds.fs_filetype));
2227 fprintf(fp, "%s, ... }",
2228 xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2230 fprintf(fp, "0x%lx", args[sc->offset]);
2233 case CloudABIFileStat: {
2234 cloudabi_filestat_t fsb;
2235 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb))
2237 fprintf(fp, "{ %s, %ju }",
2238 xlookup(cloudabi_filetype, fsb.st_filetype),
2239 (uintmax_t)fsb.st_size);
2241 fprintf(fp, "0x%lx", args[sc->offset]);
2244 case CloudABIFileType:
2245 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2247 case CloudABIFSFlags:
2248 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2250 case CloudABILookup:
2251 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2252 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2253 (int)args[sc->offset]);
2255 fprintf(fp, "%d", (int)args[sc->offset]);
2257 case CloudABIMFlags:
2258 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2261 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2263 case CloudABIMSFlags:
2264 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2266 case CloudABIOFlags:
2267 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2269 case CloudABISDFlags:
2270 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2272 case CloudABISignal:
2273 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2275 case CloudABISockStat: {
2276 cloudabi_sockstat_t ss;
2277 if (get_struct(pid, (void *)args[sc->offset], &ss, sizeof(ss))
2279 fprintf(fp, "{ %s, ", xlookup(
2280 cloudabi_sa_family, ss.ss_sockname.sa_family));
2281 fprintf(fp, "%s, ", xlookup(
2282 cloudabi_sa_family, ss.ss_peername.sa_family));
2283 fprintf(fp, "%s, ", xlookup(
2284 cloudabi_errno, ss.ss_error));
2285 fprintf(fp, "%s }", xlookup_bits(
2286 cloudabi_ssstate, ss.ss_state));
2288 fprintf(fp, "0x%lx", args[sc->offset]);
2291 case CloudABISSFlags:
2292 fputs(xlookup_bits(cloudabi_ssflags, args[sc->offset]), fp);
2294 case CloudABITimestamp:
2295 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2296 args[sc->offset] % 1000000000);
2298 case CloudABIULFlags:
2299 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2301 case CloudABIWhence:
2302 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2306 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2313 * Print (to outfile) the system call and its arguments.
2316 print_syscall(struct trussinfo *trussinfo)
2318 struct threadinfo *t;
2323 t = trussinfo->curthread;
2325 name = t->cs.sc->name;
2326 nargs = t->cs.nargs;
2327 s_args = t->cs.s_args;
2329 len = print_line_prefix(trussinfo);
2330 len += fprintf(trussinfo->outfile, "%s(", name);
2332 for (i = 0; i < nargs; i++) {
2333 if (s_args[i] != NULL)
2334 len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2336 len += fprintf(trussinfo->outfile,
2337 "<missing argument>");
2338 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2341 len += fprintf(trussinfo->outfile, ")");
2342 for (i = 0; i < 6 - (len / 8); i++)
2343 fprintf(trussinfo->outfile, "\t");
2347 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
2349 struct timespec timediff;
2350 struct threadinfo *t;
2354 t = trussinfo->curthread;
2356 if (trussinfo->flags & COUNTONLY) {
2357 timespecsubt(&t->after, &t->before, &timediff);
2358 timespecadd(&sc->time, &timediff, &sc->time);
2365 print_syscall(trussinfo);
2366 fflush(trussinfo->outfile);
2368 if (retval == NULL) {
2370 * This system call resulted in the current thread's exit,
2371 * so there is no return value or error to display.
2373 fprintf(trussinfo->outfile, "\n");
2378 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi,
2380 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
2381 error == INT_MAX ? "Unknown error" : strerror(error));
2384 else if (sc->ret_type == 2) {
2387 #if _BYTE_ORDER == _LITTLE_ENDIAN
2388 off = (off_t)retval[1] << 32 | retval[0];
2390 off = (off_t)retval[0] << 32 | retval[1];
2392 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2397 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
2402 print_summary(struct trussinfo *trussinfo)
2404 struct timespec total = {0, 0};
2408 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2409 "syscall", "seconds", "calls", "errors");
2411 STAILQ_FOREACH(sc, &syscalls, entries)
2413 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2414 sc->name, (intmax_t)sc->time.tv_sec,
2415 sc->time.tv_nsec, sc->ncalls, sc->nerror);
2416 timespecadd(&total, &sc->time, &total);
2417 ncall += sc->ncalls;
2418 nerror += sc->nerror;
2420 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2421 "", "-------------", "-------", "-------");
2422 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2423 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);