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>
51 #include <machine/sysarch.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
65 #include <sysdecode.h>
69 #include <contrib/cloudabi/cloudabi_types_common.h>
76 * This should probably be in its own file, sorted alphabetically.
78 static struct syscall decoded_syscalls[] = {
80 { .name = "__acl_aclcheck_fd", .ret_type = 1, .nargs = 3,
81 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
82 { .name = "__acl_aclcheck_file", .ret_type = 1, .nargs = 3,
83 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
84 { .name = "__acl_aclcheck_link", .ret_type = 1, .nargs = 3,
85 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
86 { .name = "__acl_delete_fd", .ret_type = 1, .nargs = 2,
87 .args = { { Int, 0 }, { Acltype, 1 } } },
88 { .name = "__acl_delete_file", .ret_type = 1, .nargs = 2,
89 .args = { { Name, 0 }, { Acltype, 1 } } },
90 { .name = "__acl_delete_link", .ret_type = 1, .nargs = 2,
91 .args = { { Name, 0 }, { Acltype, 1 } } },
92 { .name = "__acl_get_fd", .ret_type = 1, .nargs = 3,
93 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
94 { .name = "__acl_get_file", .ret_type = 1, .nargs = 3,
95 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
96 { .name = "__acl_get_link", .ret_type = 1, .nargs = 3,
97 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
98 { .name = "__acl_set_fd", .ret_type = 1, .nargs = 3,
99 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
100 { .name = "__acl_set_file", .ret_type = 1, .nargs = 3,
101 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
102 { .name = "__acl_set_link", .ret_type = 1, .nargs = 3,
103 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
104 { .name = "__cap_rights_get", .ret_type = 1, .nargs = 3,
105 .args = { { Int, 0 }, { Int, 1 }, { CapRights | OUT, 2 } } },
106 { .name = "__getcwd", .ret_type = 1, .nargs = 2,
107 .args = { { Name | OUT, 0 }, { Int, 1 } } },
108 { .name = "_umtx_op", .ret_type = 1, .nargs = 5,
109 .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
111 { .name = "accept", .ret_type = 1, .nargs = 3,
112 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
113 { .name = "access", .ret_type = 1, .nargs = 2,
114 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
115 { .name = "bind", .ret_type = 1, .nargs = 3,
116 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
117 { .name = "bindat", .ret_type = 1, .nargs = 4,
118 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
120 { .name = "break", .ret_type = 1, .nargs = 1,
121 .args = { { Ptr, 0 } } },
122 { .name = "cap_fcntls_get", .ret_type = 1, .nargs = 2,
123 .args = { { Int, 0 }, { CapFcntlRights | OUT, 1 } } },
124 { .name = "cap_fcntls_limit", .ret_type = 1, .nargs = 2,
125 .args = { { Int, 0 }, { CapFcntlRights, 1 } } },
126 { .name = "cap_getmode", .ret_type = 1, .nargs = 1,
127 .args = { { PUInt | OUT, 0 } } },
128 { .name = "cap_rights_limit", .ret_type = 1, .nargs = 2,
129 .args = { { Int, 0 }, { CapRights, 1 } } },
130 { .name = "chdir", .ret_type = 1, .nargs = 1,
131 .args = { { Name, 0 } } },
132 { .name = "chflags", .ret_type = 1, .nargs = 2,
133 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
134 { .name = "chflagsat", .ret_type = 1, .nargs = 4,
135 .args = { { Atfd, 0 }, { Name | IN, 1 }, { FileFlags, 2 },
137 { .name = "chmod", .ret_type = 1, .nargs = 2,
138 .args = { { Name, 0 }, { Octal, 1 } } },
139 { .name = "chown", .ret_type = 1, .nargs = 3,
140 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
141 { .name = "chroot", .ret_type = 1, .nargs = 1,
142 .args = { { Name, 0 } } },
143 { .name = "clock_gettime", .ret_type = 1, .nargs = 2,
144 .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
145 { .name = "close", .ret_type = 1, .nargs = 1,
146 .args = { { Int, 0 } } },
147 { .name = "connect", .ret_type = 1, .nargs = 3,
148 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
149 { .name = "connectat", .ret_type = 1, .nargs = 4,
150 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
152 { .name = "dup", .ret_type = 1, .nargs = 1,
153 .args = { { Int, 0 } } },
154 { .name = "dup2", .ret_type = 1, .nargs = 2,
155 .args = { { Int, 0 }, { Int, 1 } } },
156 { .name = "eaccess", .ret_type = 1, .nargs = 2,
157 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
158 { .name = "execve", .ret_type = 1, .nargs = 3,
159 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
160 { ExecEnv | IN, 2 } } },
161 { .name = "exit", .ret_type = 0, .nargs = 1,
162 .args = { { Hex, 0 } } },
163 { .name = "extattr_delete_fd", .ret_type = 1, .nargs = 3,
164 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
165 { .name = "extattr_delete_file", .ret_type = 1, .nargs = 3,
166 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
167 { .name = "extattr_delete_link", .ret_type = 1, .nargs = 3,
168 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
169 { .name = "extattr_get_fd", .ret_type = 1, .nargs = 5,
170 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
171 { BinString | OUT, 3 }, { Sizet, 4 } } },
172 { .name = "extattr_get_file", .ret_type = 1, .nargs = 5,
173 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
174 { BinString | OUT, 3 }, { Sizet, 4 } } },
175 { .name = "extattr_get_link", .ret_type = 1, .nargs = 5,
176 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
177 { BinString | OUT, 3 }, { Sizet, 4 } } },
178 { .name = "extattr_list_fd", .ret_type = 1, .nargs = 4,
179 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
181 { .name = "extattr_list_file", .ret_type = 1, .nargs = 4,
182 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
184 { .name = "extattr_list_link", .ret_type = 1, .nargs = 4,
185 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
187 { .name = "extattr_set_fd", .ret_type = 1, .nargs = 5,
188 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
189 { BinString | IN, 3 }, { Sizet, 4 } } },
190 { .name = "extattr_set_file", .ret_type = 1, .nargs = 5,
191 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
192 { BinString | IN, 3 }, { Sizet, 4 } } },
193 { .name = "extattr_set_link", .ret_type = 1, .nargs = 5,
194 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
195 { BinString | IN, 3 }, { Sizet, 4 } } },
196 { .name = "extattrctl", .ret_type = 1, .nargs = 5,
197 .args = { { Name, 0 }, { Hex, 1 }, { Name, 2 },
198 { Extattrnamespace, 3 }, { Name, 4 } } },
199 { .name = "faccessat", .ret_type = 1, .nargs = 4,
200 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
202 { .name = "fchflags", .ret_type = 1, .nargs = 2,
203 .args = { { Int, 0 }, { FileFlags, 1 } } },
204 { .name = "fchmod", .ret_type = 1, .nargs = 2,
205 .args = { { Int, 0 }, { Octal, 1 } } },
206 { .name = "fchmodat", .ret_type = 1, .nargs = 4,
207 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
208 { .name = "fchown", .ret_type = 1, .nargs = 3,
209 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
210 { .name = "fchownat", .ret_type = 1, .nargs = 5,
211 .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
213 { .name = "fcntl", .ret_type = 1, .nargs = 3,
214 .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
215 { .name = "flock", .ret_type = 1, .nargs = 2,
216 .args = { { Int, 0 }, { Flockop, 1 } } },
217 { .name = "fstat", .ret_type = 1, .nargs = 2,
218 .args = { { Int, 0 }, { Stat | OUT, 1 } } },
219 { .name = "fstatat", .ret_type = 1, .nargs = 4,
220 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
222 { .name = "fstatfs", .ret_type = 1, .nargs = 2,
223 .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
224 { .name = "ftruncate", .ret_type = 1, .nargs = 2,
225 .args = { { Int | IN, 0 }, { QuadHex | IN, 1 } } },
226 { .name = "futimens", .ret_type = 1, .nargs = 2,
227 .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
228 { .name = "futimes", .ret_type = 1, .nargs = 2,
229 .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
230 { .name = "futimesat", .ret_type = 1, .nargs = 3,
231 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
232 { .name = "getdirentries", .ret_type = 1, .nargs = 4,
233 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
234 { PQuadHex | OUT, 3 } } },
235 { .name = "getfsstat", .ret_type = 1, .nargs = 3,
236 .args = { { Ptr, 0 }, { Long, 1 }, { Getfsstatmode, 2 } } },
237 { .name = "getitimer", .ret_type = 1, .nargs = 2,
238 .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
239 { .name = "getpeername", .ret_type = 1, .nargs = 3,
240 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
241 { .name = "getpgid", .ret_type = 1, .nargs = 1,
242 .args = { { Int, 0 } } },
243 { .name = "getrlimit", .ret_type = 1, .nargs = 2,
244 .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
245 { .name = "getrusage", .ret_type = 1, .nargs = 2,
246 .args = { { RusageWho, 0 }, { Rusage | OUT, 1 } } },
247 { .name = "getsid", .ret_type = 1, .nargs = 1,
248 .args = { { Int, 0 } } },
249 { .name = "getsockname", .ret_type = 1, .nargs = 3,
250 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
251 { .name = "getsockopt", .ret_type = 1, .nargs = 5,
252 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
253 { Ptr | OUT, 3 }, { Ptr | OUT, 4 } } },
254 { .name = "gettimeofday", .ret_type = 1, .nargs = 2,
255 .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
256 { .name = "ioctl", .ret_type = 1, .nargs = 3,
257 .args = { { Int, 0 }, { Ioctl, 1 }, { Ptr, 2 } } },
258 { .name = "kevent", .ret_type = 1, .nargs = 6,
259 .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
260 { Int, 4 }, { Timespec, 5 } } },
261 { .name = "kill", .ret_type = 1, .nargs = 2,
262 .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
263 { .name = "kldfind", .ret_type = 1, .nargs = 1,
264 .args = { { Name | IN, 0 } } },
265 { .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
266 .args = { { Int, 0 } } },
267 { .name = "kldload", .ret_type = 1, .nargs = 1,
268 .args = { { Name | IN, 0 } } },
269 { .name = "kldnext", .ret_type = 1, .nargs = 1,
270 .args = { { Int, 0 } } },
271 { .name = "kldstat", .ret_type = 1, .nargs = 2,
272 .args = { { Int, 0 }, { Ptr, 1 } } },
273 { .name = "kldsym", .ret_type = 1, .nargs = 3,
274 .args = { { Int, 0 }, { Kldsymcmd, 1 }, { Ptr, 2 } } },
275 { .name = "kldunload", .ret_type = 1, .nargs = 1,
276 .args = { { Int, 0 } } },
277 { .name = "kldunloadf", .ret_type = 1, .nargs = 2,
278 .args = { { Int, 0 }, { Kldunloadflags, 1 } } },
279 { .name = "kse_release", .ret_type = 0, .nargs = 1,
280 .args = { { Timespec, 0 } } },
281 { .name = "lchflags", .ret_type = 1, .nargs = 2,
282 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
283 { .name = "lchmod", .ret_type = 1, .nargs = 2,
284 .args = { { Name, 0 }, { Octal, 1 } } },
285 { .name = "lchown", .ret_type = 1, .nargs = 3,
286 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
287 { .name = "link", .ret_type = 1, .nargs = 2,
288 .args = { { Name, 0 }, { Name, 1 } } },
289 { .name = "linkat", .ret_type = 1, .nargs = 5,
290 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
292 { .name = "listen", .ret_type = 1, .nargs = 2,
293 .args = { { Int, 0 }, { Int, 1 } } },
294 { .name = "lseek", .ret_type = 2, .nargs = 3,
295 .args = { { Int, 0 }, { QuadHex, 1 }, { Whence, 2 } } },
296 { .name = "lstat", .ret_type = 1, .nargs = 2,
297 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
298 { .name = "lutimes", .ret_type = 1, .nargs = 2,
299 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
300 { .name = "madvise", .ret_type = 1, .nargs = 3,
301 .args = { { Ptr, 0 }, { Sizet, 1 }, { Madvice, 2 } } },
302 { .name = "mkdir", .ret_type = 1, .nargs = 2,
303 .args = { { Name, 0 }, { Octal, 1 } } },
304 { .name = "mkdirat", .ret_type = 1, .nargs = 3,
305 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
306 { .name = "mkfifo", .ret_type = 1, .nargs = 2,
307 .args = { { Name, 0 }, { Octal, 1 } } },
308 { .name = "mkfifoat", .ret_type = 1, .nargs = 3,
309 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
310 { .name = "mknod", .ret_type = 1, .nargs = 3,
311 .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
312 { .name = "mknodat", .ret_type = 1, .nargs = 4,
313 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
314 { .name = "mmap", .ret_type = 1, .nargs = 6,
315 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
316 { Int, 4 }, { QuadHex, 5 } } },
317 { .name = "modfind", .ret_type = 1, .nargs = 1,
318 .args = { { Name | IN, 0 } } },
319 { .name = "mount", .ret_type = 1, .nargs = 4,
320 .args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } },
321 { .name = "mprotect", .ret_type = 1, .nargs = 3,
322 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 } } },
323 { .name = "munmap", .ret_type = 1, .nargs = 2,
324 .args = { { Ptr, 0 }, { Sizet, 1 } } },
325 { .name = "nanosleep", .ret_type = 1, .nargs = 1,
326 .args = { { Timespec, 0 } } },
327 { .name = "open", .ret_type = 1, .nargs = 3,
328 .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
329 { .name = "openat", .ret_type = 1, .nargs = 4,
330 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
332 { .name = "pathconf", .ret_type = 1, .nargs = 2,
333 .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
334 { .name = "pipe", .ret_type = 1, .nargs = 1,
335 .args = { { PipeFds | OUT, 0 } } },
336 { .name = "pipe2", .ret_type = 1, .nargs = 2,
337 .args = { { Ptr, 0 }, { Pipe2, 1 } } },
338 { .name = "poll", .ret_type = 1, .nargs = 3,
339 .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
340 { .name = "posix_fadvise", .ret_type = 1, .nargs = 4,
341 .args = { { Int, 0 }, { QuadHex, 1 }, { QuadHex, 2 },
343 { .name = "posix_openpt", .ret_type = 1, .nargs = 1,
344 .args = { { Open, 0 } } },
345 { .name = "pread", .ret_type = 1, .nargs = 4,
346 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
348 { .name = "procctl", .ret_type = 1, .nargs = 4,
349 .args = { { Idtype, 0 }, { Quad, 1 }, { Procctl, 2 }, { Ptr, 3 } } },
350 { .name = "pwrite", .ret_type = 1, .nargs = 4,
351 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
353 { .name = "read", .ret_type = 1, .nargs = 3,
354 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 } } },
355 { .name = "readlink", .ret_type = 1, .nargs = 3,
356 .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Sizet, 2 } } },
357 { .name = "readlinkat", .ret_type = 1, .nargs = 4,
358 .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
360 { .name = "recvfrom", .ret_type = 1, .nargs = 6,
361 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
362 { Msgflags, 3 }, { Sockaddr | OUT, 4 },
363 { Ptr | OUT, 5 } } },
364 { .name = "recvmsg", .ret_type = 1, .nargs = 3,
365 .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
366 { .name = "rename", .ret_type = 1, .nargs = 2,
367 .args = { { Name, 0 }, { Name, 1 } } },
368 { .name = "renameat", .ret_type = 1, .nargs = 4,
369 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
370 { .name = "rfork", .ret_type = 1, .nargs = 1,
371 .args = { { Rforkflags, 0 } } },
372 { .name = "rmdir", .ret_type = 1, .nargs = 1,
373 .args = { { Name, 0 } } },
374 { .name = "sctp_generic_recvmsg", .ret_type = 1, .nargs = 7,
375 .args = { { Int, 0 }, { Ptr | IN, 1 }, { Int, 2 },
376 { Sockaddr | OUT, 3 }, { Ptr | OUT, 4 }, { Ptr | OUT, 5 },
377 { Ptr | OUT, 6 } } },
378 { .name = "sctp_generic_sendmsg", .ret_type = 1, .nargs = 7,
379 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
380 { Sockaddr | IN, 3 }, { Socklent, 4 }, { Ptr | IN, 5 },
382 { .name = "select", .ret_type = 1, .nargs = 5,
383 .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
385 { .name = "sendmsg", .ret_type = 1, .nargs = 3,
386 .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
387 { .name = "sendto", .ret_type = 1, .nargs = 6,
388 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
389 { Msgflags, 3 }, { Sockaddr | IN, 4 },
390 { Socklent | IN, 5 } } },
391 { .name = "setitimer", .ret_type = 1, .nargs = 3,
392 .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
393 { .name = "setrlimit", .ret_type = 1, .nargs = 2,
394 .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
395 { .name = "setsockopt", .ret_type = 1, .nargs = 5,
396 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
397 { Ptr | IN, 3 }, { Socklent, 4 } } },
398 { .name = "shutdown", .ret_type = 1, .nargs = 2,
399 .args = { { Int, 0 }, { Shutdown, 1 } } },
400 { .name = "sigaction", .ret_type = 1, .nargs = 3,
401 .args = { { Signal, 0 }, { Sigaction | IN, 1 },
402 { Sigaction | OUT, 2 } } },
403 { .name = "sigpending", .ret_type = 1, .nargs = 1,
404 .args = { { Sigset | OUT, 0 } } },
405 { .name = "sigprocmask", .ret_type = 1, .nargs = 3,
406 .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
407 { .name = "sigqueue", .ret_type = 1, .nargs = 3,
408 .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
409 { .name = "sigreturn", .ret_type = 1, .nargs = 1,
410 .args = { { Ptr, 0 } } },
411 { .name = "sigsuspend", .ret_type = 1, .nargs = 1,
412 .args = { { Sigset | IN, 0 } } },
413 { .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
414 .args = { { Sigset | IN, 0 }, { Ptr, 1 }, { Timespec | IN, 2 } } },
415 { .name = "sigwait", .ret_type = 1, .nargs = 2,
416 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
417 { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
418 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
419 { .name = "socket", .ret_type = 1, .nargs = 3,
420 .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Sockprotocol, 2 } } },
421 { .name = "stat", .ret_type = 1, .nargs = 2,
422 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
423 { .name = "statfs", .ret_type = 1, .nargs = 2,
424 .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } },
425 { .name = "symlink", .ret_type = 1, .nargs = 2,
426 .args = { { Name, 0 }, { Name, 1 } } },
427 { .name = "symlinkat", .ret_type = 1, .nargs = 3,
428 .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } },
429 { .name = "sysarch", .ret_type = 1, .nargs = 2,
430 .args = { { Sysarch, 0 }, { Ptr, 1 } } },
431 { .name = "thr_kill", .ret_type = 1, .nargs = 2,
432 .args = { { Long, 0 }, { Signal, 1 } } },
433 { .name = "thr_self", .ret_type = 1, .nargs = 1,
434 .args = { { Ptr, 0 } } },
435 { .name = "truncate", .ret_type = 1, .nargs = 2,
436 .args = { { Name | IN, 0 }, { QuadHex | IN, 1 } } },
439 { .name = "umount", .ret_type = 1, .nargs = 2,
440 .args = { { Name, 0 }, { Int, 2 } } },
442 { .name = "unlink", .ret_type = 1, .nargs = 1,
443 .args = { { Name, 0 } } },
444 { .name = "unlinkat", .ret_type = 1, .nargs = 3,
445 .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
446 { .name = "unmount", .ret_type = 1, .nargs = 2,
447 .args = { { Name, 0 }, { Int, 1 } } },
448 { .name = "utimensat", .ret_type = 1, .nargs = 4,
449 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
451 { .name = "utimes", .ret_type = 1, .nargs = 2,
452 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
453 { .name = "utrace", .ret_type = 1, .nargs = 1,
454 .args = { { Utrace, 0 } } },
455 { .name = "wait4", .ret_type = 1, .nargs = 4,
456 .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
457 { Rusage | OUT, 3 } } },
458 { .name = "wait6", .ret_type = 1, .nargs = 6,
459 .args = { { Idtype, 0 }, { Quad, 1 }, { ExitStatus | OUT, 2 },
460 { Waitoptions, 3 }, { Rusage | OUT, 4 }, { Ptr, 5 } } },
461 { .name = "write", .ret_type = 1, .nargs = 3,
462 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 } } },
465 { .name = "linux_access", .ret_type = 1, .nargs = 2,
466 .args = { { Name, 0 }, { Accessmode, 1 } } },
467 { .name = "linux_execve", .ret_type = 1, .nargs = 3,
468 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
469 { ExecEnv | IN, 2 } } },
470 { .name = "linux_lseek", .ret_type = 2, .nargs = 3,
471 .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
472 { .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
473 .args = { { Name | IN, 0 }, { Int, 1 } } },
474 { .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
475 .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
476 { .name = "linux_newstat", .ret_type = 1, .nargs = 2,
477 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
478 { .name = "linux_open", .ret_type = 1, .nargs = 3,
479 .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
480 { .name = "linux_readlink", .ret_type = 1, .nargs = 3,
481 .args = { { Name, 0 }, { Name | OUT, 1 }, { Sizet, 2 } } },
482 { .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
483 .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
484 { .name = "linux_stat64", .ret_type = 1, .nargs = 2,
485 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
487 /* CloudABI system calls. */
488 { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
489 .args = { { CloudABIClockID, 0 } } },
490 { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
491 .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
492 { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
493 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
494 { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
495 .args = { { Int, 0 } } },
496 { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
497 .args = { { CloudABIFileType, 0 } } },
498 { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
499 .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
500 { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
501 .args = { { Int, 0 } } },
502 { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
503 .args = { { Int, 0 } } },
504 { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
505 .args = { { Int, 0 }, { Int, 1 } } },
506 { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
507 .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
508 { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
509 .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
510 { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
511 .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
512 { ClouduABIFDSFlags, 2 } } },
513 { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
514 .args = { { Int, 0 } } },
515 { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
516 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
517 { CloudABIAdvice, 3 } } },
518 { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
519 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
520 { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
521 .args = { { Int, 0 }, { BinString | IN, 1 },
522 { CloudABIFileType, 3 } } },
523 { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
524 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
525 { Int, 3 }, { BinString | IN, 4 } } },
526 { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
527 .args = { { Int, 0 }, { BinString | IN, 1 },
528 { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
529 { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
530 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
532 { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
533 .args = { { Int, 0 }, { BinString | IN, 1 },
534 { BinString | OUT, 3 }, { Int, 4 } } },
535 { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
536 .args = { { Int, 0 }, { BinString | IN, 1 },
537 { Int, 3 }, { BinString | IN, 4 } } },
538 { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
539 .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
540 { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
541 .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
542 { CloudABIFSFlags, 2 } } },
543 { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
544 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
545 { CloudABIFileStat | OUT, 3 } } },
546 { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
547 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
548 { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
549 { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
550 .args = { { BinString | IN, 0 },
551 { Int, 2 }, { BinString | IN, 3 } } },
552 { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
553 .args = { { Int, 0 }, { BinString | IN, 1 },
554 { CloudABIULFlags, 3 } } },
555 { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
556 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
557 { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
558 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
559 { .name = "cloudabi_sys_mem_lock", .ret_type = 1, .nargs = 2,
560 .args = { { Ptr, 0 }, { Int, 1 } } },
561 { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
562 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
563 { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
564 { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
565 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
566 { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
567 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
568 { .name = "cloudabi_sys_mem_unlock", .ret_type = 1, .nargs = 2,
569 .args = { { Ptr, 0 }, { Int, 1 } } },
570 { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
571 .args = { { Ptr, 0 }, { Int, 1 } } },
572 { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
573 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
574 { IntArray, 3 }, { Int, 4 } } },
575 { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
576 .args = { { Int, 0 } } },
577 { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
578 { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
579 .args = { { CloudABISignal, 0 } } },
580 { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
581 .args = { { BinString | OUT, 0 }, { Int, 1 } } },
582 { .name = "cloudabi_sys_sock_accept", .ret_type = 1, .nargs = 2,
583 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 } } },
584 { .name = "cloudabi_sys_sock_bind", .ret_type = 1, .nargs = 3,
585 .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
586 { .name = "cloudabi_sys_sock_connect", .ret_type = 1, .nargs = 3,
587 .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
588 { .name = "cloudabi_sys_sock_listen", .ret_type = 1, .nargs = 2,
589 .args = { { Int, 0 }, { Int, 1 } } },
590 { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
591 .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
592 { .name = "cloudabi_sys_sock_stat_get", .ret_type = 1, .nargs = 3,
593 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 },
594 { CloudABISSFlags, 2 } } },
595 { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
596 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
597 { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
601 static STAILQ_HEAD(, syscall) syscalls;
603 /* Xlat idea taken from strace */
609 #define X(a) { a, #a },
610 #define XEND { 0, NULL }
612 static struct xlat kevent_filters[] = {
613 X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
614 X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
615 X(EVFILT_PROCDESC) X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER)
616 X(EVFILT_SENDFILE) XEND
619 static struct xlat kevent_flags[] = {
620 X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
621 X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH) X(EV_FORCEONESHOT)
622 X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
625 static struct xlat kevent_user_ffctrl[] = {
626 X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
630 static struct xlat kevent_rdwr_fflags[] = {
631 X(NOTE_LOWAT) X(NOTE_FILE_POLL) XEND
634 static struct xlat kevent_vnode_fflags[] = {
635 X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB)
636 X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND
639 static struct xlat kevent_proc_fflags[] = {
640 X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR)
644 static struct xlat kevent_timer_fflags[] = {
645 X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS)
649 static struct xlat poll_flags[] = {
650 X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
651 X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
652 X(POLLWRBAND) X(POLLINIGNEOF) XEND
655 static struct xlat sigaction_flags[] = {
656 X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
657 X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
660 static struct xlat pathconf_arg[] = {
661 X(_PC_LINK_MAX) X(_PC_MAX_CANON) X(_PC_MAX_INPUT)
662 X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF)
663 X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE)
664 X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO)
665 X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS)
666 X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE)
667 X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
668 X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
669 X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
670 X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND
673 static struct xlat at_flags[] = {
674 X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW)
678 static struct xlat sysarch_ops[] = {
679 #if defined(__i386__) || defined(__amd64__)
680 X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM)
681 X(I386_VM86) X(I386_GET_FSBASE) X(I386_SET_FSBASE) X(I386_GET_GSBASE)
682 X(I386_SET_GSBASE) X(I386_GET_XFPUSTATE) X(AMD64_GET_FSBASE)
683 X(AMD64_SET_FSBASE) X(AMD64_GET_GSBASE) X(AMD64_SET_GSBASE)
684 X(AMD64_GET_XFPUSTATE)
689 static struct xlat linux_socketcall_ops[] = {
690 X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
691 X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
692 X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
693 X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
694 X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
699 #define X(a) { CLOUDABI_##a, #a },
701 static struct xlat cloudabi_advice[] = {
702 X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
703 X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
707 static struct xlat cloudabi_clockid[] = {
708 X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
709 X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
713 static struct xlat cloudabi_errno[] = {
714 X(E2BIG) X(EACCES) X(EADDRINUSE) X(EADDRNOTAVAIL)
715 X(EAFNOSUPPORT) X(EAGAIN) X(EALREADY) X(EBADF) X(EBADMSG)
716 X(EBUSY) X(ECANCELED) X(ECHILD) X(ECONNABORTED) X(ECONNREFUSED)
717 X(ECONNRESET) X(EDEADLK) X(EDESTADDRREQ) X(EDOM) X(EDQUOT)
718 X(EEXIST) X(EFAULT) X(EFBIG) X(EHOSTUNREACH) X(EIDRM) X(EILSEQ)
719 X(EINPROGRESS) X(EINTR) X(EINVAL) X(EIO) X(EISCONN) X(EISDIR)
720 X(ELOOP) X(EMFILE) X(EMLINK) X(EMSGSIZE) X(EMULTIHOP)
721 X(ENAMETOOLONG) X(ENETDOWN) X(ENETRESET) X(ENETUNREACH)
722 X(ENFILE) X(ENOBUFS) X(ENODEV) X(ENOENT) X(ENOEXEC) X(ENOLCK)
723 X(ENOLINK) X(ENOMEM) X(ENOMSG) X(ENOPROTOOPT) X(ENOSPC)
724 X(ENOSYS) X(ENOTCONN) X(ENOTDIR) X(ENOTEMPTY) X(ENOTRECOVERABLE)
725 X(ENOTSOCK) X(ENOTSUP) X(ENOTTY) X(ENXIO) X(EOVERFLOW)
726 X(EOWNERDEAD) X(EPERM) X(EPIPE) X(EPROTO) X(EPROTONOSUPPORT)
727 X(EPROTOTYPE) X(ERANGE) X(EROFS) X(ESPIPE) X(ESRCH) X(ESTALE)
728 X(ETIMEDOUT) X(ETXTBSY) X(EXDEV) X(ENOTCAPABLE)
732 static struct xlat cloudabi_fdflags[] = {
733 X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
734 X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
738 static struct xlat cloudabi_fdsflags[] = {
739 X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
743 static struct xlat cloudabi_filetype[] = {
744 X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
745 X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
746 X(FILETYPE_FIFO) X(FILETYPE_POLL) X(FILETYPE_PROCESS)
747 X(FILETYPE_REGULAR_FILE) X(FILETYPE_SHARED_MEMORY)
748 X(FILETYPE_SOCKET_DGRAM) X(FILETYPE_SOCKET_SEQPACKET)
749 X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK)
753 static struct xlat cloudabi_fsflags[] = {
754 X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
755 X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
759 static struct xlat cloudabi_mflags[] = {
760 X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
764 static struct xlat cloudabi_mprot[] = {
765 X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
769 static struct xlat cloudabi_msflags[] = {
770 X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
774 static struct xlat cloudabi_oflags[] = {
775 X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
779 static struct xlat cloudabi_sa_family[] = {
780 X(AF_UNSPEC) X(AF_INET) X(AF_INET6) X(AF_UNIX)
784 static struct xlat cloudabi_sdflags[] = {
785 X(SHUT_RD) X(SHUT_WR)
789 static struct xlat cloudabi_signal[] = {
790 X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
791 X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
792 X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
793 X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
794 X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
798 static struct xlat cloudabi_ssflags[] = {
799 X(SOCKSTAT_CLEAR_ERROR)
803 static struct xlat cloudabi_ssstate[] = {
804 X(SOCKSTATE_ACCEPTCONN)
808 static struct xlat cloudabi_ulflags[] = {
813 static struct xlat cloudabi_whence[] = {
814 X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
822 * Searches an xlat array for a value, and returns it if found. Otherwise
823 * return a string representation.
826 lookup(struct xlat *xlat, int val, int base)
830 for (; xlat->str != NULL; xlat++)
831 if (xlat->val == val)
835 sprintf(tmp, "0%o", val);
838 sprintf(tmp, "0x%x", val);
841 sprintf(tmp, "%u", val);
844 errx(1,"Unknown lookup base");
851 xlookup(struct xlat *xlat, int val)
854 return (lookup(xlat, val, 16));
858 * Searches an xlat array containing bitfield values. Remaining bits
859 * set after removing the known ones are printed at the end:
863 xlookup_bits(struct xlat *xlat, int val)
866 static char str[512];
870 for (; xlat->str != NULL; xlat++) {
871 if ((xlat->val & rem) == xlat->val) {
873 * Don't print the "all-bits-zero" string unless all
874 * bits are really zero.
876 if (xlat->val == 0 && val != 0)
878 len += sprintf(str + len, "%s|", xlat->str);
884 * If we have leftover bits or didn't match anything, print
888 len += sprintf(str + len, "0x%x", rem);
889 if (len && str[len - 1] == '|')
896 print_integer_arg(const char *(*decoder)(int), FILE *fp, int value)
900 str = decoder(value);
904 fprintf(fp, "%d", value);
908 print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value)
912 if (!decoder(fp, value, &rem))
913 fprintf(fp, "0x%x", rem);
915 fprintf(fp, "|0x%x", rem);
919 print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), FILE *fp,
924 if (!decoder(fp, value, &rem))
925 fprintf(fp, "0x%x", rem);
927 fprintf(fp, "|0x%x", rem);
932 * Add argument padding to subsequent system calls afater a Quad
933 * syscall arguments as needed. This used to be done by hand in the
934 * decoded_syscalls table which was ugly and error prone. It is
935 * simpler to do the fixup of offsets at initalization time than when
936 * decoding arguments.
939 quad_fixup(struct syscall *sc)
946 for (i = 0; i < sc->nargs; i++) {
947 /* This arg type is a dummy that doesn't use offset. */
948 if ((sc->args[i].type & ARG_MASK) == PipeFds)
951 assert(prev < sc->args[i].offset);
952 prev = sc->args[i].offset;
953 sc->args[i].offset += offset;
954 switch (sc->args[i].type & ARG_MASK) {
959 * 64-bit arguments on 32-bit powerpc must be
960 * 64-bit aligned. If the current offset is
961 * not aligned, the calling convention inserts
962 * a 32-bit pad argument that should be skipped.
964 if (sc->args[i].offset % 2 == 1) {
965 sc->args[i].offset++;
982 STAILQ_INIT(&syscalls);
983 for (sc = decoded_syscalls; sc->name != NULL; sc++) {
987 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
991 static struct syscall *
992 find_syscall(struct procabi *abi, u_int number)
994 struct extra_syscall *es;
996 if (number < nitems(abi->syscalls))
997 return (abi->syscalls[number]);
998 STAILQ_FOREACH(es, &abi->extra_syscalls, entries) {
999 if (es->number == number)
1006 add_syscall(struct procabi *abi, u_int number, struct syscall *sc)
1008 struct extra_syscall *es;
1010 if (number < nitems(abi->syscalls)) {
1011 assert(abi->syscalls[number] == NULL);
1012 abi->syscalls[number] = sc;
1014 es = malloc(sizeof(*es));
1016 es->number = number;
1017 STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries);
1022 * If/when the list gets big, it might be desirable to do it
1023 * as a hash table or binary search.
1026 get_syscall(struct threadinfo *t, u_int number, u_int nargs)
1033 sc = find_syscall(t->proc->abi, number);
1037 name = sysdecode_syscallname(t->proc->abi->abi, number);
1039 asprintf(&new_name, "#%d", number);
1043 STAILQ_FOREACH(sc, &syscalls, entries) {
1044 if (strcmp(name, sc->name) == 0) {
1045 add_syscall(t->proc->abi, number, sc);
1051 /* It is unknown. Add it into the list. */
1053 fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
1057 sc = calloc(1, sizeof(struct syscall));
1059 if (new_name != NULL)
1063 for (i = 0; i < nargs; i++) {
1064 sc->args[i].offset = i;
1065 /* Treat all unknown arguments as LongHex. */
1066 sc->args[i].type = LongHex;
1068 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
1069 add_syscall(t->proc->abi, number, sc);
1075 * Copy a fixed amount of bytes from the process.
1078 get_struct(pid_t pid, void *offset, void *buf, int len)
1080 struct ptrace_io_desc iorequest;
1082 iorequest.piod_op = PIOD_READ_D;
1083 iorequest.piod_offs = offset;
1084 iorequest.piod_addr = buf;
1085 iorequest.piod_len = len;
1086 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
1091 #define MAXSIZE 4096
1094 * Copy a string from the process. Note that it is
1095 * expected to be a C string, but if max is set, it will
1096 * only get that much.
1099 get_string(pid_t pid, void *addr, int max)
1101 struct ptrace_io_desc iorequest;
1103 size_t offset, size, totalsize;
1109 /* Read up to the end of the current page. */
1110 size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE);
1115 buf = malloc(totalsize);
1119 iorequest.piod_op = PIOD_READ_D;
1120 iorequest.piod_offs = (char *)addr + offset;
1121 iorequest.piod_addr = buf + offset;
1122 iorequest.piod_len = size;
1123 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
1127 if (memchr(buf + offset, '\0', size) != NULL)
1130 if (totalsize < MAXSIZE && max == 0) {
1131 size = MAXSIZE - totalsize;
1132 if (size > PAGE_SIZE)
1134 nbuf = realloc(buf, totalsize + size);
1136 buf[totalsize - 1] = '\0';
1142 buf[totalsize - 1] = '\0';
1151 static char tmp[32];
1152 const char *signame;
1154 signame = sysdecode_signal(sig);
1155 if (signame == NULL) {
1156 snprintf(tmp, sizeof(tmp), "%d", sig);
1163 print_kevent(FILE *fp, struct kevent *ke, int input)
1166 switch (ke->filter) {
1172 case EVFILT_PROCDESC:
1173 fprintf(fp, "%ju", (uintmax_t)ke->ident);
1176 fputs(strsig2(ke->ident), fp);
1179 fprintf(fp, "%p", (void *)ke->ident);
1181 fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter),
1182 xlookup_bits(kevent_flags, ke->flags));
1183 switch (ke->filter) {
1186 fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp);
1189 fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp);
1192 case EVFILT_PROCDESC:
1193 fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp);
1196 fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp);
1201 ctrl = ke->fflags & NOTE_FFCTRLMASK;
1202 data = ke->fflags & NOTE_FFLAGSMASK;
1204 fputs(xlookup(kevent_user_ffctrl, ctrl), fp);
1205 if (ke->fflags & NOTE_TRIGGER)
1206 fputs("|NOTE_TRIGGER", fp);
1208 fprintf(fp, "|%#x", data);
1210 fprintf(fp, "%#x", data);
1215 fprintf(fp, "%#x", ke->fflags);
1217 fprintf(fp, ",%p,%p", (void *)ke->data, (void *)ke->udata);
1221 print_utrace(FILE *fp, void *utrace_addr, size_t len)
1223 unsigned char *utrace_buffer;
1226 if (sysdecode_utrace(fp, utrace_addr, len)) {
1231 utrace_buffer = utrace_addr;
1232 fprintf(fp, "%zu:", len);
1234 fprintf(fp, " %02x", *utrace_buffer++);
1239 * Converts a syscall argument into a string. Said string is
1240 * allocated via malloc(), so needs to be free()'d. sc is
1241 * a pointer to the syscall description (see above); args is
1242 * an array of all of the system call arguments.
1245 print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
1246 struct trussinfo *trussinfo)
1253 fp = open_memstream(&tmp, &tmplen);
1254 pid = trussinfo->curthread->proc->pid;
1255 switch (sc->type & ARG_MASK) {
1257 fprintf(fp, "0x%x", (int)args[sc->offset]);
1260 fprintf(fp, "0%o", (int)args[sc->offset]);
1263 fprintf(fp, "%d", (int)args[sc->offset]);
1266 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1271 if (get_struct(pid, (void *)args[sc->offset], &val,
1273 fprintf(fp, "{ %u }", val);
1275 fprintf(fp, "0x%lx", args[sc->offset]);
1279 fprintf(fp, "0x%lx", args[sc->offset]);
1282 fprintf(fp, "%ld", args[sc->offset]);
1285 fprintf(fp, "%zu", (size_t)args[sc->offset]);
1288 /* NULL-terminated string. */
1291 tmp2 = get_string(pid, (void*)args[sc->offset], 0);
1292 fprintf(fp, "\"%s\"", tmp2);
1298 * Binary block of data that might have printable characters.
1299 * XXX If type|OUT, assume that the length is the syscall's
1300 * return value. Otherwise, assume that the length of the block
1301 * is in the next syscall argument.
1303 int max_string = trussinfo->strsize;
1304 char tmp2[max_string + 1], *tmp3;
1311 len = args[sc->offset + 1];
1314 * Don't print more than max_string characters, to avoid word
1315 * wrap. If we have to truncate put some ... after the string.
1317 if (len > max_string) {
1321 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
1323 tmp3 = malloc(len * 4 + 1);
1325 if (strvisx(tmp3, tmp2, len,
1326 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1331 fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1335 fprintf(fp, "0x%lx", args[sc->offset]);
1345 char buf[PAGE_SIZE];
1352 * Only parse argv[] and environment arrays from exec calls
1355 if (((sc->type & ARG_MASK) == ExecArgs &&
1356 (trussinfo->flags & EXECVEARGS) == 0) ||
1357 ((sc->type & ARG_MASK) == ExecEnv &&
1358 (trussinfo->flags & EXECVEENVS) == 0)) {
1359 fprintf(fp, "0x%lx", args[sc->offset]);
1364 * Read a page of pointers at a time. Punt if the top-level
1365 * pointer is not aligned. Note that the first read is of
1368 addr = args[sc->offset];
1369 if (addr % sizeof(char *) != 0) {
1370 fprintf(fp, "0x%lx", args[sc->offset]);
1374 len = PAGE_SIZE - (addr & PAGE_MASK);
1375 if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
1376 fprintf(fp, "0x%lx", args[sc->offset]);
1383 while (u.strarray[i] != NULL) {
1384 string = get_string(pid, u.strarray[i], 0);
1385 fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1390 if (i == len / sizeof(char *)) {
1393 if (get_struct(pid, (void *)addr, u.buf, len) ==
1395 fprintf(fp, ", <inval>");
1406 fprintf(fp, "%ld", args[sc->offset]);
1409 fprintf(fp, "0x%lx", args[sc->offset]);
1414 unsigned long long ll;
1416 #if _BYTE_ORDER == _LITTLE_ENDIAN
1417 ll = (unsigned long long)args[sc->offset + 1] << 32 |
1420 ll = (unsigned long long)args[sc->offset] << 32 |
1421 args[sc->offset + 1];
1423 if ((sc->type & ARG_MASK) == Quad)
1424 fprintf(fp, "%lld", ll);
1426 fprintf(fp, "0x%llx", ll);
1433 if (get_struct(pid, (void *)args[sc->offset], &val,
1435 fprintf(fp, "{ 0x%jx }", (uintmax_t)val);
1437 fprintf(fp, "0x%lx", args[sc->offset]);
1441 fprintf(fp, "0x%lx", args[sc->offset]);
1446 if (retval[0] == -1)
1448 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
1449 fprintf(fp, "\"%s\"", tmp2);
1457 cmd = args[sc->offset];
1458 temp = sysdecode_ioctlname(cmd);
1462 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1463 cmd, cmd & IOC_OUT ? "R" : "",
1464 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1465 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1466 cmd & 0xFF, IOCPARM_LEN(cmd));
1473 if (get_struct(pid, (void *)args[sc->offset], &ts,
1475 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1478 fprintf(fp, "0x%lx", args[sc->offset]);
1482 struct timespec ts[2];
1486 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
1490 for (i = 0; i < nitems(ts); i++) {
1493 switch (ts[i].tv_nsec) {
1495 fprintf(fp, "UTIME_NOW");
1498 fprintf(fp, "UTIME_OMIT");
1501 fprintf(fp, "%jd.%09ld",
1502 (intmax_t)ts[i].tv_sec,
1509 fprintf(fp, "0x%lx", args[sc->offset]);
1515 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1517 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1520 fprintf(fp, "0x%lx", args[sc->offset]);
1524 struct timeval tv[2];
1526 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1528 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1529 (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1530 (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1532 fprintf(fp, "0x%lx", args[sc->offset]);
1536 struct itimerval itv;
1538 if (get_struct(pid, (void *)args[sc->offset], &itv,
1540 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1541 (intmax_t)itv.it_interval.tv_sec,
1542 itv.it_interval.tv_usec,
1543 (intmax_t)itv.it_value.tv_sec,
1544 itv.it_value.tv_usec);
1546 fprintf(fp, "0x%lx", args[sc->offset]);
1551 struct linux_socketcall_args largs;
1553 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
1554 sizeof(largs)) != -1)
1555 fprintf(fp, "{ %s, 0x%lx }",
1556 lookup(linux_socketcall_ops, largs.what, 10),
1557 (long unsigned int)largs.args);
1559 fprintf(fp, "0x%lx", args[sc->offset]);
1564 * XXX: A Pollfd argument expects the /next/ syscall argument
1565 * to be the number of fds in the array. This matches the poll
1569 int numfds = args[sc->offset + 1];
1570 size_t bytes = sizeof(struct pollfd) * numfds;
1573 if ((pfd = malloc(bytes)) == NULL)
1574 err(1, "Cannot malloc %zu bytes for pollfd array",
1576 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
1579 for (i = 0; i < numfds; i++) {
1580 fprintf(fp, " %d/%s", pfd[i].fd,
1581 xlookup_bits(poll_flags, pfd[i].events));
1585 fprintf(fp, "0x%lx", args[sc->offset]);
1592 * XXX: A Fd_set argument expects the /first/ syscall argument
1593 * to be the number of fds in the array. This matches the
1597 int numfds = args[0];
1598 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1601 if ((fds = malloc(bytes)) == NULL)
1602 err(1, "Cannot malloc %zu bytes for fd_set array",
1604 if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
1607 for (i = 0; i < numfds; i++) {
1608 if (FD_ISSET(i, fds))
1609 fprintf(fp, " %d", i);
1613 fprintf(fp, "0x%lx", args[sc->offset]);
1618 fputs(strsig2(args[sc->offset]), fp);
1625 sig = args[sc->offset];
1626 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
1627 sizeof(ss)) == -1) {
1628 fprintf(fp, "0x%lx", args[sc->offset]);
1633 for (i = 1; i < sys_nsig; i++) {
1634 if (sigismember(&ss, i)) {
1635 fprintf(fp, "%s%s", !first ? "|" : "",
1646 print_integer_arg(sysdecode_sigprocmask_how, fp,
1650 /* XXX: Output depends on the value of the previous argument. */
1651 if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
1652 sysdecode_fcntl_arg(fp, args[sc->offset - 1],
1653 args[sc->offset], 16);
1656 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
1659 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
1662 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
1665 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
1668 print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
1671 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
1674 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
1677 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
1680 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
1683 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]);
1686 fputs(xlookup(pathconf_arg, args[sc->offset]), fp);
1689 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
1693 struct sockaddr_in *lsin;
1694 struct sockaddr_in6 *lsin6;
1695 struct sockaddr_un *sun;
1696 struct sockaddr *sa;
1700 if (args[sc->offset] == 0) {
1706 * Extract the address length from the next argument. If
1707 * this is an output sockaddr (OUT is set), then the
1708 * next argument is a pointer to a socklen_t. Otherwise
1709 * the next argument contains a socklen_t by value.
1711 if (sc->type & OUT) {
1712 if (get_struct(pid, (void *)args[sc->offset + 1],
1713 &len, sizeof(len)) == -1) {
1714 fprintf(fp, "0x%lx", args[sc->offset]);
1718 len = args[sc->offset + 1];
1720 /* If the length is too small, just bail. */
1721 if (len < sizeof(*sa)) {
1722 fprintf(fp, "0x%lx", args[sc->offset]);
1726 sa = calloc(1, len);
1727 if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) {
1729 fprintf(fp, "0x%lx", args[sc->offset]);
1733 switch (sa->sa_family) {
1735 if (len < sizeof(*lsin))
1736 goto sockaddr_short;
1737 lsin = (struct sockaddr_in *)(void *)sa;
1738 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1739 fprintf(fp, "{ AF_INET %s:%d }", addr,
1740 htons(lsin->sin_port));
1743 if (len < sizeof(*lsin6))
1744 goto sockaddr_short;
1745 lsin6 = (struct sockaddr_in6 *)(void *)sa;
1746 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1748 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1749 htons(lsin6->sin6_port));
1752 sun = (struct sockaddr_un *)sa;
1753 fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1754 (int)(len - offsetof(struct sockaddr_un, sun_path)),
1760 "{ sa_len = %d, sa_family = %d, sa_data = {",
1761 (int)sa->sa_len, (int)sa->sa_family);
1762 for (q = (u_char *)sa->sa_data;
1763 q < (u_char *)sa + len; q++)
1764 fprintf(fp, "%s 0x%02x",
1765 q == (u_char *)sa->sa_data ? "" : ",",
1773 struct sigaction sa;
1775 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
1778 if (sa.sa_handler == SIG_DFL)
1779 fputs("SIG_DFL", fp);
1780 else if (sa.sa_handler == SIG_IGN)
1781 fputs("SIG_IGN", fp);
1783 fprintf(fp, "%p", sa.sa_handler);
1784 fprintf(fp, " %s ss_t }",
1785 xlookup_bits(sigaction_flags, sa.sa_flags));
1787 fprintf(fp, "0x%lx", args[sc->offset]);
1792 * XXX XXX: The size of the array is determined by either the
1793 * next syscall argument, or by the syscall return value,
1794 * depending on which argument number we are. This matches the
1795 * kevent syscall, but luckily that's the only syscall that uses
1803 if (sc->offset == 1)
1804 numevents = args[sc->offset+1];
1805 else if (sc->offset == 3 && retval[0] != -1)
1806 numevents = retval[0];
1808 if (numevents >= 0) {
1809 bytes = sizeof(struct kevent) * numevents;
1810 if ((ke = malloc(bytes)) == NULL)
1812 "Cannot malloc %zu bytes for kevent array",
1816 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
1819 for (i = 0; i < numevents; i++) {
1821 print_kevent(fp, &ke[i], sc->offset == 1);
1825 fprintf(fp, "0x%lx", args[sc->offset]);
1833 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1837 strmode(st.st_mode, mode);
1839 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1840 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1841 (long)st.st_blksize);
1843 fprintf(fp, "0x%lx", args[sc->offset]);
1851 if (get_struct(pid, (void *)args[sc->offset], &buf,
1852 sizeof(buf)) != -1) {
1855 bzero(fsid, sizeof(fsid));
1856 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
1857 for (i = 0; i < sizeof(buf.f_fsid); i++)
1858 snprintf(&fsid[i*2],
1859 sizeof(fsid) - (i*2), "%02x",
1860 ((u_char *)&buf.f_fsid)[i]);
1863 "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
1864 "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
1865 buf.f_mntfromname, fsid);
1867 fprintf(fp, "0x%lx", args[sc->offset]);
1874 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
1877 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
1878 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
1879 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
1880 ru.ru_inblock, ru.ru_oublock);
1882 fprintf(fp, "0x%lx", args[sc->offset]);
1888 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
1890 fprintf(fp, "{ cur=%ju,max=%ju }",
1891 rl.rlim_cur, rl.rlim_max);
1893 fprintf(fp, "0x%lx", args[sc->offset]);
1899 if (get_struct(pid, (void *)args[sc->offset], &status,
1900 sizeof(status)) != -1) {
1902 if (WIFCONTINUED(status))
1903 fputs("CONTINUED", fp);
1904 else if (WIFEXITED(status))
1905 fprintf(fp, "EXITED,val=%d",
1906 WEXITSTATUS(status));
1907 else if (WIFSIGNALED(status))
1908 fprintf(fp, "SIGNALED,sig=%s%s",
1909 strsig2(WTERMSIG(status)),
1910 WCOREDUMP(status) ? ",cored" : "");
1912 fprintf(fp, "STOPPED,sig=%s",
1913 strsig2(WTERMSIG(status)));
1916 fprintf(fp, "0x%lx", args[sc->offset]);
1920 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]);
1923 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]);
1926 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]);
1929 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]);
1932 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]);
1935 fputs(xlookup_bits(at_flags, args[sc->offset]), fp);
1938 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]);
1941 fputs(xlookup(sysarch_ops, args[sc->offset]), fp);
1945 * The pipe() system call in the kernel returns its
1946 * two file descriptors via return values. However,
1947 * the interface exposed by libc is that pipe()
1948 * accepts a pointer to an array of descriptors.
1949 * Format the output to match the libc API by printing
1950 * the returned file descriptors as a fake argument.
1952 * Overwrite the first retval to signal a successful
1955 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
1962 len = args[sc->offset + 1];
1963 utrace_addr = calloc(1, len);
1964 if (get_struct(pid, (void *)args[sc->offset],
1965 (void *)utrace_addr, len) != -1)
1966 print_utrace(fp, utrace_addr, len);
1968 fprintf(fp, "0x%lx", args[sc->offset]);
1973 int descriptors[16];
1974 unsigned long i, ndescriptors;
1977 ndescriptors = args[sc->offset + 1];
1979 if (ndescriptors > nitems(descriptors)) {
1980 ndescriptors = nitems(descriptors);
1983 if (get_struct(pid, (void *)args[sc->offset],
1984 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
1986 for (i = 0; i < ndescriptors; i++)
1987 fprintf(fp, i == 0 ? " %d" : ", %d",
1989 fprintf(fp, truncated ? ", ... }" : " }");
1991 fprintf(fp, "0x%lx", args[sc->offset]);
1995 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]);
1997 case CapFcntlRights: {
2000 if (sc->type & OUT) {
2001 if (get_struct(pid, (void *)args[sc->offset], &rights,
2002 sizeof(rights)) == -1) {
2003 fprintf(fp, "0x%lx", args[sc->offset]);
2007 rights = args[sc->offset];
2008 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights);
2012 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]);
2017 if (!sysdecode_fileflags(fp, args[sc->offset], &rem))
2018 fprintf(fp, "0x%x", rem);
2020 fprintf(fp, "|0x%x", rem);
2024 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]);
2027 print_integer_arg(sysdecode_getfsstat_mode, fp,
2031 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]);
2033 case Kldunloadflags:
2034 print_integer_arg(sysdecode_kldunload_flags, fp,
2038 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]);
2041 fprintf(fp, "%u", (socklen_t)args[sc->offset]);
2043 case Sockprotocol: {
2045 int domain, protocol;
2047 domain = args[sc->offset - 2];
2048 protocol = args[sc->offset];
2049 if (protocol == 0) {
2052 temp = sysdecode_socket_protocol(domain, protocol);
2056 fprintf(fp, "%d", protocol);
2062 print_integer_arg(sysdecode_sockopt_level, fp,
2069 level = args[sc->offset - 1];
2070 name = args[sc->offset];
2071 temp = sysdecode_sockopt_name(level, name);
2075 fprintf(fp, "%d", name);
2080 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]);
2083 cap_rights_t rights;
2085 if (get_struct(pid, (void *)args[sc->offset], &rights,
2086 sizeof(rights)) != -1) {
2088 sysdecode_cap_rights(fp, &rights);
2091 fprintf(fp, "0x%lx", args[sc->offset]);
2095 print_integer_arg(sysdecode_acltype, fp, args[sc->offset]);
2097 case Extattrnamespace:
2098 print_integer_arg(sysdecode_extattrnamespace, fp,
2102 case CloudABIAdvice:
2103 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
2105 case CloudABIClockID:
2106 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2108 case ClouduABIFDSFlags:
2109 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2111 case CloudABIFDStat: {
2112 cloudabi_fdstat_t fds;
2113 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds))
2115 fprintf(fp, "{ %s, ",
2116 xlookup(cloudabi_filetype, fds.fs_filetype));
2117 fprintf(fp, "%s, ... }",
2118 xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2120 fprintf(fp, "0x%lx", args[sc->offset]);
2123 case CloudABIFileStat: {
2124 cloudabi_filestat_t fsb;
2125 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb))
2127 fprintf(fp, "{ %s, %ju }",
2128 xlookup(cloudabi_filetype, fsb.st_filetype),
2129 (uintmax_t)fsb.st_size);
2131 fprintf(fp, "0x%lx", args[sc->offset]);
2134 case CloudABIFileType:
2135 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2137 case CloudABIFSFlags:
2138 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2140 case CloudABILookup:
2141 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2142 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2143 (int)args[sc->offset]);
2145 fprintf(fp, "%d", (int)args[sc->offset]);
2147 case CloudABIMFlags:
2148 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2151 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2153 case CloudABIMSFlags:
2154 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2156 case CloudABIOFlags:
2157 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2159 case CloudABISDFlags:
2160 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2162 case CloudABISignal:
2163 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2165 case CloudABISockStat: {
2166 cloudabi_sockstat_t ss;
2167 if (get_struct(pid, (void *)args[sc->offset], &ss, sizeof(ss))
2169 fprintf(fp, "{ %s, ", xlookup(
2170 cloudabi_sa_family, ss.ss_sockname.sa_family));
2171 fprintf(fp, "%s, ", xlookup(
2172 cloudabi_sa_family, ss.ss_peername.sa_family));
2173 fprintf(fp, "%s, ", xlookup(
2174 cloudabi_errno, ss.ss_error));
2175 fprintf(fp, "%s }", xlookup_bits(
2176 cloudabi_ssstate, ss.ss_state));
2178 fprintf(fp, "0x%lx", args[sc->offset]);
2181 case CloudABISSFlags:
2182 fputs(xlookup_bits(cloudabi_ssflags, args[sc->offset]), fp);
2184 case CloudABITimestamp:
2185 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2186 args[sc->offset] % 1000000000);
2188 case CloudABIULFlags:
2189 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2191 case CloudABIWhence:
2192 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2196 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2203 * Print (to outfile) the system call and its arguments.
2206 print_syscall(struct trussinfo *trussinfo)
2208 struct threadinfo *t;
2213 t = trussinfo->curthread;
2215 name = t->cs.sc->name;
2216 nargs = t->cs.nargs;
2217 s_args = t->cs.s_args;
2219 len = print_line_prefix(trussinfo);
2220 len += fprintf(trussinfo->outfile, "%s(", name);
2222 for (i = 0; i < nargs; i++) {
2223 if (s_args[i] != NULL)
2224 len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2226 len += fprintf(trussinfo->outfile,
2227 "<missing argument>");
2228 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2231 len += fprintf(trussinfo->outfile, ")");
2232 for (i = 0; i < 6 - (len / 8); i++)
2233 fprintf(trussinfo->outfile, "\t");
2237 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
2239 struct timespec timediff;
2240 struct threadinfo *t;
2244 t = trussinfo->curthread;
2246 if (trussinfo->flags & COUNTONLY) {
2247 timespecsubt(&t->after, &t->before, &timediff);
2248 timespecadd(&sc->time, &timediff, &sc->time);
2255 print_syscall(trussinfo);
2256 fflush(trussinfo->outfile);
2258 if (retval == NULL) {
2260 * This system call resulted in the current thread's exit,
2261 * so there is no return value or error to display.
2263 fprintf(trussinfo->outfile, "\n");
2268 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi,
2270 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
2271 error == INT_MAX ? "Unknown error" : strerror(error));
2274 else if (sc->ret_type == 2) {
2277 #if _BYTE_ORDER == _LITTLE_ENDIAN
2278 off = (off_t)retval[1] << 32 | retval[0];
2280 off = (off_t)retval[0] << 32 | retval[1];
2282 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2287 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
2292 print_summary(struct trussinfo *trussinfo)
2294 struct timespec total = {0, 0};
2298 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2299 "syscall", "seconds", "calls", "errors");
2301 STAILQ_FOREACH(sc, &syscalls, entries)
2303 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2304 sc->name, (intmax_t)sc->time.tv_sec,
2305 sc->time.tv_nsec, sc->ncalls, sc->nerror);
2306 timespecadd(&total, &sc->time, &total);
2307 ncall += sc->ncalls;
2308 nerror += sc->nerror;
2310 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2311 "", "-------------", "-------", "-------");
2312 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2313 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);