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 = "thr_set_name", .ret_type = 1, .nargs = 2,
487 .args = { { Long, 0 }, { Name, 1 } } },
488 { .name = "truncate", .ret_type = 1, .nargs = 2,
489 .args = { { Name | IN, 0 }, { QuadHex | IN, 1 } } },
492 { .name = "umount", .ret_type = 1, .nargs = 2,
493 .args = { { Name, 0 }, { Int, 2 } } },
495 { .name = "unlink", .ret_type = 1, .nargs = 1,
496 .args = { { Name, 0 } } },
497 { .name = "unlinkat", .ret_type = 1, .nargs = 3,
498 .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
499 { .name = "unmount", .ret_type = 1, .nargs = 2,
500 .args = { { Name, 0 }, { Mountflags, 1 } } },
501 { .name = "utimensat", .ret_type = 1, .nargs = 4,
502 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
504 { .name = "utimes", .ret_type = 1, .nargs = 2,
505 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
506 { .name = "utrace", .ret_type = 1, .nargs = 1,
507 .args = { { Utrace, 0 } } },
508 { .name = "wait4", .ret_type = 1, .nargs = 4,
509 .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
510 { Rusage | OUT, 3 } } },
511 { .name = "wait6", .ret_type = 1, .nargs = 6,
512 .args = { { Idtype, 0 }, { Quad, 1 }, { ExitStatus | OUT, 2 },
513 { Waitoptions, 3 }, { Rusage | OUT, 4 }, { Ptr, 5 } } },
514 { .name = "write", .ret_type = 1, .nargs = 3,
515 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 } } },
518 { .name = "linux_access", .ret_type = 1, .nargs = 2,
519 .args = { { Name, 0 }, { Accessmode, 1 } } },
520 { .name = "linux_execve", .ret_type = 1, .nargs = 3,
521 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
522 { ExecEnv | IN, 2 } } },
523 { .name = "linux_lseek", .ret_type = 2, .nargs = 3,
524 .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
525 { .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
526 .args = { { Name | IN, 0 }, { Int, 1 } } },
527 { .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
528 .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
529 { .name = "linux_newstat", .ret_type = 1, .nargs = 2,
530 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
531 { .name = "linux_open", .ret_type = 1, .nargs = 3,
532 .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
533 { .name = "linux_readlink", .ret_type = 1, .nargs = 3,
534 .args = { { Name, 0 }, { Name | OUT, 1 }, { Sizet, 2 } } },
535 { .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
536 .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
537 { .name = "linux_stat64", .ret_type = 1, .nargs = 2,
538 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
540 /* CloudABI system calls. */
541 { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
542 .args = { { CloudABIClockID, 0 } } },
543 { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
544 .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
545 { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
546 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
547 { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
548 .args = { { Int, 0 } } },
549 { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
550 .args = { { CloudABIFileType, 0 } } },
551 { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
552 .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
553 { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
554 .args = { { Int, 0 } } },
555 { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
556 .args = { { Int, 0 } } },
557 { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
558 .args = { { Int, 0 }, { Int, 1 } } },
559 { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
560 .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
561 { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
562 .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
563 { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
564 .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
565 { ClouduABIFDSFlags, 2 } } },
566 { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
567 .args = { { Int, 0 } } },
568 { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
569 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
570 { CloudABIAdvice, 3 } } },
571 { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
572 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
573 { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
574 .args = { { Int, 0 }, { BinString | IN, 1 },
575 { CloudABIFileType, 3 } } },
576 { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
577 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
578 { Int, 3 }, { BinString | IN, 4 } } },
579 { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
580 .args = { { Int, 0 }, { BinString | IN, 1 },
581 { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
582 { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
583 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
585 { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
586 .args = { { Int, 0 }, { BinString | IN, 1 },
587 { BinString | OUT, 3 }, { Int, 4 } } },
588 { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
589 .args = { { Int, 0 }, { BinString | IN, 1 },
590 { Int, 3 }, { BinString | IN, 4 } } },
591 { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
592 .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
593 { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
594 .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
595 { CloudABIFSFlags, 2 } } },
596 { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
597 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
598 { CloudABIFileStat | OUT, 3 } } },
599 { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
600 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
601 { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
602 { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
603 .args = { { BinString | IN, 0 },
604 { Int, 2 }, { BinString | IN, 3 } } },
605 { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
606 .args = { { Int, 0 }, { BinString | IN, 1 },
607 { CloudABIULFlags, 3 } } },
608 { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
609 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
610 { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
611 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
612 { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
613 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
614 { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
615 { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
616 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
617 { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
618 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
619 { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
620 .args = { { Ptr, 0 }, { Int, 1 } } },
621 { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
622 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
623 { IntArray, 3 }, { Int, 4 } } },
624 { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
625 .args = { { Int, 0 } } },
626 { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
627 { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
628 .args = { { CloudABISignal, 0 } } },
629 { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
630 .args = { { BinString | OUT, 0 }, { Int, 1 } } },
631 { .name = "cloudabi_sys_sock_accept", .ret_type = 1, .nargs = 2,
632 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 } } },
633 { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
634 .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
635 { .name = "cloudabi_sys_sock_stat_get", .ret_type = 1, .nargs = 3,
636 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 },
637 { CloudABISSFlags, 2 } } },
638 { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
639 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
640 { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
644 static STAILQ_HEAD(, syscall) syscalls;
646 /* Xlat idea taken from strace */
652 #define X(a) { a, #a },
653 #define XEND { 0, NULL }
655 static struct xlat kevent_filters[] = {
656 X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
657 X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
658 X(EVFILT_PROCDESC) X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER)
659 X(EVFILT_SENDFILE) XEND
662 static struct xlat kevent_flags[] = {
663 X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
664 X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH) X(EV_FORCEONESHOT)
665 X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
668 static struct xlat kevent_user_ffctrl[] = {
669 X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
673 static struct xlat kevent_rdwr_fflags[] = {
674 X(NOTE_LOWAT) X(NOTE_FILE_POLL) XEND
677 static struct xlat kevent_vnode_fflags[] = {
678 X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB)
679 X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND
682 static struct xlat kevent_proc_fflags[] = {
683 X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR)
687 static struct xlat kevent_timer_fflags[] = {
688 X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS)
692 static struct xlat poll_flags[] = {
693 X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
694 X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
695 X(POLLWRBAND) X(POLLINIGNEOF) XEND
698 static struct xlat sigaction_flags[] = {
699 X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
700 X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
703 static struct xlat pathconf_arg[] = {
704 X(_PC_LINK_MAX) X(_PC_MAX_CANON) X(_PC_MAX_INPUT)
705 X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF)
706 X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE)
707 X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO)
708 X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS)
709 X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE)
710 X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
711 X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
712 X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
713 X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND
716 static struct xlat at_flags[] = {
717 X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW)
721 static struct xlat sysarch_ops[] = {
722 #if defined(__i386__) || defined(__amd64__)
723 X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM)
724 X(I386_VM86) X(I386_GET_FSBASE) X(I386_SET_FSBASE) X(I386_GET_GSBASE)
725 X(I386_SET_GSBASE) X(I386_GET_XFPUSTATE) X(AMD64_GET_FSBASE)
726 X(AMD64_SET_FSBASE) X(AMD64_GET_GSBASE) X(AMD64_SET_GSBASE)
727 X(AMD64_GET_XFPUSTATE)
732 static struct xlat linux_socketcall_ops[] = {
733 X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
734 X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
735 X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
736 X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
737 X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
742 #define X(a) { CLOUDABI_##a, #a },
744 static struct xlat cloudabi_advice[] = {
745 X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
746 X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
750 static struct xlat cloudabi_clockid[] = {
751 X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
752 X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
756 static struct xlat cloudabi_errno[] = {
757 X(E2BIG) X(EACCES) X(EADDRINUSE) X(EADDRNOTAVAIL)
758 X(EAFNOSUPPORT) X(EAGAIN) X(EALREADY) X(EBADF) X(EBADMSG)
759 X(EBUSY) X(ECANCELED) X(ECHILD) X(ECONNABORTED) X(ECONNREFUSED)
760 X(ECONNRESET) X(EDEADLK) X(EDESTADDRREQ) X(EDOM) X(EDQUOT)
761 X(EEXIST) X(EFAULT) X(EFBIG) X(EHOSTUNREACH) X(EIDRM) X(EILSEQ)
762 X(EINPROGRESS) X(EINTR) X(EINVAL) X(EIO) X(EISCONN) X(EISDIR)
763 X(ELOOP) X(EMFILE) X(EMLINK) X(EMSGSIZE) X(EMULTIHOP)
764 X(ENAMETOOLONG) X(ENETDOWN) X(ENETRESET) X(ENETUNREACH)
765 X(ENFILE) X(ENOBUFS) X(ENODEV) X(ENOENT) X(ENOEXEC) X(ENOLCK)
766 X(ENOLINK) X(ENOMEM) X(ENOMSG) X(ENOPROTOOPT) X(ENOSPC)
767 X(ENOSYS) X(ENOTCONN) X(ENOTDIR) X(ENOTEMPTY) X(ENOTRECOVERABLE)
768 X(ENOTSOCK) X(ENOTSUP) X(ENOTTY) X(ENXIO) X(EOVERFLOW)
769 X(EOWNERDEAD) X(EPERM) X(EPIPE) X(EPROTO) X(EPROTONOSUPPORT)
770 X(EPROTOTYPE) X(ERANGE) X(EROFS) X(ESPIPE) X(ESRCH) X(ESTALE)
771 X(ETIMEDOUT) X(ETXTBSY) X(EXDEV) X(ENOTCAPABLE)
775 static struct xlat cloudabi_fdflags[] = {
776 X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
777 X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
781 static struct xlat cloudabi_fdsflags[] = {
782 X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
786 static struct xlat cloudabi_filetype[] = {
787 X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
788 X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
789 X(FILETYPE_FIFO) X(FILETYPE_POLL) X(FILETYPE_PROCESS)
790 X(FILETYPE_REGULAR_FILE) X(FILETYPE_SHARED_MEMORY)
791 X(FILETYPE_SOCKET_DGRAM) X(FILETYPE_SOCKET_STREAM)
792 X(FILETYPE_SYMBOLIC_LINK)
796 static struct xlat cloudabi_fsflags[] = {
797 X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
798 X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
802 static struct xlat cloudabi_mflags[] = {
803 X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
807 static struct xlat cloudabi_mprot[] = {
808 X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
812 static struct xlat cloudabi_msflags[] = {
813 X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
817 static struct xlat cloudabi_oflags[] = {
818 X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
822 static struct xlat cloudabi_sdflags[] = {
823 X(SHUT_RD) X(SHUT_WR)
827 static struct xlat cloudabi_signal[] = {
828 X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
829 X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
830 X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
831 X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
832 X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
836 static struct xlat cloudabi_ssflags[] = {
837 X(SOCKSTAT_CLEAR_ERROR)
841 static struct xlat cloudabi_ssstate[] = {
842 X(SOCKSTATE_ACCEPTCONN)
846 static struct xlat cloudabi_ulflags[] = {
851 static struct xlat cloudabi_whence[] = {
852 X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
860 * Searches an xlat array for a value, and returns it if found. Otherwise
861 * return a string representation.
864 lookup(struct xlat *xlat, int val, int base)
868 for (; xlat->str != NULL; xlat++)
869 if (xlat->val == val)
873 sprintf(tmp, "0%o", val);
876 sprintf(tmp, "0x%x", val);
879 sprintf(tmp, "%u", val);
882 errx(1,"Unknown lookup base");
889 xlookup(struct xlat *xlat, int val)
892 return (lookup(xlat, val, 16));
896 * Searches an xlat array containing bitfield values. Remaining bits
897 * set after removing the known ones are printed at the end:
901 xlookup_bits(struct xlat *xlat, int val)
904 static char str[512];
908 for (; xlat->str != NULL; xlat++) {
909 if ((xlat->val & rem) == xlat->val) {
911 * Don't print the "all-bits-zero" string unless all
912 * bits are really zero.
914 if (xlat->val == 0 && val != 0)
916 len += sprintf(str + len, "%s|", xlat->str);
922 * If we have leftover bits or didn't match anything, print
926 len += sprintf(str + len, "0x%x", rem);
927 if (len && str[len - 1] == '|')
934 print_integer_arg(const char *(*decoder)(int), FILE *fp, int value)
938 str = decoder(value);
942 fprintf(fp, "%d", value);
946 print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value)
950 if (!decoder(fp, value, &rem))
951 fprintf(fp, "0x%x", rem);
953 fprintf(fp, "|0x%x", rem);
957 print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), FILE *fp,
962 if (!decoder(fp, value, &rem))
963 fprintf(fp, "0x%x", rem);
965 fprintf(fp, "|0x%x", rem);
970 * Add argument padding to subsequent system calls afater a Quad
971 * syscall arguments as needed. This used to be done by hand in the
972 * decoded_syscalls table which was ugly and error prone. It is
973 * simpler to do the fixup of offsets at initalization time than when
974 * decoding arguments.
977 quad_fixup(struct syscall *sc)
984 for (i = 0; i < sc->nargs; i++) {
985 /* This arg type is a dummy that doesn't use offset. */
986 if ((sc->args[i].type & ARG_MASK) == PipeFds)
989 assert(prev < sc->args[i].offset);
990 prev = sc->args[i].offset;
991 sc->args[i].offset += offset;
992 switch (sc->args[i].type & ARG_MASK) {
997 * 64-bit arguments on 32-bit powerpc must be
998 * 64-bit aligned. If the current offset is
999 * not aligned, the calling convention inserts
1000 * a 32-bit pad argument that should be skipped.
1002 if (sc->args[i].offset % 2 == 1) {
1003 sc->args[i].offset++;
1020 STAILQ_INIT(&syscalls);
1021 for (sc = decoded_syscalls; sc->name != NULL; sc++) {
1025 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
1029 static struct syscall *
1030 find_syscall(struct procabi *abi, u_int number)
1032 struct extra_syscall *es;
1034 if (number < nitems(abi->syscalls))
1035 return (abi->syscalls[number]);
1036 STAILQ_FOREACH(es, &abi->extra_syscalls, entries) {
1037 if (es->number == number)
1044 add_syscall(struct procabi *abi, u_int number, struct syscall *sc)
1046 struct extra_syscall *es;
1048 if (number < nitems(abi->syscalls)) {
1049 assert(abi->syscalls[number] == NULL);
1050 abi->syscalls[number] = sc;
1052 es = malloc(sizeof(*es));
1054 es->number = number;
1055 STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries);
1060 * If/when the list gets big, it might be desirable to do it
1061 * as a hash table or binary search.
1064 get_syscall(struct threadinfo *t, u_int number, u_int nargs)
1071 sc = find_syscall(t->proc->abi, number);
1075 name = sysdecode_syscallname(t->proc->abi->abi, number);
1077 asprintf(&new_name, "#%d", number);
1081 STAILQ_FOREACH(sc, &syscalls, entries) {
1082 if (strcmp(name, sc->name) == 0) {
1083 add_syscall(t->proc->abi, number, sc);
1089 /* It is unknown. Add it into the list. */
1091 fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
1095 sc = calloc(1, sizeof(struct syscall));
1097 if (new_name != NULL)
1101 for (i = 0; i < nargs; i++) {
1102 sc->args[i].offset = i;
1103 /* Treat all unknown arguments as LongHex. */
1104 sc->args[i].type = LongHex;
1106 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
1107 add_syscall(t->proc->abi, number, sc);
1113 * Copy a fixed amount of bytes from the process.
1116 get_struct(pid_t pid, void *offset, void *buf, int len)
1118 struct ptrace_io_desc iorequest;
1120 iorequest.piod_op = PIOD_READ_D;
1121 iorequest.piod_offs = offset;
1122 iorequest.piod_addr = buf;
1123 iorequest.piod_len = len;
1124 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
1129 #define MAXSIZE 4096
1132 * Copy a string from the process. Note that it is
1133 * expected to be a C string, but if max is set, it will
1134 * only get that much.
1137 get_string(pid_t pid, void *addr, int max)
1139 struct ptrace_io_desc iorequest;
1141 size_t offset, size, totalsize;
1147 /* Read up to the end of the current page. */
1148 size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE);
1153 buf = malloc(totalsize);
1157 iorequest.piod_op = PIOD_READ_D;
1158 iorequest.piod_offs = (char *)addr + offset;
1159 iorequest.piod_addr = buf + offset;
1160 iorequest.piod_len = size;
1161 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
1165 if (memchr(buf + offset, '\0', size) != NULL)
1168 if (totalsize < MAXSIZE && max == 0) {
1169 size = MAXSIZE - totalsize;
1170 if (size > PAGE_SIZE)
1172 nbuf = realloc(buf, totalsize + size);
1174 buf[totalsize - 1] = '\0';
1180 buf[totalsize - 1] = '\0';
1189 static char tmp[32];
1190 const char *signame;
1192 signame = sysdecode_signal(sig);
1193 if (signame == NULL) {
1194 snprintf(tmp, sizeof(tmp), "%d", sig);
1201 print_kevent(FILE *fp, struct kevent *ke, int input)
1204 switch (ke->filter) {
1210 case EVFILT_PROCDESC:
1211 fprintf(fp, "%ju", (uintmax_t)ke->ident);
1214 fputs(strsig2(ke->ident), fp);
1217 fprintf(fp, "%p", (void *)ke->ident);
1219 fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter),
1220 xlookup_bits(kevent_flags, ke->flags));
1221 switch (ke->filter) {
1224 fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp);
1227 fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp);
1230 case EVFILT_PROCDESC:
1231 fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp);
1234 fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp);
1239 ctrl = ke->fflags & NOTE_FFCTRLMASK;
1240 data = ke->fflags & NOTE_FFLAGSMASK;
1242 fputs(xlookup(kevent_user_ffctrl, ctrl), fp);
1243 if (ke->fflags & NOTE_TRIGGER)
1244 fputs("|NOTE_TRIGGER", fp);
1246 fprintf(fp, "|%#x", data);
1248 fprintf(fp, "%#x", data);
1253 fprintf(fp, "%#x", ke->fflags);
1255 fprintf(fp, ",%#jx,%p", (uintmax_t)ke->data, ke->udata);
1259 print_utrace(FILE *fp, void *utrace_addr, size_t len)
1261 unsigned char *utrace_buffer;
1264 if (sysdecode_utrace(fp, utrace_addr, len)) {
1269 utrace_buffer = utrace_addr;
1270 fprintf(fp, "%zu:", len);
1272 fprintf(fp, " %02x", *utrace_buffer++);
1277 * Converts a syscall argument into a string. Said string is
1278 * allocated via malloc(), so needs to be free()'d. sc is
1279 * a pointer to the syscall description (see above); args is
1280 * an array of all of the system call arguments.
1283 print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
1284 struct trussinfo *trussinfo)
1291 fp = open_memstream(&tmp, &tmplen);
1292 pid = trussinfo->curthread->proc->pid;
1293 switch (sc->type & ARG_MASK) {
1295 fprintf(fp, "0x%x", (int)args[sc->offset]);
1298 fprintf(fp, "0%o", (int)args[sc->offset]);
1301 fprintf(fp, "%d", (int)args[sc->offset]);
1304 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1309 if (get_struct(pid, (void *)args[sc->offset], &val,
1311 fprintf(fp, "{ %u }", val);
1313 fprintf(fp, "0x%lx", args[sc->offset]);
1317 fprintf(fp, "0x%lx", args[sc->offset]);
1320 fprintf(fp, "%ld", args[sc->offset]);
1323 fprintf(fp, "%zu", (size_t)args[sc->offset]);
1326 /* NULL-terminated string. */
1329 tmp2 = get_string(pid, (void*)args[sc->offset], 0);
1330 fprintf(fp, "\"%s\"", tmp2);
1336 * Binary block of data that might have printable characters.
1337 * XXX If type|OUT, assume that the length is the syscall's
1338 * return value. Otherwise, assume that the length of the block
1339 * is in the next syscall argument.
1341 int max_string = trussinfo->strsize;
1342 char tmp2[max_string + 1], *tmp3;
1349 len = args[sc->offset + 1];
1352 * Don't print more than max_string characters, to avoid word
1353 * wrap. If we have to truncate put some ... after the string.
1355 if (len > max_string) {
1359 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
1361 tmp3 = malloc(len * 4 + 1);
1363 if (strvisx(tmp3, tmp2, len,
1364 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1369 fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1373 fprintf(fp, "0x%lx", args[sc->offset]);
1383 char buf[PAGE_SIZE];
1390 * Only parse argv[] and environment arrays from exec calls
1393 if (((sc->type & ARG_MASK) == ExecArgs &&
1394 (trussinfo->flags & EXECVEARGS) == 0) ||
1395 ((sc->type & ARG_MASK) == ExecEnv &&
1396 (trussinfo->flags & EXECVEENVS) == 0)) {
1397 fprintf(fp, "0x%lx", args[sc->offset]);
1402 * Read a page of pointers at a time. Punt if the top-level
1403 * pointer is not aligned. Note that the first read is of
1406 addr = args[sc->offset];
1407 if (addr % sizeof(char *) != 0) {
1408 fprintf(fp, "0x%lx", args[sc->offset]);
1412 len = PAGE_SIZE - (addr & PAGE_MASK);
1413 if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
1414 fprintf(fp, "0x%lx", args[sc->offset]);
1421 while (u.strarray[i] != NULL) {
1422 string = get_string(pid, u.strarray[i], 0);
1423 fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1428 if (i == len / sizeof(char *)) {
1431 if (get_struct(pid, (void *)addr, u.buf, len) ==
1433 fprintf(fp, ", <inval>");
1444 fprintf(fp, "%ld", args[sc->offset]);
1447 fprintf(fp, "0x%lx", args[sc->offset]);
1452 unsigned long long ll;
1454 #if _BYTE_ORDER == _LITTLE_ENDIAN
1455 ll = (unsigned long long)args[sc->offset + 1] << 32 |
1458 ll = (unsigned long long)args[sc->offset] << 32 |
1459 args[sc->offset + 1];
1461 if ((sc->type & ARG_MASK) == Quad)
1462 fprintf(fp, "%lld", ll);
1464 fprintf(fp, "0x%llx", ll);
1471 if (get_struct(pid, (void *)args[sc->offset], &val,
1473 fprintf(fp, "{ 0x%jx }", (uintmax_t)val);
1475 fprintf(fp, "0x%lx", args[sc->offset]);
1479 fprintf(fp, "0x%lx", args[sc->offset]);
1484 if (retval[0] == -1)
1486 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
1487 fprintf(fp, "\"%s\"", tmp2);
1495 cmd = args[sc->offset];
1496 temp = sysdecode_ioctlname(cmd);
1500 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1501 cmd, cmd & IOC_OUT ? "R" : "",
1502 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1503 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1504 cmd & 0xFF, IOCPARM_LEN(cmd));
1511 if (get_struct(pid, (void *)args[sc->offset], &ts,
1513 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1516 fprintf(fp, "0x%lx", args[sc->offset]);
1520 struct timespec ts[2];
1524 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
1528 for (i = 0; i < nitems(ts); i++) {
1531 switch (ts[i].tv_nsec) {
1533 fprintf(fp, "UTIME_NOW");
1536 fprintf(fp, "UTIME_OMIT");
1539 fprintf(fp, "%jd.%09ld",
1540 (intmax_t)ts[i].tv_sec,
1547 fprintf(fp, "0x%lx", args[sc->offset]);
1553 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1555 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1558 fprintf(fp, "0x%lx", args[sc->offset]);
1562 struct timeval tv[2];
1564 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1566 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1567 (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1568 (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1570 fprintf(fp, "0x%lx", args[sc->offset]);
1574 struct itimerval itv;
1576 if (get_struct(pid, (void *)args[sc->offset], &itv,
1578 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1579 (intmax_t)itv.it_interval.tv_sec,
1580 itv.it_interval.tv_usec,
1581 (intmax_t)itv.it_value.tv_sec,
1582 itv.it_value.tv_usec);
1584 fprintf(fp, "0x%lx", args[sc->offset]);
1589 struct linux_socketcall_args largs;
1591 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
1592 sizeof(largs)) != -1)
1593 fprintf(fp, "{ %s, 0x%lx }",
1594 lookup(linux_socketcall_ops, largs.what, 10),
1595 (long unsigned int)largs.args);
1597 fprintf(fp, "0x%lx", args[sc->offset]);
1602 * XXX: A Pollfd argument expects the /next/ syscall argument
1603 * to be the number of fds in the array. This matches the poll
1607 int numfds = args[sc->offset + 1];
1608 size_t bytes = sizeof(struct pollfd) * numfds;
1611 if ((pfd = malloc(bytes)) == NULL)
1612 err(1, "Cannot malloc %zu bytes for pollfd array",
1614 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
1617 for (i = 0; i < numfds; i++) {
1618 fprintf(fp, " %d/%s", pfd[i].fd,
1619 xlookup_bits(poll_flags, pfd[i].events));
1623 fprintf(fp, "0x%lx", args[sc->offset]);
1630 * XXX: A Fd_set argument expects the /first/ syscall argument
1631 * to be the number of fds in the array. This matches the
1635 int numfds = args[0];
1636 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1639 if ((fds = malloc(bytes)) == NULL)
1640 err(1, "Cannot malloc %zu bytes for fd_set array",
1642 if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
1645 for (i = 0; i < numfds; i++) {
1646 if (FD_ISSET(i, fds))
1647 fprintf(fp, " %d", i);
1651 fprintf(fp, "0x%lx", args[sc->offset]);
1656 fputs(strsig2(args[sc->offset]), fp);
1663 sig = args[sc->offset];
1664 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
1665 sizeof(ss)) == -1) {
1666 fprintf(fp, "0x%lx", args[sc->offset]);
1671 for (i = 1; i < sys_nsig; i++) {
1672 if (sigismember(&ss, i)) {
1673 fprintf(fp, "%s%s", !first ? "|" : "",
1684 print_integer_arg(sysdecode_sigprocmask_how, fp,
1688 /* XXX: Output depends on the value of the previous argument. */
1689 if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
1690 sysdecode_fcntl_arg(fp, args[sc->offset - 1],
1691 args[sc->offset], 16);
1694 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
1697 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
1700 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
1703 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
1706 print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
1709 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
1712 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
1715 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
1718 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
1721 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]);
1724 fputs(xlookup(pathconf_arg, args[sc->offset]), fp);
1727 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
1731 struct sockaddr_in *lsin;
1732 struct sockaddr_in6 *lsin6;
1733 struct sockaddr_un *sun;
1734 struct sockaddr *sa;
1738 if (args[sc->offset] == 0) {
1744 * Extract the address length from the next argument. If
1745 * this is an output sockaddr (OUT is set), then the
1746 * next argument is a pointer to a socklen_t. Otherwise
1747 * the next argument contains a socklen_t by value.
1749 if (sc->type & OUT) {
1750 if (get_struct(pid, (void *)args[sc->offset + 1],
1751 &len, sizeof(len)) == -1) {
1752 fprintf(fp, "0x%lx", args[sc->offset]);
1756 len = args[sc->offset + 1];
1758 /* If the length is too small, just bail. */
1759 if (len < sizeof(*sa)) {
1760 fprintf(fp, "0x%lx", args[sc->offset]);
1764 sa = calloc(1, len);
1765 if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) {
1767 fprintf(fp, "0x%lx", args[sc->offset]);
1771 switch (sa->sa_family) {
1773 if (len < sizeof(*lsin))
1774 goto sockaddr_short;
1775 lsin = (struct sockaddr_in *)(void *)sa;
1776 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1777 fprintf(fp, "{ AF_INET %s:%d }", addr,
1778 htons(lsin->sin_port));
1781 if (len < sizeof(*lsin6))
1782 goto sockaddr_short;
1783 lsin6 = (struct sockaddr_in6 *)(void *)sa;
1784 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1786 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1787 htons(lsin6->sin6_port));
1790 sun = (struct sockaddr_un *)sa;
1791 fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1792 (int)(len - offsetof(struct sockaddr_un, sun_path)),
1798 "{ sa_len = %d, sa_family = %d, sa_data = {",
1799 (int)sa->sa_len, (int)sa->sa_family);
1800 for (q = (u_char *)sa->sa_data;
1801 q < (u_char *)sa + len; q++)
1802 fprintf(fp, "%s 0x%02x",
1803 q == (u_char *)sa->sa_data ? "" : ",",
1811 struct sigaction sa;
1813 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
1816 if (sa.sa_handler == SIG_DFL)
1817 fputs("SIG_DFL", fp);
1818 else if (sa.sa_handler == SIG_IGN)
1819 fputs("SIG_IGN", fp);
1821 fprintf(fp, "%p", sa.sa_handler);
1822 fprintf(fp, " %s ss_t }",
1823 xlookup_bits(sigaction_flags, sa.sa_flags));
1825 fprintf(fp, "0x%lx", args[sc->offset]);
1830 * XXX XXX: The size of the array is determined by either the
1831 * next syscall argument, or by the syscall return value,
1832 * depending on which argument number we are. This matches the
1833 * kevent syscall, but luckily that's the only syscall that uses
1841 if (sc->offset == 1)
1842 numevents = args[sc->offset+1];
1843 else if (sc->offset == 3 && retval[0] != -1)
1844 numevents = retval[0];
1846 if (numevents >= 0) {
1847 bytes = sizeof(struct kevent) * numevents;
1848 if ((ke = malloc(bytes)) == NULL)
1850 "Cannot malloc %zu bytes for kevent array",
1854 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
1857 for (i = 0; i < numevents; i++) {
1859 print_kevent(fp, &ke[i], sc->offset == 1);
1863 fprintf(fp, "0x%lx", args[sc->offset]);
1871 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1875 strmode(st.st_mode, mode);
1877 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1878 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1879 (long)st.st_blksize);
1881 fprintf(fp, "0x%lx", args[sc->offset]);
1886 struct freebsd11_stat st;
1888 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1892 strmode(st.st_mode, mode);
1894 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1895 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1896 (long)st.st_blksize);
1898 fprintf(fp, "0x%lx", args[sc->offset]);
1906 if (get_struct(pid, (void *)args[sc->offset], &buf,
1907 sizeof(buf)) != -1) {
1910 bzero(fsid, sizeof(fsid));
1911 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
1912 for (i = 0; i < sizeof(buf.f_fsid); i++)
1913 snprintf(&fsid[i*2],
1914 sizeof(fsid) - (i*2), "%02x",
1915 ((u_char *)&buf.f_fsid)[i]);
1918 "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
1919 "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
1920 buf.f_mntfromname, fsid);
1922 fprintf(fp, "0x%lx", args[sc->offset]);
1929 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
1932 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
1933 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
1934 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
1935 ru.ru_inblock, ru.ru_oublock);
1937 fprintf(fp, "0x%lx", args[sc->offset]);
1943 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
1945 fprintf(fp, "{ cur=%ju,max=%ju }",
1946 rl.rlim_cur, rl.rlim_max);
1948 fprintf(fp, "0x%lx", args[sc->offset]);
1954 if (get_struct(pid, (void *)args[sc->offset], &status,
1955 sizeof(status)) != -1) {
1957 if (WIFCONTINUED(status))
1958 fputs("CONTINUED", fp);
1959 else if (WIFEXITED(status))
1960 fprintf(fp, "EXITED,val=%d",
1961 WEXITSTATUS(status));
1962 else if (WIFSIGNALED(status))
1963 fprintf(fp, "SIGNALED,sig=%s%s",
1964 strsig2(WTERMSIG(status)),
1965 WCOREDUMP(status) ? ",cored" : "");
1967 fprintf(fp, "STOPPED,sig=%s",
1968 strsig2(WTERMSIG(status)));
1971 fprintf(fp, "0x%lx", args[sc->offset]);
1975 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]);
1978 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]);
1981 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]);
1984 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]);
1987 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]);
1990 fputs(xlookup_bits(at_flags, args[sc->offset]), fp);
1993 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]);
1996 fputs(xlookup(sysarch_ops, args[sc->offset]), fp);
2000 * The pipe() system call in the kernel returns its
2001 * two file descriptors via return values. However,
2002 * the interface exposed by libc is that pipe()
2003 * accepts a pointer to an array of descriptors.
2004 * Format the output to match the libc API by printing
2005 * the returned file descriptors as a fake argument.
2007 * Overwrite the first retval to signal a successful
2010 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
2017 len = args[sc->offset + 1];
2018 utrace_addr = calloc(1, len);
2019 if (get_struct(pid, (void *)args[sc->offset],
2020 (void *)utrace_addr, len) != -1)
2021 print_utrace(fp, utrace_addr, len);
2023 fprintf(fp, "0x%lx", args[sc->offset]);
2028 int descriptors[16];
2029 unsigned long i, ndescriptors;
2032 ndescriptors = args[sc->offset + 1];
2034 if (ndescriptors > nitems(descriptors)) {
2035 ndescriptors = nitems(descriptors);
2038 if (get_struct(pid, (void *)args[sc->offset],
2039 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
2041 for (i = 0; i < ndescriptors; i++)
2042 fprintf(fp, i == 0 ? " %d" : ", %d",
2044 fprintf(fp, truncated ? ", ... }" : " }");
2046 fprintf(fp, "0x%lx", args[sc->offset]);
2050 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]);
2052 case CapFcntlRights: {
2055 if (sc->type & OUT) {
2056 if (get_struct(pid, (void *)args[sc->offset], &rights,
2057 sizeof(rights)) == -1) {
2058 fprintf(fp, "0x%lx", args[sc->offset]);
2062 rights = args[sc->offset];
2063 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights);
2067 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]);
2072 if (!sysdecode_fileflags(fp, args[sc->offset], &rem))
2073 fprintf(fp, "0x%x", rem);
2075 fprintf(fp, "|0x%x", rem);
2079 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]);
2082 print_integer_arg(sysdecode_getfsstat_mode, fp,
2086 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]);
2088 case Kldunloadflags:
2089 print_integer_arg(sysdecode_kldunload_flags, fp,
2093 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]);
2096 fprintf(fp, "%u", (socklen_t)args[sc->offset]);
2098 case Sockprotocol: {
2100 int domain, protocol;
2102 domain = args[sc->offset - 2];
2103 protocol = args[sc->offset];
2104 if (protocol == 0) {
2107 temp = sysdecode_socket_protocol(domain, protocol);
2111 fprintf(fp, "%d", protocol);
2117 print_integer_arg(sysdecode_sockopt_level, fp,
2124 level = args[sc->offset - 1];
2125 name = args[sc->offset];
2126 temp = sysdecode_sockopt_name(level, name);
2130 fprintf(fp, "%d", name);
2135 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]);
2138 cap_rights_t rights;
2140 if (get_struct(pid, (void *)args[sc->offset], &rights,
2141 sizeof(rights)) != -1) {
2143 sysdecode_cap_rights(fp, &rights);
2146 fprintf(fp, "0x%lx", args[sc->offset]);
2150 print_integer_arg(sysdecode_acltype, fp, args[sc->offset]);
2152 case Extattrnamespace:
2153 print_integer_arg(sysdecode_extattrnamespace, fp,
2157 print_integer_arg(sysdecode_minherit_inherit, fp,
2161 print_mask_arg(sysdecode_mlockall_flags, fp, args[sc->offset]);
2164 print_mask_arg(sysdecode_mount_flags, fp, args[sc->offset]);
2167 print_mask_arg(sysdecode_msync_flags, fp, args[sc->offset]);
2170 print_integer_arg(sysdecode_prio_which, fp, args[sc->offset]);
2173 print_integer_arg(sysdecode_ptrace_request, fp,
2177 if (!sysdecode_quotactl_cmd(fp, args[sc->offset]))
2178 fprintf(fp, "%#x", (int)args[sc->offset]);
2181 print_mask_arg(sysdecode_reboot_howto, fp, args[sc->offset]);
2184 print_integer_arg(sysdecode_rtprio_function, fp,
2188 print_integer_arg(sysdecode_scheduler_policy, fp,
2192 struct sched_param sp;
2194 if (get_struct(pid, (void *)args[sc->offset], &sp,
2196 fprintf(fp, "{ %d }", sp.sched_priority);
2198 fprintf(fp, "0x%lx", args[sc->offset]);
2202 case CloudABIAdvice:
2203 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
2205 case CloudABIClockID:
2206 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2208 case ClouduABIFDSFlags:
2209 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2211 case CloudABIFDStat: {
2212 cloudabi_fdstat_t fds;
2213 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds))
2215 fprintf(fp, "{ %s, ",
2216 xlookup(cloudabi_filetype, fds.fs_filetype));
2217 fprintf(fp, "%s, ... }",
2218 xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2220 fprintf(fp, "0x%lx", args[sc->offset]);
2223 case CloudABIFileStat: {
2224 cloudabi_filestat_t fsb;
2225 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb))
2227 fprintf(fp, "{ %s, %ju }",
2228 xlookup(cloudabi_filetype, fsb.st_filetype),
2229 (uintmax_t)fsb.st_size);
2231 fprintf(fp, "0x%lx", args[sc->offset]);
2234 case CloudABIFileType:
2235 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2237 case CloudABIFSFlags:
2238 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2240 case CloudABILookup:
2241 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2242 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2243 (int)args[sc->offset]);
2245 fprintf(fp, "%d", (int)args[sc->offset]);
2247 case CloudABIMFlags:
2248 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2251 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2253 case CloudABIMSFlags:
2254 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2256 case CloudABIOFlags:
2257 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2259 case CloudABISDFlags:
2260 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2262 case CloudABISignal:
2263 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2265 case CloudABISockStat: {
2266 cloudabi_sockstat_t ss;
2267 if (get_struct(pid, (void *)args[sc->offset], &ss, sizeof(ss))
2269 fprintf(fp, "%s, ", xlookup(
2270 cloudabi_errno, ss.ss_error));
2271 fprintf(fp, "%s }", xlookup_bits(
2272 cloudabi_ssstate, ss.ss_state));
2274 fprintf(fp, "0x%lx", args[sc->offset]);
2277 case CloudABISSFlags:
2278 fputs(xlookup_bits(cloudabi_ssflags, args[sc->offset]), fp);
2280 case CloudABITimestamp:
2281 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2282 args[sc->offset] % 1000000000);
2284 case CloudABIULFlags:
2285 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2287 case CloudABIWhence:
2288 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2292 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2299 * Print (to outfile) the system call and its arguments.
2302 print_syscall(struct trussinfo *trussinfo)
2304 struct threadinfo *t;
2309 t = trussinfo->curthread;
2311 name = t->cs.sc->name;
2312 nargs = t->cs.nargs;
2313 s_args = t->cs.s_args;
2315 len = print_line_prefix(trussinfo);
2316 len += fprintf(trussinfo->outfile, "%s(", name);
2318 for (i = 0; i < nargs; i++) {
2319 if (s_args[i] != NULL)
2320 len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2322 len += fprintf(trussinfo->outfile,
2323 "<missing argument>");
2324 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2327 len += fprintf(trussinfo->outfile, ")");
2328 for (i = 0; i < 6 - (len / 8); i++)
2329 fprintf(trussinfo->outfile, "\t");
2333 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
2335 struct timespec timediff;
2336 struct threadinfo *t;
2340 t = trussinfo->curthread;
2342 if (trussinfo->flags & COUNTONLY) {
2343 timespecsubt(&t->after, &t->before, &timediff);
2344 timespecadd(&sc->time, &timediff, &sc->time);
2351 print_syscall(trussinfo);
2352 fflush(trussinfo->outfile);
2354 if (retval == NULL) {
2356 * This system call resulted in the current thread's exit,
2357 * so there is no return value or error to display.
2359 fprintf(trussinfo->outfile, "\n");
2364 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi,
2366 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
2367 error == INT_MAX ? "Unknown error" : strerror(error));
2370 else if (sc->ret_type == 2) {
2373 #if _BYTE_ORDER == _LITTLE_ENDIAN
2374 off = (off_t)retval[1] << 32 | retval[0];
2376 off = (off_t)retval[0] << 32 | retval[1];
2378 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2383 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
2388 print_summary(struct trussinfo *trussinfo)
2390 struct timespec total = {0, 0};
2394 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2395 "syscall", "seconds", "calls", "errors");
2397 STAILQ_FOREACH(sc, &syscalls, entries)
2399 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2400 sc->name, (intmax_t)sc->time.tv_sec,
2401 sc->time.tv_nsec, sc->ncalls, sc->nerror);
2402 timespecadd(&total, &sc->time, &total);
2403 ncall += sc->ncalls;
2404 nerror += sc->nerror;
2406 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2407 "", "-------------", "-------", "-------");
2408 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2409 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);