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 <netinet/in.h>
53 #include <arpa/inet.h>
66 #include <sysdecode.h>
70 #include <contrib/cloudabi/cloudabi_types_common.h>
77 * This should probably be in its own file, sorted alphabetically.
79 static struct syscall decoded_syscalls[] = {
81 { .name = "__acl_aclcheck_fd", .ret_type = 1, .nargs = 3,
82 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
83 { .name = "__acl_aclcheck_file", .ret_type = 1, .nargs = 3,
84 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
85 { .name = "__acl_aclcheck_link", .ret_type = 1, .nargs = 3,
86 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
87 { .name = "__acl_delete_fd", .ret_type = 1, .nargs = 2,
88 .args = { { Int, 0 }, { Acltype, 1 } } },
89 { .name = "__acl_delete_file", .ret_type = 1, .nargs = 2,
90 .args = { { Name, 0 }, { Acltype, 1 } } },
91 { .name = "__acl_delete_link", .ret_type = 1, .nargs = 2,
92 .args = { { Name, 0 }, { Acltype, 1 } } },
93 { .name = "__acl_get_fd", .ret_type = 1, .nargs = 3,
94 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
95 { .name = "__acl_get_file", .ret_type = 1, .nargs = 3,
96 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
97 { .name = "__acl_get_link", .ret_type = 1, .nargs = 3,
98 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
99 { .name = "__acl_set_fd", .ret_type = 1, .nargs = 3,
100 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
101 { .name = "__acl_set_file", .ret_type = 1, .nargs = 3,
102 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
103 { .name = "__acl_set_link", .ret_type = 1, .nargs = 3,
104 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
105 { .name = "__cap_rights_get", .ret_type = 1, .nargs = 3,
106 .args = { { Int, 0 }, { Int, 1 }, { CapRights | OUT, 2 } } },
107 { .name = "__getcwd", .ret_type = 1, .nargs = 2,
108 .args = { { Name | OUT, 0 }, { Int, 1 } } },
109 { .name = "_umtx_op", .ret_type = 1, .nargs = 5,
110 .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
112 { .name = "accept", .ret_type = 1, .nargs = 3,
113 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
114 { .name = "access", .ret_type = 1, .nargs = 2,
115 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
116 { .name = "bind", .ret_type = 1, .nargs = 3,
117 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
118 { .name = "bindat", .ret_type = 1, .nargs = 4,
119 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
121 { .name = "break", .ret_type = 1, .nargs = 1,
122 .args = { { Ptr, 0 } } },
123 { .name = "cap_fcntls_get", .ret_type = 1, .nargs = 2,
124 .args = { { Int, 0 }, { CapFcntlRights | OUT, 1 } } },
125 { .name = "cap_fcntls_limit", .ret_type = 1, .nargs = 2,
126 .args = { { Int, 0 }, { CapFcntlRights, 1 } } },
127 { .name = "cap_getmode", .ret_type = 1, .nargs = 1,
128 .args = { { PUInt | OUT, 0 } } },
129 { .name = "cap_rights_limit", .ret_type = 1, .nargs = 2,
130 .args = { { Int, 0 }, { CapRights, 1 } } },
131 { .name = "chdir", .ret_type = 1, .nargs = 1,
132 .args = { { Name, 0 } } },
133 { .name = "chflags", .ret_type = 1, .nargs = 2,
134 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
135 { .name = "chflagsat", .ret_type = 1, .nargs = 4,
136 .args = { { Atfd, 0 }, { Name | IN, 1 }, { FileFlags, 2 },
138 { .name = "chmod", .ret_type = 1, .nargs = 2,
139 .args = { { Name, 0 }, { Octal, 1 } } },
140 { .name = "chown", .ret_type = 1, .nargs = 3,
141 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
142 { .name = "chroot", .ret_type = 1, .nargs = 1,
143 .args = { { Name, 0 } } },
144 { .name = "clock_gettime", .ret_type = 1, .nargs = 2,
145 .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
146 { .name = "close", .ret_type = 1, .nargs = 1,
147 .args = { { Int, 0 } } },
148 { .name = "compat11.fstat", .ret_type = 1, .nargs = 2,
149 .args = { { Int, 0 }, { Stat11 | OUT, 1 } } },
150 { .name = "compat11.fstatat", .ret_type = 1, .nargs = 4,
151 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat11 | OUT, 2 },
153 { .name = "compat11.lstat", .ret_type = 1, .nargs = 2,
154 .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } },
155 { .name = "compat11.stat", .ret_type = 1, .nargs = 2,
156 .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } },
157 { .name = "connect", .ret_type = 1, .nargs = 3,
158 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
159 { .name = "connectat", .ret_type = 1, .nargs = 4,
160 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
162 { .name = "dup", .ret_type = 1, .nargs = 1,
163 .args = { { Int, 0 } } },
164 { .name = "dup2", .ret_type = 1, .nargs = 2,
165 .args = { { Int, 0 }, { Int, 1 } } },
166 { .name = "eaccess", .ret_type = 1, .nargs = 2,
167 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
168 { .name = "execve", .ret_type = 1, .nargs = 3,
169 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
170 { ExecEnv | IN, 2 } } },
171 { .name = "exit", .ret_type = 0, .nargs = 1,
172 .args = { { Hex, 0 } } },
173 { .name = "extattr_delete_fd", .ret_type = 1, .nargs = 3,
174 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
175 { .name = "extattr_delete_file", .ret_type = 1, .nargs = 3,
176 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
177 { .name = "extattr_delete_link", .ret_type = 1, .nargs = 3,
178 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
179 { .name = "extattr_get_fd", .ret_type = 1, .nargs = 5,
180 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
181 { BinString | OUT, 3 }, { Sizet, 4 } } },
182 { .name = "extattr_get_file", .ret_type = 1, .nargs = 5,
183 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
184 { BinString | OUT, 3 }, { Sizet, 4 } } },
185 { .name = "extattr_get_link", .ret_type = 1, .nargs = 5,
186 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
187 { BinString | OUT, 3 }, { Sizet, 4 } } },
188 { .name = "extattr_list_fd", .ret_type = 1, .nargs = 4,
189 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
191 { .name = "extattr_list_file", .ret_type = 1, .nargs = 4,
192 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
194 { .name = "extattr_list_link", .ret_type = 1, .nargs = 4,
195 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
197 { .name = "extattr_set_fd", .ret_type = 1, .nargs = 5,
198 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
199 { BinString | IN, 3 }, { Sizet, 4 } } },
200 { .name = "extattr_set_file", .ret_type = 1, .nargs = 5,
201 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
202 { BinString | IN, 3 }, { Sizet, 4 } } },
203 { .name = "extattr_set_link", .ret_type = 1, .nargs = 5,
204 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
205 { BinString | IN, 3 }, { Sizet, 4 } } },
206 { .name = "extattrctl", .ret_type = 1, .nargs = 5,
207 .args = { { Name, 0 }, { Hex, 1 }, { Name, 2 },
208 { Extattrnamespace, 3 }, { Name, 4 } } },
209 { .name = "faccessat", .ret_type = 1, .nargs = 4,
210 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
212 { .name = "fchflags", .ret_type = 1, .nargs = 2,
213 .args = { { Int, 0 }, { FileFlags, 1 } } },
214 { .name = "fchmod", .ret_type = 1, .nargs = 2,
215 .args = { { Int, 0 }, { Octal, 1 } } },
216 { .name = "fchmodat", .ret_type = 1, .nargs = 4,
217 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
218 { .name = "fchown", .ret_type = 1, .nargs = 3,
219 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
220 { .name = "fchownat", .ret_type = 1, .nargs = 5,
221 .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
223 { .name = "fcntl", .ret_type = 1, .nargs = 3,
224 .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
225 { .name = "flock", .ret_type = 1, .nargs = 2,
226 .args = { { Int, 0 }, { Flockop, 1 } } },
227 { .name = "fstat", .ret_type = 1, .nargs = 2,
228 .args = { { Int, 0 }, { Stat | OUT, 1 } } },
229 { .name = "fstatat", .ret_type = 1, .nargs = 4,
230 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
232 { .name = "fstatfs", .ret_type = 1, .nargs = 2,
233 .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
234 { .name = "ftruncate", .ret_type = 1, .nargs = 2,
235 .args = { { Int | IN, 0 }, { QuadHex | IN, 1 } } },
236 { .name = "futimens", .ret_type = 1, .nargs = 2,
237 .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
238 { .name = "futimes", .ret_type = 1, .nargs = 2,
239 .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
240 { .name = "futimesat", .ret_type = 1, .nargs = 3,
241 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
242 { .name = "getdirentries", .ret_type = 1, .nargs = 4,
243 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
244 { PQuadHex | OUT, 3 } } },
245 { .name = "getfsstat", .ret_type = 1, .nargs = 3,
246 .args = { { Ptr, 0 }, { Long, 1 }, { Getfsstatmode, 2 } } },
247 { .name = "getitimer", .ret_type = 1, .nargs = 2,
248 .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
249 { .name = "getpeername", .ret_type = 1, .nargs = 3,
250 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
251 { .name = "getpgid", .ret_type = 1, .nargs = 1,
252 .args = { { Int, 0 } } },
253 { .name = "getpriority", .ret_type = 1, .nargs = 2,
254 .args = { { Priowhich, 0 }, { Int, 1 } } },
255 { .name = "getrlimit", .ret_type = 1, .nargs = 2,
256 .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
257 { .name = "getrusage", .ret_type = 1, .nargs = 2,
258 .args = { { RusageWho, 0 }, { Rusage | OUT, 1 } } },
259 { .name = "getsid", .ret_type = 1, .nargs = 1,
260 .args = { { Int, 0 } } },
261 { .name = "getsockname", .ret_type = 1, .nargs = 3,
262 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
263 { .name = "getsockopt", .ret_type = 1, .nargs = 5,
264 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
265 { Ptr | OUT, 3 }, { Ptr | OUT, 4 } } },
266 { .name = "gettimeofday", .ret_type = 1, .nargs = 2,
267 .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
268 { .name = "ioctl", .ret_type = 1, .nargs = 3,
269 .args = { { Int, 0 }, { Ioctl, 1 }, { Ptr, 2 } } },
270 { .name = "kevent", .ret_type = 1, .nargs = 6,
271 .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
272 { Int, 4 }, { Timespec, 5 } } },
273 { .name = "kill", .ret_type = 1, .nargs = 2,
274 .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
275 { .name = "kldfind", .ret_type = 1, .nargs = 1,
276 .args = { { Name | IN, 0 } } },
277 { .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
278 .args = { { Int, 0 } } },
279 { .name = "kldload", .ret_type = 1, .nargs = 1,
280 .args = { { Name | IN, 0 } } },
281 { .name = "kldnext", .ret_type = 1, .nargs = 1,
282 .args = { { Int, 0 } } },
283 { .name = "kldstat", .ret_type = 1, .nargs = 2,
284 .args = { { Int, 0 }, { Ptr, 1 } } },
285 { .name = "kldsym", .ret_type = 1, .nargs = 3,
286 .args = { { Int, 0 }, { Kldsymcmd, 1 }, { Ptr, 2 } } },
287 { .name = "kldunload", .ret_type = 1, .nargs = 1,
288 .args = { { Int, 0 } } },
289 { .name = "kldunloadf", .ret_type = 1, .nargs = 2,
290 .args = { { Int, 0 }, { Kldunloadflags, 1 } } },
291 { .name = "kse_release", .ret_type = 0, .nargs = 1,
292 .args = { { Timespec, 0 } } },
293 { .name = "lchflags", .ret_type = 1, .nargs = 2,
294 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
295 { .name = "lchmod", .ret_type = 1, .nargs = 2,
296 .args = { { Name, 0 }, { Octal, 1 } } },
297 { .name = "lchown", .ret_type = 1, .nargs = 3,
298 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
299 { .name = "link", .ret_type = 1, .nargs = 2,
300 .args = { { Name, 0 }, { Name, 1 } } },
301 { .name = "linkat", .ret_type = 1, .nargs = 5,
302 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
304 { .name = "listen", .ret_type = 1, .nargs = 2,
305 .args = { { Int, 0 }, { Int, 1 } } },
306 { .name = "lseek", .ret_type = 2, .nargs = 3,
307 .args = { { Int, 0 }, { QuadHex, 1 }, { Whence, 2 } } },
308 { .name = "lstat", .ret_type = 1, .nargs = 2,
309 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
310 { .name = "lutimes", .ret_type = 1, .nargs = 2,
311 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
312 { .name = "madvise", .ret_type = 1, .nargs = 3,
313 .args = { { Ptr, 0 }, { Sizet, 1 }, { Madvice, 2 } } },
314 { .name = "minherit", .ret_type = 1, .nargs = 3,
315 .args = { { Ptr, 0 }, { Sizet, 1 }, { Minherit, 2 } } },
316 { .name = "mkdir", .ret_type = 1, .nargs = 2,
317 .args = { { Name, 0 }, { Octal, 1 } } },
318 { .name = "mkdirat", .ret_type = 1, .nargs = 3,
319 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
320 { .name = "mkfifo", .ret_type = 1, .nargs = 2,
321 .args = { { Name, 0 }, { Octal, 1 } } },
322 { .name = "mkfifoat", .ret_type = 1, .nargs = 3,
323 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
324 { .name = "mknod", .ret_type = 1, .nargs = 3,
325 .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
326 { .name = "mknodat", .ret_type = 1, .nargs = 4,
327 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
328 { .name = "mlock", .ret_type = 1, .nargs = 2,
329 .args = { { Ptr, 0 }, { Sizet, 1 } } },
330 { .name = "mlockall", .ret_type = 1, .nargs = 1,
331 .args = { { Mlockall, 0 } } },
332 { .name = "mmap", .ret_type = 1, .nargs = 6,
333 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
334 { Int, 4 }, { QuadHex, 5 } } },
335 { .name = "modfind", .ret_type = 1, .nargs = 1,
336 .args = { { Name | IN, 0 } } },
337 { .name = "mount", .ret_type = 1, .nargs = 4,
338 .args = { { Name, 0 }, { Name, 1 }, { Mountflags, 2 }, { Ptr, 3 } } },
339 { .name = "mprotect", .ret_type = 1, .nargs = 3,
340 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 } } },
341 { .name = "msync", .ret_type = 1, .nargs = 3,
342 .args = { { Ptr, 0 }, { Sizet, 1 }, { Msync, 2 } } },
343 { .name = "munlock", .ret_type = 1, .nargs = 2,
344 .args = { { Ptr, 0 }, { Sizet, 1 } } },
345 { .name = "munmap", .ret_type = 1, .nargs = 2,
346 .args = { { Ptr, 0 }, { Sizet, 1 } } },
347 { .name = "nanosleep", .ret_type = 1, .nargs = 1,
348 .args = { { Timespec, 0 } } },
349 { .name = "nmount", .ret_type = 1, .nargs = 3,
350 .args = { { Ptr, 0 }, { UInt, 1 }, { Mountflags, 2 } } },
351 { .name = "open", .ret_type = 1, .nargs = 3,
352 .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
353 { .name = "openat", .ret_type = 1, .nargs = 4,
354 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
356 { .name = "pathconf", .ret_type = 1, .nargs = 2,
357 .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
358 { .name = "pipe", .ret_type = 1, .nargs = 1,
359 .args = { { PipeFds | OUT, 0 } } },
360 { .name = "pipe2", .ret_type = 1, .nargs = 2,
361 .args = { { Ptr, 0 }, { Pipe2, 1 } } },
362 { .name = "poll", .ret_type = 1, .nargs = 3,
363 .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
364 { .name = "posix_fadvise", .ret_type = 1, .nargs = 4,
365 .args = { { Int, 0 }, { QuadHex, 1 }, { QuadHex, 2 },
367 { .name = "posix_openpt", .ret_type = 1, .nargs = 1,
368 .args = { { Open, 0 } } },
369 { .name = "pread", .ret_type = 1, .nargs = 4,
370 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
372 { .name = "procctl", .ret_type = 1, .nargs = 4,
373 .args = { { Idtype, 0 }, { Quad, 1 }, { Procctl, 2 }, { Ptr, 3 } } },
374 { .name = "ptrace", .ret_type = 1, .nargs = 4,
375 .args = { { Ptraceop, 0 }, { Int, 1 }, { Ptr, 2 }, { Int, 3 } } },
376 { .name = "pwrite", .ret_type = 1, .nargs = 4,
377 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
379 { .name = "quotactl", .ret_type = 1, .nargs = 4,
380 .args = { { Name, 0 }, { Quotactlcmd, 1 }, { Int, 2 }, { Ptr, 3 } } },
381 { .name = "read", .ret_type = 1, .nargs = 3,
382 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 } } },
383 { .name = "readlink", .ret_type = 1, .nargs = 3,
384 .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Sizet, 2 } } },
385 { .name = "readlinkat", .ret_type = 1, .nargs = 4,
386 .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
388 { .name = "reboot", .ret_type = 1, .nargs = 1,
389 .args = { { Reboothowto, 0 } } },
390 { .name = "recvfrom", .ret_type = 1, .nargs = 6,
391 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
392 { Msgflags, 3 }, { Sockaddr | OUT, 4 },
393 { Ptr | OUT, 5 } } },
394 { .name = "recvmsg", .ret_type = 1, .nargs = 3,
395 .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
396 { .name = "rename", .ret_type = 1, .nargs = 2,
397 .args = { { Name, 0 }, { Name, 1 } } },
398 { .name = "renameat", .ret_type = 1, .nargs = 4,
399 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
400 { .name = "rfork", .ret_type = 1, .nargs = 1,
401 .args = { { Rforkflags, 0 } } },
402 { .name = "rmdir", .ret_type = 1, .nargs = 1,
403 .args = { { Name, 0 } } },
404 { .name = "rtprio", .ret_type = 1, .nargs = 3,
405 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
406 { .name = "rtprio_thread", .ret_type = 1, .nargs = 3,
407 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
408 { .name = "sched_get_priority_max", .ret_type = 1, .nargs = 1,
409 .args = { { Schedpolicy, 0 } } },
410 { .name = "sched_get_priority_min", .ret_type = 1, .nargs = 1,
411 .args = { { Schedpolicy, 0 } } },
412 { .name = "sched_getparam", .ret_type = 1, .nargs = 2,
413 .args = { { Int, 0 }, { Schedparam | OUT, 1 } } },
414 { .name = "sched_getscheduler", .ret_type = 1, .nargs = 1,
415 .args = { { Int, 0 } } },
416 { .name = "sched_rr_get_interval", .ret_type = 1, .nargs = 2,
417 .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
418 { .name = "sched_setparam", .ret_type = 1, .nargs = 2,
419 .args = { { Int, 0 }, { Schedparam, 1 } } },
420 { .name = "sched_setscheduler", .ret_type = 1, .nargs = 3,
421 .args = { { Int, 0 }, { Schedpolicy, 1 }, { Schedparam, 2 } } },
422 { .name = "sctp_generic_recvmsg", .ret_type = 1, .nargs = 7,
423 .args = { { Int, 0 }, { Ptr | IN, 1 }, { Int, 2 },
424 { Sockaddr | OUT, 3 }, { Ptr | OUT, 4 }, { Ptr | OUT, 5 },
425 { Ptr | OUT, 6 } } },
426 { .name = "sctp_generic_sendmsg", .ret_type = 1, .nargs = 7,
427 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
428 { Sockaddr | IN, 3 }, { Socklent, 4 }, { Ptr | IN, 5 },
430 { .name = "select", .ret_type = 1, .nargs = 5,
431 .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
433 { .name = "sendmsg", .ret_type = 1, .nargs = 3,
434 .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
435 { .name = "sendto", .ret_type = 1, .nargs = 6,
436 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
437 { Msgflags, 3 }, { Sockaddr | IN, 4 },
438 { Socklent | IN, 5 } } },
439 { .name = "setitimer", .ret_type = 1, .nargs = 3,
440 .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
441 { .name = "setpriority", .ret_type = 1, .nargs = 3,
442 .args = { { Priowhich, 0 }, { Int, 1 }, { Int, 2 } } },
443 { .name = "setrlimit", .ret_type = 1, .nargs = 2,
444 .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
445 { .name = "setsockopt", .ret_type = 1, .nargs = 5,
446 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
447 { Ptr | IN, 3 }, { Socklent, 4 } } },
448 { .name = "shutdown", .ret_type = 1, .nargs = 2,
449 .args = { { Int, 0 }, { Shutdown, 1 } } },
450 { .name = "sigaction", .ret_type = 1, .nargs = 3,
451 .args = { { Signal, 0 }, { Sigaction | IN, 1 },
452 { Sigaction | OUT, 2 } } },
453 { .name = "sigpending", .ret_type = 1, .nargs = 1,
454 .args = { { Sigset | OUT, 0 } } },
455 { .name = "sigprocmask", .ret_type = 1, .nargs = 3,
456 .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
457 { .name = "sigqueue", .ret_type = 1, .nargs = 3,
458 .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
459 { .name = "sigreturn", .ret_type = 1, .nargs = 1,
460 .args = { { Ptr, 0 } } },
461 { .name = "sigsuspend", .ret_type = 1, .nargs = 1,
462 .args = { { Sigset | IN, 0 } } },
463 { .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
464 .args = { { Sigset | IN, 0 }, { Siginfo | OUT, 1 },
465 { Timespec | IN, 2 } } },
466 { .name = "sigwait", .ret_type = 1, .nargs = 2,
467 .args = { { Sigset | IN, 0 }, { PSig | OUT, 1 } } },
468 { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
469 .args = { { Sigset | IN, 0 }, { Siginfo | OUT, 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 },
514 { Siginfo | OUT, 5 } } },
515 { .name = "write", .ret_type = 1, .nargs = 3,
516 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 } } },
519 { .name = "linux_access", .ret_type = 1, .nargs = 2,
520 .args = { { Name, 0 }, { Accessmode, 1 } } },
521 { .name = "linux_execve", .ret_type = 1, .nargs = 3,
522 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
523 { ExecEnv | IN, 2 } } },
524 { .name = "linux_lseek", .ret_type = 2, .nargs = 3,
525 .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
526 { .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
527 .args = { { Name | IN, 0 }, { Int, 1 } } },
528 { .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
529 .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
530 { .name = "linux_newstat", .ret_type = 1, .nargs = 2,
531 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
532 { .name = "linux_open", .ret_type = 1, .nargs = 3,
533 .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
534 { .name = "linux_readlink", .ret_type = 1, .nargs = 3,
535 .args = { { Name, 0 }, { Name | OUT, 1 }, { Sizet, 2 } } },
536 { .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
537 .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
538 { .name = "linux_stat64", .ret_type = 1, .nargs = 2,
539 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
541 /* CloudABI system calls. */
542 { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
543 .args = { { CloudABIClockID, 0 } } },
544 { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
545 .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
546 { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
547 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
548 { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
549 .args = { { Int, 0 } } },
550 { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
551 .args = { { CloudABIFileType, 0 } } },
552 { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
553 .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
554 { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
555 .args = { { Int, 0 } } },
556 { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
557 .args = { { Int, 0 } } },
558 { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
559 .args = { { Int, 0 }, { Int, 1 } } },
560 { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
561 .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
562 { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
563 .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
564 { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
565 .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
566 { ClouduABIFDSFlags, 2 } } },
567 { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
568 .args = { { Int, 0 } } },
569 { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
570 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
571 { CloudABIAdvice, 3 } } },
572 { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
573 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
574 { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
575 .args = { { Int, 0 }, { BinString | IN, 1 },
576 { CloudABIFileType, 3 } } },
577 { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
578 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
579 { Int, 3 }, { BinString | IN, 4 } } },
580 { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
581 .args = { { Int, 0 }, { BinString | IN, 1 },
582 { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
583 { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
584 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
586 { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
587 .args = { { Int, 0 }, { BinString | IN, 1 },
588 { BinString | OUT, 3 }, { Int, 4 } } },
589 { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
590 .args = { { Int, 0 }, { BinString | IN, 1 },
591 { Int, 3 }, { BinString | IN, 4 } } },
592 { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
593 .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
594 { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
595 .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
596 { CloudABIFSFlags, 2 } } },
597 { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
598 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
599 { CloudABIFileStat | OUT, 3 } } },
600 { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
601 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
602 { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
603 { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
604 .args = { { BinString | IN, 0 },
605 { Int, 2 }, { BinString | IN, 3 } } },
606 { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
607 .args = { { Int, 0 }, { BinString | IN, 1 },
608 { CloudABIULFlags, 3 } } },
609 { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
610 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
611 { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
612 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
613 { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
614 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
615 { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
616 { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
617 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
618 { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
619 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
620 { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
621 .args = { { Ptr, 0 }, { Int, 1 } } },
622 { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
623 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
624 { IntArray, 3 }, { Int, 4 } } },
625 { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
626 .args = { { Int, 0 } } },
627 { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
628 { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
629 .args = { { CloudABISignal, 0 } } },
630 { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
631 .args = { { BinString | OUT, 0 }, { Int, 1 } } },
632 { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
633 .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
634 { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
635 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
636 { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
640 static STAILQ_HEAD(, syscall) syscalls;
642 /* Xlat idea taken from strace */
648 #define X(a) { a, #a },
649 #define XEND { 0, NULL }
651 static struct xlat kevent_filters[] = {
652 X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
653 X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
654 X(EVFILT_PROCDESC) X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER)
655 X(EVFILT_SENDFILE) XEND
658 static struct xlat kevent_flags[] = {
659 X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
660 X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH) X(EV_FORCEONESHOT)
661 X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
664 static struct xlat kevent_user_ffctrl[] = {
665 X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
669 static struct xlat kevent_rdwr_fflags[] = {
670 X(NOTE_LOWAT) X(NOTE_FILE_POLL) XEND
673 static struct xlat kevent_vnode_fflags[] = {
674 X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB)
675 X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND
678 static struct xlat kevent_proc_fflags[] = {
679 X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR)
683 static struct xlat kevent_timer_fflags[] = {
684 X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS)
688 static struct xlat poll_flags[] = {
689 X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
690 X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
691 X(POLLWRBAND) X(POLLINIGNEOF) XEND
694 static struct xlat sigaction_flags[] = {
695 X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
696 X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
699 static struct xlat linux_socketcall_ops[] = {
700 X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
701 X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
702 X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
703 X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
704 X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
709 #define X(a) { CLOUDABI_##a, #a },
711 static struct xlat cloudabi_advice[] = {
712 X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
713 X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
717 static struct xlat cloudabi_clockid[] = {
718 X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
719 X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
723 static struct xlat cloudabi_fdflags[] = {
724 X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
725 X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
729 static struct xlat cloudabi_fdsflags[] = {
730 X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
734 static struct xlat cloudabi_filetype[] = {
735 X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
736 X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
737 X(FILETYPE_PROCESS) X(FILETYPE_REGULAR_FILE)
738 X(FILETYPE_SHARED_MEMORY) X(FILETYPE_SOCKET_DGRAM)
739 X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK)
743 static struct xlat cloudabi_fsflags[] = {
744 X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
745 X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
749 static struct xlat cloudabi_mflags[] = {
750 X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
754 static struct xlat cloudabi_mprot[] = {
755 X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
759 static struct xlat cloudabi_msflags[] = {
760 X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
764 static struct xlat cloudabi_oflags[] = {
765 X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
769 static struct xlat cloudabi_sdflags[] = {
770 X(SHUT_RD) X(SHUT_WR)
774 static struct xlat cloudabi_signal[] = {
775 X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
776 X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
777 X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
778 X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
779 X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
783 static struct xlat cloudabi_ulflags[] = {
788 static struct xlat cloudabi_whence[] = {
789 X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
797 * Searches an xlat array for a value, and returns it if found. Otherwise
798 * return a string representation.
801 lookup(struct xlat *xlat, int val, int base)
805 for (; xlat->str != NULL; xlat++)
806 if (xlat->val == val)
810 sprintf(tmp, "0%o", val);
813 sprintf(tmp, "0x%x", val);
816 sprintf(tmp, "%u", val);
819 errx(1,"Unknown lookup base");
826 xlookup(struct xlat *xlat, int val)
829 return (lookup(xlat, val, 16));
833 * Searches an xlat array containing bitfield values. Remaining bits
834 * set after removing the known ones are printed at the end:
838 xlookup_bits(struct xlat *xlat, int val)
841 static char str[512];
845 for (; xlat->str != NULL; xlat++) {
846 if ((xlat->val & rem) == xlat->val) {
848 * Don't print the "all-bits-zero" string unless all
849 * bits are really zero.
851 if (xlat->val == 0 && val != 0)
853 len += sprintf(str + len, "%s|", xlat->str);
859 * If we have leftover bits or didn't match anything, print
863 len += sprintf(str + len, "0x%x", rem);
864 if (len && str[len - 1] == '|')
871 print_integer_arg(const char *(*decoder)(int), FILE *fp, int value)
875 str = decoder(value);
879 fprintf(fp, "%d", value);
883 print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value)
887 if (!decoder(fp, value, &rem))
888 fprintf(fp, "0x%x", rem);
890 fprintf(fp, "|0x%x", rem);
894 print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), FILE *fp,
899 if (!decoder(fp, value, &rem))
900 fprintf(fp, "0x%x", rem);
902 fprintf(fp, "|0x%x", rem);
907 * Add argument padding to subsequent system calls afater a Quad
908 * syscall arguments as needed. This used to be done by hand in the
909 * decoded_syscalls table which was ugly and error prone. It is
910 * simpler to do the fixup of offsets at initalization time than when
911 * decoding arguments.
914 quad_fixup(struct syscall *sc)
921 for (i = 0; i < sc->nargs; i++) {
922 /* This arg type is a dummy that doesn't use offset. */
923 if ((sc->args[i].type & ARG_MASK) == PipeFds)
926 assert(prev < sc->args[i].offset);
927 prev = sc->args[i].offset;
928 sc->args[i].offset += offset;
929 switch (sc->args[i].type & ARG_MASK) {
934 * 64-bit arguments on 32-bit powerpc must be
935 * 64-bit aligned. If the current offset is
936 * not aligned, the calling convention inserts
937 * a 32-bit pad argument that should be skipped.
939 if (sc->args[i].offset % 2 == 1) {
940 sc->args[i].offset++;
957 STAILQ_INIT(&syscalls);
958 for (sc = decoded_syscalls; sc->name != NULL; sc++) {
962 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
966 static struct syscall *
967 find_syscall(struct procabi *abi, u_int number)
969 struct extra_syscall *es;
971 if (number < nitems(abi->syscalls))
972 return (abi->syscalls[number]);
973 STAILQ_FOREACH(es, &abi->extra_syscalls, entries) {
974 if (es->number == number)
981 add_syscall(struct procabi *abi, u_int number, struct syscall *sc)
983 struct extra_syscall *es;
985 if (number < nitems(abi->syscalls)) {
986 assert(abi->syscalls[number] == NULL);
987 abi->syscalls[number] = sc;
989 es = malloc(sizeof(*es));
992 STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries);
997 * If/when the list gets big, it might be desirable to do it
998 * as a hash table or binary search.
1001 get_syscall(struct threadinfo *t, u_int number, u_int nargs)
1008 sc = find_syscall(t->proc->abi, number);
1012 name = sysdecode_syscallname(t->proc->abi->abi, number);
1014 asprintf(&new_name, "#%d", number);
1018 STAILQ_FOREACH(sc, &syscalls, entries) {
1019 if (strcmp(name, sc->name) == 0) {
1020 add_syscall(t->proc->abi, number, sc);
1026 /* It is unknown. Add it into the list. */
1028 fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
1032 sc = calloc(1, sizeof(struct syscall));
1034 if (new_name != NULL)
1038 for (i = 0; i < nargs; i++) {
1039 sc->args[i].offset = i;
1040 /* Treat all unknown arguments as LongHex. */
1041 sc->args[i].type = LongHex;
1043 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
1044 add_syscall(t->proc->abi, number, sc);
1050 * Copy a fixed amount of bytes from the process.
1053 get_struct(pid_t pid, void *offset, void *buf, int len)
1055 struct ptrace_io_desc iorequest;
1057 iorequest.piod_op = PIOD_READ_D;
1058 iorequest.piod_offs = offset;
1059 iorequest.piod_addr = buf;
1060 iorequest.piod_len = len;
1061 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
1066 #define MAXSIZE 4096
1069 * Copy a string from the process. Note that it is
1070 * expected to be a C string, but if max is set, it will
1071 * only get that much.
1074 get_string(pid_t pid, void *addr, int max)
1076 struct ptrace_io_desc iorequest;
1078 size_t offset, size, totalsize;
1084 /* Read up to the end of the current page. */
1085 size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE);
1090 buf = malloc(totalsize);
1094 iorequest.piod_op = PIOD_READ_D;
1095 iorequest.piod_offs = (char *)addr + offset;
1096 iorequest.piod_addr = buf + offset;
1097 iorequest.piod_len = size;
1098 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
1102 if (memchr(buf + offset, '\0', size) != NULL)
1105 if (totalsize < MAXSIZE && max == 0) {
1106 size = MAXSIZE - totalsize;
1107 if (size > PAGE_SIZE)
1109 nbuf = realloc(buf, totalsize + size);
1111 buf[totalsize - 1] = '\0';
1117 buf[totalsize - 1] = '\0';
1126 static char tmp[32];
1127 const char *signame;
1129 signame = sysdecode_signal(sig);
1130 if (signame == NULL) {
1131 snprintf(tmp, sizeof(tmp), "%d", sig);
1138 print_kevent(FILE *fp, struct kevent *ke, int input)
1141 switch (ke->filter) {
1147 case EVFILT_PROCDESC:
1148 fprintf(fp, "%ju", (uintmax_t)ke->ident);
1151 fputs(strsig2(ke->ident), fp);
1154 fprintf(fp, "%p", (void *)ke->ident);
1156 fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter),
1157 xlookup_bits(kevent_flags, ke->flags));
1158 switch (ke->filter) {
1161 fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp);
1164 fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp);
1167 case EVFILT_PROCDESC:
1168 fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp);
1171 fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp);
1176 ctrl = ke->fflags & NOTE_FFCTRLMASK;
1177 data = ke->fflags & NOTE_FFLAGSMASK;
1179 fputs(xlookup(kevent_user_ffctrl, ctrl), fp);
1180 if (ke->fflags & NOTE_TRIGGER)
1181 fputs("|NOTE_TRIGGER", fp);
1183 fprintf(fp, "|%#x", data);
1185 fprintf(fp, "%#x", data);
1190 fprintf(fp, "%#x", ke->fflags);
1192 fprintf(fp, ",%#jx,%p", (uintmax_t)ke->data, ke->udata);
1196 print_utrace(FILE *fp, void *utrace_addr, size_t len)
1198 unsigned char *utrace_buffer;
1201 if (sysdecode_utrace(fp, utrace_addr, len)) {
1206 utrace_buffer = utrace_addr;
1207 fprintf(fp, "%zu:", len);
1209 fprintf(fp, " %02x", *utrace_buffer++);
1214 * Converts a syscall argument into a string. Said string is
1215 * allocated via malloc(), so needs to be free()'d. sc is
1216 * a pointer to the syscall description (see above); args is
1217 * an array of all of the system call arguments.
1220 print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
1221 struct trussinfo *trussinfo)
1228 fp = open_memstream(&tmp, &tmplen);
1229 pid = trussinfo->curthread->proc->pid;
1230 switch (sc->type & ARG_MASK) {
1232 fprintf(fp, "0x%x", (int)args[sc->offset]);
1235 fprintf(fp, "0%o", (int)args[sc->offset]);
1238 fprintf(fp, "%d", (int)args[sc->offset]);
1241 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1246 if (get_struct(pid, (void *)args[sc->offset], &val,
1248 fprintf(fp, "{ %u }", val);
1250 fprintf(fp, "0x%lx", args[sc->offset]);
1254 fprintf(fp, "0x%lx", args[sc->offset]);
1257 fprintf(fp, "%ld", args[sc->offset]);
1260 fprintf(fp, "%zu", (size_t)args[sc->offset]);
1263 /* NULL-terminated string. */
1266 tmp2 = get_string(pid, (void*)args[sc->offset], 0);
1267 fprintf(fp, "\"%s\"", tmp2);
1273 * Binary block of data that might have printable characters.
1274 * XXX If type|OUT, assume that the length is the syscall's
1275 * return value. Otherwise, assume that the length of the block
1276 * is in the next syscall argument.
1278 int max_string = trussinfo->strsize;
1279 char tmp2[max_string + 1], *tmp3;
1286 len = args[sc->offset + 1];
1289 * Don't print more than max_string characters, to avoid word
1290 * wrap. If we have to truncate put some ... after the string.
1292 if (len > max_string) {
1296 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
1298 tmp3 = malloc(len * 4 + 1);
1300 if (strvisx(tmp3, tmp2, len,
1301 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1306 fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1310 fprintf(fp, "0x%lx", args[sc->offset]);
1320 char buf[PAGE_SIZE];
1327 * Only parse argv[] and environment arrays from exec calls
1330 if (((sc->type & ARG_MASK) == ExecArgs &&
1331 (trussinfo->flags & EXECVEARGS) == 0) ||
1332 ((sc->type & ARG_MASK) == ExecEnv &&
1333 (trussinfo->flags & EXECVEENVS) == 0)) {
1334 fprintf(fp, "0x%lx", args[sc->offset]);
1339 * Read a page of pointers at a time. Punt if the top-level
1340 * pointer is not aligned. Note that the first read is of
1343 addr = args[sc->offset];
1344 if (addr % sizeof(char *) != 0) {
1345 fprintf(fp, "0x%lx", args[sc->offset]);
1349 len = PAGE_SIZE - (addr & PAGE_MASK);
1350 if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
1351 fprintf(fp, "0x%lx", args[sc->offset]);
1358 while (u.strarray[i] != NULL) {
1359 string = get_string(pid, u.strarray[i], 0);
1360 fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1365 if (i == len / sizeof(char *)) {
1368 if (get_struct(pid, (void *)addr, u.buf, len) ==
1370 fprintf(fp, ", <inval>");
1381 fprintf(fp, "%ld", args[sc->offset]);
1384 fprintf(fp, "0x%lx", args[sc->offset]);
1389 unsigned long long ll;
1391 #if _BYTE_ORDER == _LITTLE_ENDIAN
1392 ll = (unsigned long long)args[sc->offset + 1] << 32 |
1395 ll = (unsigned long long)args[sc->offset] << 32 |
1396 args[sc->offset + 1];
1398 if ((sc->type & ARG_MASK) == Quad)
1399 fprintf(fp, "%lld", ll);
1401 fprintf(fp, "0x%llx", ll);
1408 if (get_struct(pid, (void *)args[sc->offset], &val,
1410 fprintf(fp, "{ 0x%jx }", (uintmax_t)val);
1412 fprintf(fp, "0x%lx", args[sc->offset]);
1416 fprintf(fp, "0x%lx", args[sc->offset]);
1421 if (retval[0] == -1)
1423 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
1424 fprintf(fp, "\"%s\"", tmp2);
1432 cmd = args[sc->offset];
1433 temp = sysdecode_ioctlname(cmd);
1437 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1438 cmd, cmd & IOC_OUT ? "R" : "",
1439 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1440 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1441 cmd & 0xFF, IOCPARM_LEN(cmd));
1448 if (get_struct(pid, (void *)args[sc->offset], &ts,
1450 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1453 fprintf(fp, "0x%lx", args[sc->offset]);
1457 struct timespec ts[2];
1461 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
1465 for (i = 0; i < nitems(ts); i++) {
1468 switch (ts[i].tv_nsec) {
1470 fprintf(fp, "UTIME_NOW");
1473 fprintf(fp, "UTIME_OMIT");
1476 fprintf(fp, "%jd.%09ld",
1477 (intmax_t)ts[i].tv_sec,
1484 fprintf(fp, "0x%lx", args[sc->offset]);
1490 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1492 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1495 fprintf(fp, "0x%lx", args[sc->offset]);
1499 struct timeval tv[2];
1501 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1503 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1504 (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1505 (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1507 fprintf(fp, "0x%lx", args[sc->offset]);
1511 struct itimerval itv;
1513 if (get_struct(pid, (void *)args[sc->offset], &itv,
1515 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1516 (intmax_t)itv.it_interval.tv_sec,
1517 itv.it_interval.tv_usec,
1518 (intmax_t)itv.it_value.tv_sec,
1519 itv.it_value.tv_usec);
1521 fprintf(fp, "0x%lx", args[sc->offset]);
1526 struct linux_socketcall_args largs;
1528 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
1529 sizeof(largs)) != -1)
1530 fprintf(fp, "{ %s, 0x%lx }",
1531 lookup(linux_socketcall_ops, largs.what, 10),
1532 (long unsigned int)largs.args);
1534 fprintf(fp, "0x%lx", args[sc->offset]);
1539 * XXX: A Pollfd argument expects the /next/ syscall argument
1540 * to be the number of fds in the array. This matches the poll
1544 int numfds = args[sc->offset + 1];
1545 size_t bytes = sizeof(struct pollfd) * numfds;
1548 if ((pfd = malloc(bytes)) == NULL)
1549 err(1, "Cannot malloc %zu bytes for pollfd array",
1551 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
1554 for (i = 0; i < numfds; i++) {
1555 fprintf(fp, " %d/%s", pfd[i].fd,
1556 xlookup_bits(poll_flags, pfd[i].events));
1560 fprintf(fp, "0x%lx", args[sc->offset]);
1567 * XXX: A Fd_set argument expects the /first/ syscall argument
1568 * to be the number of fds in the array. This matches the
1572 int numfds = args[0];
1573 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1576 if ((fds = malloc(bytes)) == NULL)
1577 err(1, "Cannot malloc %zu bytes for fd_set array",
1579 if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
1582 for (i = 0; i < numfds; i++) {
1583 if (FD_ISSET(i, fds))
1584 fprintf(fp, " %d", i);
1588 fprintf(fp, "0x%lx", args[sc->offset]);
1593 fputs(strsig2(args[sc->offset]), fp);
1600 sig = args[sc->offset];
1601 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
1602 sizeof(ss)) == -1) {
1603 fprintf(fp, "0x%lx", args[sc->offset]);
1608 for (i = 1; i < sys_nsig; i++) {
1609 if (sigismember(&ss, i)) {
1610 fprintf(fp, "%s%s", !first ? "|" : "",
1621 print_integer_arg(sysdecode_sigprocmask_how, fp,
1625 /* XXX: Output depends on the value of the previous argument. */
1626 if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
1627 sysdecode_fcntl_arg(fp, args[sc->offset - 1],
1628 args[sc->offset], 16);
1631 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
1634 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
1637 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
1640 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
1643 print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
1646 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
1649 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
1652 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
1655 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
1658 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]);
1661 print_integer_arg(sysdecode_pathconf_name, fp, args[sc->offset]);
1664 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
1668 struct sockaddr_in *lsin;
1669 struct sockaddr_in6 *lsin6;
1670 struct sockaddr_un *sun;
1671 struct sockaddr *sa;
1675 if (args[sc->offset] == 0) {
1681 * Extract the address length from the next argument. If
1682 * this is an output sockaddr (OUT is set), then the
1683 * next argument is a pointer to a socklen_t. Otherwise
1684 * the next argument contains a socklen_t by value.
1686 if (sc->type & OUT) {
1687 if (get_struct(pid, (void *)args[sc->offset + 1],
1688 &len, sizeof(len)) == -1) {
1689 fprintf(fp, "0x%lx", args[sc->offset]);
1693 len = args[sc->offset + 1];
1695 /* If the length is too small, just bail. */
1696 if (len < sizeof(*sa)) {
1697 fprintf(fp, "0x%lx", args[sc->offset]);
1701 sa = calloc(1, len);
1702 if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) {
1704 fprintf(fp, "0x%lx", args[sc->offset]);
1708 switch (sa->sa_family) {
1710 if (len < sizeof(*lsin))
1711 goto sockaddr_short;
1712 lsin = (struct sockaddr_in *)(void *)sa;
1713 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1714 fprintf(fp, "{ AF_INET %s:%d }", addr,
1715 htons(lsin->sin_port));
1718 if (len < sizeof(*lsin6))
1719 goto sockaddr_short;
1720 lsin6 = (struct sockaddr_in6 *)(void *)sa;
1721 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1723 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1724 htons(lsin6->sin6_port));
1727 sun = (struct sockaddr_un *)sa;
1728 fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1729 (int)(len - offsetof(struct sockaddr_un, sun_path)),
1735 "{ sa_len = %d, sa_family = %d, sa_data = {",
1736 (int)sa->sa_len, (int)sa->sa_family);
1737 for (q = (u_char *)sa->sa_data;
1738 q < (u_char *)sa + len; q++)
1739 fprintf(fp, "%s 0x%02x",
1740 q == (u_char *)sa->sa_data ? "" : ",",
1748 struct sigaction sa;
1750 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
1753 if (sa.sa_handler == SIG_DFL)
1754 fputs("SIG_DFL", fp);
1755 else if (sa.sa_handler == SIG_IGN)
1756 fputs("SIG_IGN", fp);
1758 fprintf(fp, "%p", sa.sa_handler);
1759 fprintf(fp, " %s ss_t }",
1760 xlookup_bits(sigaction_flags, sa.sa_flags));
1762 fprintf(fp, "0x%lx", args[sc->offset]);
1767 * XXX XXX: The size of the array is determined by either the
1768 * next syscall argument, or by the syscall return value,
1769 * depending on which argument number we are. This matches the
1770 * kevent syscall, but luckily that's the only syscall that uses
1778 if (sc->offset == 1)
1779 numevents = args[sc->offset+1];
1780 else if (sc->offset == 3 && retval[0] != -1)
1781 numevents = retval[0];
1783 if (numevents >= 0) {
1784 bytes = sizeof(struct kevent) * numevents;
1785 if ((ke = malloc(bytes)) == NULL)
1787 "Cannot malloc %zu bytes for kevent array",
1791 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
1794 for (i = 0; i < numevents; i++) {
1796 print_kevent(fp, &ke[i], sc->offset == 1);
1800 fprintf(fp, "0x%lx", args[sc->offset]);
1808 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1812 strmode(st.st_mode, mode);
1814 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1815 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1816 (long)st.st_blksize);
1818 fprintf(fp, "0x%lx", args[sc->offset]);
1823 struct freebsd11_stat st;
1825 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1829 strmode(st.st_mode, mode);
1831 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1832 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1833 (long)st.st_blksize);
1835 fprintf(fp, "0x%lx", args[sc->offset]);
1843 if (get_struct(pid, (void *)args[sc->offset], &buf,
1844 sizeof(buf)) != -1) {
1847 bzero(fsid, sizeof(fsid));
1848 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
1849 for (i = 0; i < sizeof(buf.f_fsid); i++)
1850 snprintf(&fsid[i*2],
1851 sizeof(fsid) - (i*2), "%02x",
1852 ((u_char *)&buf.f_fsid)[i]);
1855 "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
1856 "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
1857 buf.f_mntfromname, fsid);
1859 fprintf(fp, "0x%lx", args[sc->offset]);
1866 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
1869 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
1870 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
1871 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
1872 ru.ru_inblock, ru.ru_oublock);
1874 fprintf(fp, "0x%lx", args[sc->offset]);
1880 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
1882 fprintf(fp, "{ cur=%ju,max=%ju }",
1883 rl.rlim_cur, rl.rlim_max);
1885 fprintf(fp, "0x%lx", args[sc->offset]);
1891 if (get_struct(pid, (void *)args[sc->offset], &status,
1892 sizeof(status)) != -1) {
1894 if (WIFCONTINUED(status))
1895 fputs("CONTINUED", fp);
1896 else if (WIFEXITED(status))
1897 fprintf(fp, "EXITED,val=%d",
1898 WEXITSTATUS(status));
1899 else if (WIFSIGNALED(status))
1900 fprintf(fp, "SIGNALED,sig=%s%s",
1901 strsig2(WTERMSIG(status)),
1902 WCOREDUMP(status) ? ",cored" : "");
1904 fprintf(fp, "STOPPED,sig=%s",
1905 strsig2(WTERMSIG(status)));
1908 fprintf(fp, "0x%lx", args[sc->offset]);
1912 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]);
1915 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]);
1918 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]);
1921 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]);
1924 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]);
1927 print_mask_arg(sysdecode_atflags, fp, args[sc->offset]);
1930 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]);
1933 print_integer_arg(sysdecode_sysarch_number, fp,
1938 * The pipe() system call in the kernel returns its
1939 * two file descriptors via return values. However,
1940 * the interface exposed by libc is that pipe()
1941 * accepts a pointer to an array of descriptors.
1942 * Format the output to match the libc API by printing
1943 * the returned file descriptors as a fake argument.
1945 * Overwrite the first retval to signal a successful
1948 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
1955 len = args[sc->offset + 1];
1956 utrace_addr = calloc(1, len);
1957 if (get_struct(pid, (void *)args[sc->offset],
1958 (void *)utrace_addr, len) != -1)
1959 print_utrace(fp, utrace_addr, len);
1961 fprintf(fp, "0x%lx", args[sc->offset]);
1966 int descriptors[16];
1967 unsigned long i, ndescriptors;
1970 ndescriptors = args[sc->offset + 1];
1972 if (ndescriptors > nitems(descriptors)) {
1973 ndescriptors = nitems(descriptors);
1976 if (get_struct(pid, (void *)args[sc->offset],
1977 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
1979 for (i = 0; i < ndescriptors; i++)
1980 fprintf(fp, i == 0 ? " %d" : ", %d",
1982 fprintf(fp, truncated ? ", ... }" : " }");
1984 fprintf(fp, "0x%lx", args[sc->offset]);
1988 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]);
1990 case CapFcntlRights: {
1993 if (sc->type & OUT) {
1994 if (get_struct(pid, (void *)args[sc->offset], &rights,
1995 sizeof(rights)) == -1) {
1996 fprintf(fp, "0x%lx", args[sc->offset]);
2000 rights = args[sc->offset];
2001 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights);
2005 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]);
2010 if (!sysdecode_fileflags(fp, args[sc->offset], &rem))
2011 fprintf(fp, "0x%x", rem);
2013 fprintf(fp, "|0x%x", rem);
2017 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]);
2020 print_integer_arg(sysdecode_getfsstat_mode, fp,
2024 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]);
2026 case Kldunloadflags:
2027 print_integer_arg(sysdecode_kldunload_flags, fp,
2031 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]);
2034 fprintf(fp, "%u", (socklen_t)args[sc->offset]);
2036 case Sockprotocol: {
2038 int domain, protocol;
2040 domain = args[sc->offset - 2];
2041 protocol = args[sc->offset];
2042 if (protocol == 0) {
2045 temp = sysdecode_socket_protocol(domain, protocol);
2049 fprintf(fp, "%d", protocol);
2055 print_integer_arg(sysdecode_sockopt_level, fp,
2062 level = args[sc->offset - 1];
2063 name = args[sc->offset];
2064 temp = sysdecode_sockopt_name(level, name);
2068 fprintf(fp, "%d", name);
2073 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]);
2076 cap_rights_t rights;
2078 if (get_struct(pid, (void *)args[sc->offset], &rights,
2079 sizeof(rights)) != -1) {
2081 sysdecode_cap_rights(fp, &rights);
2084 fprintf(fp, "0x%lx", args[sc->offset]);
2088 print_integer_arg(sysdecode_acltype, fp, args[sc->offset]);
2090 case Extattrnamespace:
2091 print_integer_arg(sysdecode_extattrnamespace, fp,
2095 print_integer_arg(sysdecode_minherit_inherit, fp,
2099 print_mask_arg(sysdecode_mlockall_flags, fp, args[sc->offset]);
2102 print_mask_arg(sysdecode_mount_flags, fp, args[sc->offset]);
2105 print_mask_arg(sysdecode_msync_flags, fp, args[sc->offset]);
2108 print_integer_arg(sysdecode_prio_which, fp, args[sc->offset]);
2111 print_integer_arg(sysdecode_ptrace_request, fp,
2115 if (!sysdecode_quotactl_cmd(fp, args[sc->offset]))
2116 fprintf(fp, "%#x", (int)args[sc->offset]);
2119 print_mask_arg(sysdecode_reboot_howto, fp, args[sc->offset]);
2122 print_integer_arg(sysdecode_rtprio_function, fp,
2126 print_integer_arg(sysdecode_scheduler_policy, fp,
2130 struct sched_param sp;
2132 if (get_struct(pid, (void *)args[sc->offset], &sp,
2134 fprintf(fp, "{ %d }", sp.sched_priority);
2136 fprintf(fp, "0x%lx", args[sc->offset]);
2142 if (get_struct(pid, (void *)args[sc->offset], &sig,
2144 fprintf(fp, "{ %s }", strsig2(sig));
2146 fprintf(fp, "0x%lx", args[sc->offset]);
2152 if (get_struct(pid, (void *)args[sc->offset], &si,
2153 sizeof(si)) != -1) {
2154 fprintf(fp, "{ signo=%s", strsig2(si.si_signo));
2155 decode_siginfo(fp, &si);
2158 fprintf(fp, "0x%lx", args[sc->offset]);
2162 case CloudABIAdvice:
2163 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
2165 case CloudABIClockID:
2166 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2168 case ClouduABIFDSFlags:
2169 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2171 case CloudABIFDStat: {
2172 cloudabi_fdstat_t fds;
2173 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds))
2175 fprintf(fp, "{ %s, ",
2176 xlookup(cloudabi_filetype, fds.fs_filetype));
2177 fprintf(fp, "%s, ... }",
2178 xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2180 fprintf(fp, "0x%lx", args[sc->offset]);
2183 case CloudABIFileStat: {
2184 cloudabi_filestat_t fsb;
2185 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb))
2187 fprintf(fp, "{ %s, %ju }",
2188 xlookup(cloudabi_filetype, fsb.st_filetype),
2189 (uintmax_t)fsb.st_size);
2191 fprintf(fp, "0x%lx", args[sc->offset]);
2194 case CloudABIFileType:
2195 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2197 case CloudABIFSFlags:
2198 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2200 case CloudABILookup:
2201 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2202 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2203 (int)args[sc->offset]);
2205 fprintf(fp, "%d", (int)args[sc->offset]);
2207 case CloudABIMFlags:
2208 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2211 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2213 case CloudABIMSFlags:
2214 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2216 case CloudABIOFlags:
2217 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2219 case CloudABISDFlags:
2220 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2222 case CloudABISignal:
2223 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2225 case CloudABITimestamp:
2226 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2227 args[sc->offset] % 1000000000);
2229 case CloudABIULFlags:
2230 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2232 case CloudABIWhence:
2233 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2237 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2244 * Print (to outfile) the system call and its arguments.
2247 print_syscall(struct trussinfo *trussinfo)
2249 struct threadinfo *t;
2254 t = trussinfo->curthread;
2256 name = t->cs.sc->name;
2257 nargs = t->cs.nargs;
2258 s_args = t->cs.s_args;
2260 len = print_line_prefix(trussinfo);
2261 len += fprintf(trussinfo->outfile, "%s(", name);
2263 for (i = 0; i < nargs; i++) {
2264 if (s_args[i] != NULL)
2265 len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2267 len += fprintf(trussinfo->outfile,
2268 "<missing argument>");
2269 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2272 len += fprintf(trussinfo->outfile, ")");
2273 for (i = 0; i < 6 - (len / 8); i++)
2274 fprintf(trussinfo->outfile, "\t");
2278 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
2280 struct timespec timediff;
2281 struct threadinfo *t;
2285 t = trussinfo->curthread;
2287 if (trussinfo->flags & COUNTONLY) {
2288 timespecsubt(&t->after, &t->before, &timediff);
2289 timespecadd(&sc->time, &timediff, &sc->time);
2296 print_syscall(trussinfo);
2297 fflush(trussinfo->outfile);
2299 if (retval == NULL) {
2301 * This system call resulted in the current thread's exit,
2302 * so there is no return value or error to display.
2304 fprintf(trussinfo->outfile, "\n");
2309 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi,
2311 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
2312 error == INT_MAX ? "Unknown error" : strerror(error));
2315 else if (sc->ret_type == 2) {
2318 #if _BYTE_ORDER == _LITTLE_ENDIAN
2319 off = (off_t)retval[1] << 32 | retval[0];
2321 off = (off_t)retval[0] << 32 | retval[1];
2323 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2328 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
2333 print_summary(struct trussinfo *trussinfo)
2335 struct timespec total = {0, 0};
2339 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2340 "syscall", "seconds", "calls", "errors");
2342 STAILQ_FOREACH(sc, &syscalls, entries)
2344 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2345 sc->name, (intmax_t)sc->time.tv_sec,
2346 sc->time.tv_nsec, sc->ncalls, sc->nerror);
2347 timespecadd(&total, &sc->time, &total);
2348 ncall += sc->ncalls;
2349 nerror += sc->nerror;
2351 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2352 "", "-------------", "-------", "-------");
2353 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2354 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);