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 = "__cap_rights_get", .ret_type = 1, .nargs = 3,
81 .args = { { Int, 0 }, { Int, 1 }, { CapRights | OUT, 2 } } },
82 { .name = "__getcwd", .ret_type = 1, .nargs = 2,
83 .args = { { Name | OUT, 0 }, { Int, 1 } } },
84 { .name = "_umtx_op", .ret_type = 1, .nargs = 5,
85 .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
87 { .name = "accept", .ret_type = 1, .nargs = 3,
88 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
89 { .name = "access", .ret_type = 1, .nargs = 2,
90 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
91 { .name = "bind", .ret_type = 1, .nargs = 3,
92 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
93 { .name = "bindat", .ret_type = 1, .nargs = 4,
94 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
96 { .name = "break", .ret_type = 1, .nargs = 1,
97 .args = { { Ptr, 0 } } },
98 { .name = "cap_fcntls_get", .ret_type = 1, .nargs = 2,
99 .args = { { Int, 0 }, { CapFcntlRights | OUT, 1 } } },
100 { .name = "cap_fcntls_limit", .ret_type = 1, .nargs = 2,
101 .args = { { Int, 0 }, { CapFcntlRights, 1 } } },
102 { .name = "cap_rights_limit", .ret_type = 1, .nargs = 2,
103 .args = { { Int, 0 }, { CapRights, 1 } } },
104 { .name = "chdir", .ret_type = 1, .nargs = 1,
105 .args = { { Name, 0 } } },
106 { .name = "chflags", .ret_type = 1, .nargs = 2,
107 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
108 { .name = "chflagsat", .ret_type = 1, .nargs = 4,
109 .args = { { Atfd, 0 }, { Name | IN, 1 }, { FileFlags, 2 },
111 { .name = "chmod", .ret_type = 1, .nargs = 2,
112 .args = { { Name, 0 }, { Octal, 1 } } },
113 { .name = "chown", .ret_type = 1, .nargs = 3,
114 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
115 { .name = "chroot", .ret_type = 1, .nargs = 1,
116 .args = { { Name, 0 } } },
117 { .name = "clock_gettime", .ret_type = 1, .nargs = 2,
118 .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
119 { .name = "close", .ret_type = 1, .nargs = 1,
120 .args = { { Int, 0 } } },
121 { .name = "connect", .ret_type = 1, .nargs = 3,
122 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
123 { .name = "connectat", .ret_type = 1, .nargs = 4,
124 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
126 { .name = "eaccess", .ret_type = 1, .nargs = 2,
127 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
128 { .name = "execve", .ret_type = 1, .nargs = 3,
129 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
130 { ExecEnv | IN, 2 } } },
131 { .name = "exit", .ret_type = 0, .nargs = 1,
132 .args = { { Hex, 0 } } },
133 { .name = "faccessat", .ret_type = 1, .nargs = 4,
134 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
136 { .name = "fchflags", .ret_type = 1, .nargs = 2,
137 .args = { { Int, 0 }, { FileFlags, 1 } } },
138 { .name = "fchmod", .ret_type = 1, .nargs = 2,
139 .args = { { Int, 0 }, { Octal, 1 } } },
140 { .name = "fchmodat", .ret_type = 1, .nargs = 4,
141 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
142 { .name = "fchown", .ret_type = 1, .nargs = 3,
143 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
144 { .name = "fchownat", .ret_type = 1, .nargs = 5,
145 .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
147 { .name = "fcntl", .ret_type = 1, .nargs = 3,
148 .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
149 { .name = "flock", .ret_type = 1, .nargs = 2,
150 .args = { { Int, 0 }, { Flockop, 1 } } },
151 { .name = "fstat", .ret_type = 1, .nargs = 2,
152 .args = { { Int, 0 }, { Stat | OUT, 1 } } },
153 { .name = "fstatat", .ret_type = 1, .nargs = 4,
154 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
156 { .name = "fstatfs", .ret_type = 1, .nargs = 2,
157 .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
158 { .name = "ftruncate", .ret_type = 1, .nargs = 2,
159 .args = { { Int | IN, 0 }, { QuadHex | IN, 1 } } },
160 { .name = "futimens", .ret_type = 1, .nargs = 2,
161 .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
162 { .name = "futimes", .ret_type = 1, .nargs = 2,
163 .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
164 { .name = "futimesat", .ret_type = 1, .nargs = 3,
165 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
166 { .name = "getfsstat", .ret_type = 1, .nargs = 3,
167 .args = { { Ptr, 0 }, { Long, 1 }, { Getfsstatmode, 2 } } },
168 { .name = "getitimer", .ret_type = 1, .nargs = 2,
169 .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
170 { .name = "getpeername", .ret_type = 1, .nargs = 3,
171 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
172 { .name = "getpgid", .ret_type = 1, .nargs = 1,
173 .args = { { Int, 0 } } },
174 { .name = "getrlimit", .ret_type = 1, .nargs = 2,
175 .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
176 { .name = "getrusage", .ret_type = 1, .nargs = 2,
177 .args = { { Int, 0 }, { Rusage | OUT, 1 } } },
178 { .name = "getsid", .ret_type = 1, .nargs = 1,
179 .args = { { Int, 0 } } },
180 { .name = "getsockname", .ret_type = 1, .nargs = 3,
181 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
182 { .name = "getsockopt", .ret_type = 1, .nargs = 5,
183 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
184 { Ptr | OUT, 3 }, { Ptr | OUT, 4 } } },
185 { .name = "gettimeofday", .ret_type = 1, .nargs = 2,
186 .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
187 { .name = "ioctl", .ret_type = 1, .nargs = 3,
188 .args = { { Int, 0 }, { Ioctl, 1 }, { Ptr, 2 } } },
189 { .name = "kevent", .ret_type = 1, .nargs = 6,
190 .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
191 { Int, 4 }, { Timespec, 5 } } },
192 { .name = "kill", .ret_type = 1, .nargs = 2,
193 .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
194 { .name = "kldfind", .ret_type = 1, .nargs = 1,
195 .args = { { Name | IN, 0 } } },
196 { .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
197 .args = { { Int, 0 } } },
198 { .name = "kldload", .ret_type = 1, .nargs = 1,
199 .args = { { Name | IN, 0 } } },
200 { .name = "kldnext", .ret_type = 1, .nargs = 1,
201 .args = { { Int, 0 } } },
202 { .name = "kldstat", .ret_type = 1, .nargs = 2,
203 .args = { { Int, 0 }, { Ptr, 1 } } },
204 { .name = "kldsym", .ret_type = 1, .nargs = 3,
205 .args = { { Int, 0 }, { Kldsymcmd, 1 }, { Ptr, 2 } } },
206 { .name = "kldunload", .ret_type = 1, .nargs = 1,
207 .args = { { Int, 0 } } },
208 { .name = "kldunloadf", .ret_type = 1, .nargs = 2,
209 .args = { { Int, 0 }, { Kldunloadflags, 1 } } },
210 { .name = "kse_release", .ret_type = 0, .nargs = 1,
211 .args = { { Timespec, 0 } } },
212 { .name = "lchflags", .ret_type = 1, .nargs = 2,
213 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
214 { .name = "lchmod", .ret_type = 1, .nargs = 2,
215 .args = { { Name, 0 }, { Octal, 1 } } },
216 { .name = "lchown", .ret_type = 1, .nargs = 3,
217 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
218 { .name = "link", .ret_type = 1, .nargs = 2,
219 .args = { { Name, 0 }, { Name, 1 } } },
220 { .name = "linkat", .ret_type = 1, .nargs = 5,
221 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
223 { .name = "listen", .ret_type = 1, .nargs = 2,
224 .args = { { Int, 0 }, { Int, 1 } } },
225 { .name = "lseek", .ret_type = 2, .nargs = 3,
226 .args = { { Int, 0 }, { QuadHex, 1 }, { Whence, 2 } } },
227 { .name = "lstat", .ret_type = 1, .nargs = 2,
228 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
229 { .name = "lutimes", .ret_type = 1, .nargs = 2,
230 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
231 { .name = "madvise", .ret_type = 1, .nargs = 3,
232 .args = { { Ptr, 0 }, { Sizet, 1 }, { Madvice, 2 } } },
233 { .name = "mkdir", .ret_type = 1, .nargs = 2,
234 .args = { { Name, 0 }, { Octal, 1 } } },
235 { .name = "mkdirat", .ret_type = 1, .nargs = 3,
236 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
237 { .name = "mkfifo", .ret_type = 1, .nargs = 2,
238 .args = { { Name, 0 }, { Octal, 1 } } },
239 { .name = "mkfifoat", .ret_type = 1, .nargs = 3,
240 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
241 { .name = "mknod", .ret_type = 1, .nargs = 3,
242 .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
243 { .name = "mknodat", .ret_type = 1, .nargs = 4,
244 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
245 { .name = "mmap", .ret_type = 1, .nargs = 6,
246 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
247 { Int, 4 }, { QuadHex, 5 } } },
248 { .name = "modfind", .ret_type = 1, .nargs = 1,
249 .args = { { Name | IN, 0 } } },
250 { .name = "mount", .ret_type = 1, .nargs = 4,
251 .args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } },
252 { .name = "mprotect", .ret_type = 1, .nargs = 3,
253 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 } } },
254 { .name = "munmap", .ret_type = 1, .nargs = 2,
255 .args = { { Ptr, 0 }, { Sizet, 1 } } },
256 { .name = "nanosleep", .ret_type = 1, .nargs = 1,
257 .args = { { Timespec, 0 } } },
258 { .name = "open", .ret_type = 1, .nargs = 3,
259 .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
260 { .name = "openat", .ret_type = 1, .nargs = 4,
261 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
263 { .name = "pathconf", .ret_type = 1, .nargs = 2,
264 .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
265 { .name = "pipe", .ret_type = 1, .nargs = 1,
266 .args = { { PipeFds | OUT, 0 } } },
267 { .name = "pipe2", .ret_type = 1, .nargs = 2,
268 .args = { { Ptr, 0 }, { Pipe2, 1 } } },
269 { .name = "poll", .ret_type = 1, .nargs = 3,
270 .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
271 { .name = "posix_fadvise", .ret_type = 1, .nargs = 4,
272 .args = { { Int, 0 }, { QuadHex, 1 }, { QuadHex, 2 },
274 { .name = "posix_openpt", .ret_type = 1, .nargs = 1,
275 .args = { { Open, 0 } } },
276 { .name = "procctl", .ret_type = 1, .nargs = 4,
277 .args = { { Idtype, 0 }, { Quad, 1 }, { Procctl, 2 }, { Ptr, 3 } } },
278 { .name = "read", .ret_type = 1, .nargs = 3,
279 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 } } },
280 { .name = "readlink", .ret_type = 1, .nargs = 3,
281 .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Sizet, 2 } } },
282 { .name = "readlinkat", .ret_type = 1, .nargs = 4,
283 .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
285 { .name = "recvfrom", .ret_type = 1, .nargs = 6,
286 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
287 { Msgflags, 3 }, { Sockaddr | OUT, 4 },
288 { Ptr | OUT, 5 } } },
289 { .name = "recvmsg", .ret_type = 1, .nargs = 3,
290 .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
291 { .name = "rename", .ret_type = 1, .nargs = 2,
292 .args = { { Name, 0 }, { Name, 1 } } },
293 { .name = "renameat", .ret_type = 1, .nargs = 4,
294 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
295 { .name = "rfork", .ret_type = 1, .nargs = 1,
296 .args = { { Rforkflags, 0 } } },
297 { .name = "rmdir", .ret_type = 1, .nargs = 1,
298 .args = { { Name, 0 } } },
299 { .name = "sctp_generic_recvmsg", .ret_type = 1, .nargs = 7,
300 .args = { { Int, 0 }, { Ptr | IN, 1 }, { Int, 2 },
301 { Sockaddr | OUT, 3 }, { Ptr | OUT, 4 }, { Ptr | OUT, 5 },
302 { Ptr | OUT, 6 } } },
303 { .name = "sctp_generic_sendmsg", .ret_type = 1, .nargs = 7,
304 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
305 { Sockaddr | IN, 3 }, { Socklent, 4 }, { Ptr | IN, 5 },
307 { .name = "select", .ret_type = 1, .nargs = 5,
308 .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
310 { .name = "sendmsg", .ret_type = 1, .nargs = 3,
311 .args = { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } },
312 { .name = "sendto", .ret_type = 1, .nargs = 6,
313 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
314 { Msgflags, 3 }, { Sockaddr | IN, 4 },
315 { Socklent | IN, 5 } } },
316 { .name = "setitimer", .ret_type = 1, .nargs = 3,
317 .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
318 { .name = "setrlimit", .ret_type = 1, .nargs = 2,
319 .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
320 { .name = "setsockopt", .ret_type = 1, .nargs = 5,
321 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
322 { Ptr | IN, 3 }, { Socklent, 4 } } },
323 { .name = "shutdown", .ret_type = 1, .nargs = 2,
324 .args = { { Int, 0 }, { Shutdown, 1 } } },
325 { .name = "sigaction", .ret_type = 1, .nargs = 3,
326 .args = { { Signal, 0 }, { Sigaction | IN, 1 },
327 { Sigaction | OUT, 2 } } },
328 { .name = "sigpending", .ret_type = 1, .nargs = 1,
329 .args = { { Sigset | OUT, 0 } } },
330 { .name = "sigprocmask", .ret_type = 1, .nargs = 3,
331 .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
332 { .name = "sigqueue", .ret_type = 1, .nargs = 3,
333 .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
334 { .name = "sigreturn", .ret_type = 1, .nargs = 1,
335 .args = { { Ptr, 0 } } },
336 { .name = "sigsuspend", .ret_type = 1, .nargs = 1,
337 .args = { { Sigset | IN, 0 } } },
338 { .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
339 .args = { { Sigset | IN, 0 }, { Ptr, 1 }, { Timespec | IN, 2 } } },
340 { .name = "sigwait", .ret_type = 1, .nargs = 2,
341 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
342 { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
343 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
344 { .name = "socket", .ret_type = 1, .nargs = 3,
345 .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Sockprotocol, 2 } } },
346 { .name = "stat", .ret_type = 1, .nargs = 2,
347 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
348 { .name = "statfs", .ret_type = 1, .nargs = 2,
349 .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } },
350 { .name = "symlink", .ret_type = 1, .nargs = 2,
351 .args = { { Name, 0 }, { Name, 1 } } },
352 { .name = "symlinkat", .ret_type = 1, .nargs = 3,
353 .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } },
354 { .name = "sysarch", .ret_type = 1, .nargs = 2,
355 .args = { { Sysarch, 0 }, { Ptr, 1 } } },
356 { .name = "thr_kill", .ret_type = 1, .nargs = 2,
357 .args = { { Long, 0 }, { Signal, 1 } } },
358 { .name = "thr_self", .ret_type = 1, .nargs = 1,
359 .args = { { Ptr, 0 } } },
360 { .name = "truncate", .ret_type = 1, .nargs = 2,
361 .args = { { Name | IN, 0 }, { QuadHex | IN, 1 } } },
364 { .name = "umount", .ret_type = 1, .nargs = 2,
365 .args = { { Name, 0 }, { Int, 2 } } },
367 { .name = "unlink", .ret_type = 1, .nargs = 1,
368 .args = { { Name, 0 } } },
369 { .name = "unlinkat", .ret_type = 1, .nargs = 3,
370 .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
371 { .name = "unmount", .ret_type = 1, .nargs = 2,
372 .args = { { Name, 0 }, { Int, 1 } } },
373 { .name = "utimensat", .ret_type = 1, .nargs = 4,
374 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
376 { .name = "utimes", .ret_type = 1, .nargs = 2,
377 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
378 { .name = "utrace", .ret_type = 1, .nargs = 1,
379 .args = { { Utrace, 0 } } },
380 { .name = "wait4", .ret_type = 1, .nargs = 4,
381 .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
382 { Rusage | OUT, 3 } } },
383 { .name = "wait6", .ret_type = 1, .nargs = 6,
384 .args = { { Idtype, 0 }, { Quad, 1 }, { ExitStatus | OUT, 2 },
385 { Waitoptions, 3 }, { Rusage | OUT, 4 }, { Ptr, 5 } } },
386 { .name = "write", .ret_type = 1, .nargs = 3,
387 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 } } },
390 { .name = "linux_access", .ret_type = 1, .nargs = 2,
391 .args = { { Name, 0 }, { Accessmode, 1 } } },
392 { .name = "linux_execve", .ret_type = 1, .nargs = 3,
393 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
394 { ExecEnv | IN, 2 } } },
395 { .name = "linux_lseek", .ret_type = 2, .nargs = 3,
396 .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
397 { .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
398 .args = { { Name | IN, 0 }, { Int, 1 } } },
399 { .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
400 .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
401 { .name = "linux_newstat", .ret_type = 1, .nargs = 2,
402 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
403 { .name = "linux_open", .ret_type = 1, .nargs = 3,
404 .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
405 { .name = "linux_readlink", .ret_type = 1, .nargs = 3,
406 .args = { { Name, 0 }, { Name | OUT, 1 }, { Sizet, 2 } } },
407 { .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
408 .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
409 { .name = "linux_stat64", .ret_type = 1, .nargs = 2,
410 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
412 /* CloudABI system calls. */
413 { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
414 .args = { { CloudABIClockID, 0 } } },
415 { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
416 .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
417 { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
418 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
419 { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
420 .args = { { Int, 0 } } },
421 { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
422 .args = { { CloudABIFileType, 0 } } },
423 { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
424 .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
425 { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
426 .args = { { Int, 0 } } },
427 { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
428 .args = { { Int, 0 } } },
429 { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
430 .args = { { Int, 0 }, { Int, 1 } } },
431 { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
432 .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
433 { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
434 .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
435 { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
436 .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
437 { ClouduABIFDSFlags, 2 } } },
438 { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
439 .args = { { Int, 0 } } },
440 { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
441 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
442 { CloudABIAdvice, 3 } } },
443 { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
444 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
445 { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
446 .args = { { Int, 0 }, { BinString | IN, 1 },
447 { CloudABIFileType, 3 } } },
448 { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
449 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
450 { Int, 3 }, { BinString | IN, 4 } } },
451 { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
452 .args = { { Int, 0 }, { BinString | IN, 1 },
453 { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
454 { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
455 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
457 { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
458 .args = { { Int, 0 }, { BinString | IN, 1 },
459 { BinString | OUT, 3 }, { Int, 4 } } },
460 { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
461 .args = { { Int, 0 }, { BinString | IN, 1 },
462 { Int, 3 }, { BinString | IN, 4 } } },
463 { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
464 .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
465 { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
466 .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
467 { CloudABIFSFlags, 2 } } },
468 { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
469 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
470 { CloudABIFileStat | OUT, 3 } } },
471 { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
472 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
473 { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
474 { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
475 .args = { { BinString | IN, 0 },
476 { Int, 2 }, { BinString | IN, 3 } } },
477 { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
478 .args = { { Int, 0 }, { BinString | IN, 1 },
479 { CloudABIULFlags, 3 } } },
480 { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
481 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
482 { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
483 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
484 { .name = "cloudabi_sys_mem_lock", .ret_type = 1, .nargs = 2,
485 .args = { { Ptr, 0 }, { Int, 1 } } },
486 { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
487 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
488 { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
489 { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
490 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
491 { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
492 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
493 { .name = "cloudabi_sys_mem_unlock", .ret_type = 1, .nargs = 2,
494 .args = { { Ptr, 0 }, { Int, 1 } } },
495 { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
496 .args = { { Ptr, 0 }, { Int, 1 } } },
497 { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
498 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
499 { IntArray, 3 }, { Int, 4 } } },
500 { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
501 .args = { { Int, 0 } } },
502 { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
503 { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
504 .args = { { CloudABISignal, 0 } } },
505 { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
506 .args = { { BinString | OUT, 0 }, { Int, 1 } } },
507 { .name = "cloudabi_sys_sock_accept", .ret_type = 1, .nargs = 2,
508 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 } } },
509 { .name = "cloudabi_sys_sock_bind", .ret_type = 1, .nargs = 3,
510 .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
511 { .name = "cloudabi_sys_sock_connect", .ret_type = 1, .nargs = 3,
512 .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
513 { .name = "cloudabi_sys_sock_listen", .ret_type = 1, .nargs = 2,
514 .args = { { Int, 0 }, { Int, 1 } } },
515 { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
516 .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
517 { .name = "cloudabi_sys_sock_stat_get", .ret_type = 1, .nargs = 3,
518 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 },
519 { CloudABISSFlags, 2 } } },
520 { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
521 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
522 { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
526 static STAILQ_HEAD(, syscall) syscalls;
528 /* Xlat idea taken from strace */
534 #define X(a) { a, #a },
535 #define XEND { 0, NULL }
537 static struct xlat kevent_filters[] = {
538 X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
539 X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
540 X(EVFILT_PROCDESC) X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER)
541 X(EVFILT_SENDFILE) XEND
544 static struct xlat kevent_flags[] = {
545 X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
546 X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH) X(EV_FORCEONESHOT)
547 X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
550 static struct xlat kevent_user_ffctrl[] = {
551 X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
555 static struct xlat kevent_rdwr_fflags[] = {
556 X(NOTE_LOWAT) X(NOTE_FILE_POLL) XEND
559 static struct xlat kevent_vnode_fflags[] = {
560 X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB)
561 X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND
564 static struct xlat kevent_proc_fflags[] = {
565 X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR)
569 static struct xlat kevent_timer_fflags[] = {
570 X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS)
574 static struct xlat poll_flags[] = {
575 X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
576 X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
577 X(POLLWRBAND) X(POLLINIGNEOF) XEND
580 static struct xlat sigaction_flags[] = {
581 X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
582 X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
585 static struct xlat pathconf_arg[] = {
586 X(_PC_LINK_MAX) X(_PC_MAX_CANON) X(_PC_MAX_INPUT)
587 X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF)
588 X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE)
589 X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO)
590 X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS)
591 X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE)
592 X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
593 X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
594 X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
595 X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND
598 static struct xlat at_flags[] = {
599 X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW)
603 static struct xlat sysarch_ops[] = {
604 #if defined(__i386__) || defined(__amd64__)
605 X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM)
606 X(I386_VM86) X(I386_GET_FSBASE) X(I386_SET_FSBASE) X(I386_GET_GSBASE)
607 X(I386_SET_GSBASE) X(I386_GET_XFPUSTATE) X(AMD64_GET_FSBASE)
608 X(AMD64_SET_FSBASE) X(AMD64_GET_GSBASE) X(AMD64_SET_GSBASE)
609 X(AMD64_GET_XFPUSTATE)
614 static struct xlat linux_socketcall_ops[] = {
615 X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
616 X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
617 X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
618 X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
619 X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
624 #define X(a) { CLOUDABI_##a, #a },
626 static struct xlat cloudabi_advice[] = {
627 X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
628 X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
632 static struct xlat cloudabi_clockid[] = {
633 X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
634 X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
638 static struct xlat cloudabi_errno[] = {
639 X(E2BIG) X(EACCES) X(EADDRINUSE) X(EADDRNOTAVAIL)
640 X(EAFNOSUPPORT) X(EAGAIN) X(EALREADY) X(EBADF) X(EBADMSG)
641 X(EBUSY) X(ECANCELED) X(ECHILD) X(ECONNABORTED) X(ECONNREFUSED)
642 X(ECONNRESET) X(EDEADLK) X(EDESTADDRREQ) X(EDOM) X(EDQUOT)
643 X(EEXIST) X(EFAULT) X(EFBIG) X(EHOSTUNREACH) X(EIDRM) X(EILSEQ)
644 X(EINPROGRESS) X(EINTR) X(EINVAL) X(EIO) X(EISCONN) X(EISDIR)
645 X(ELOOP) X(EMFILE) X(EMLINK) X(EMSGSIZE) X(EMULTIHOP)
646 X(ENAMETOOLONG) X(ENETDOWN) X(ENETRESET) X(ENETUNREACH)
647 X(ENFILE) X(ENOBUFS) X(ENODEV) X(ENOENT) X(ENOEXEC) X(ENOLCK)
648 X(ENOLINK) X(ENOMEM) X(ENOMSG) X(ENOPROTOOPT) X(ENOSPC)
649 X(ENOSYS) X(ENOTCONN) X(ENOTDIR) X(ENOTEMPTY) X(ENOTRECOVERABLE)
650 X(ENOTSOCK) X(ENOTSUP) X(ENOTTY) X(ENXIO) X(EOVERFLOW)
651 X(EOWNERDEAD) X(EPERM) X(EPIPE) X(EPROTO) X(EPROTONOSUPPORT)
652 X(EPROTOTYPE) X(ERANGE) X(EROFS) X(ESPIPE) X(ESRCH) X(ESTALE)
653 X(ETIMEDOUT) X(ETXTBSY) X(EXDEV) X(ENOTCAPABLE)
657 static struct xlat cloudabi_fdflags[] = {
658 X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
659 X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
663 static struct xlat cloudabi_fdsflags[] = {
664 X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
668 static struct xlat cloudabi_filetype[] = {
669 X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
670 X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
671 X(FILETYPE_FIFO) X(FILETYPE_POLL) X(FILETYPE_PROCESS)
672 X(FILETYPE_REGULAR_FILE) X(FILETYPE_SHARED_MEMORY)
673 X(FILETYPE_SOCKET_DGRAM) X(FILETYPE_SOCKET_SEQPACKET)
674 X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK)
678 static struct xlat cloudabi_fsflags[] = {
679 X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
680 X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
684 static struct xlat cloudabi_mflags[] = {
685 X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
689 static struct xlat cloudabi_mprot[] = {
690 X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
694 static struct xlat cloudabi_msflags[] = {
695 X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
699 static struct xlat cloudabi_oflags[] = {
700 X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
704 static struct xlat cloudabi_sa_family[] = {
705 X(AF_UNSPEC) X(AF_INET) X(AF_INET6) X(AF_UNIX)
709 static struct xlat cloudabi_sdflags[] = {
710 X(SHUT_RD) X(SHUT_WR)
714 static struct xlat cloudabi_signal[] = {
715 X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
716 X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
717 X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
718 X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
719 X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
723 static struct xlat cloudabi_ssflags[] = {
724 X(SOCKSTAT_CLEAR_ERROR)
728 static struct xlat cloudabi_ssstate[] = {
729 X(SOCKSTATE_ACCEPTCONN)
733 static struct xlat cloudabi_ulflags[] = {
738 static struct xlat cloudabi_whence[] = {
739 X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
747 * Searches an xlat array for a value, and returns it if found. Otherwise
748 * return a string representation.
751 lookup(struct xlat *xlat, int val, int base)
755 for (; xlat->str != NULL; xlat++)
756 if (xlat->val == val)
760 sprintf(tmp, "0%o", val);
763 sprintf(tmp, "0x%x", val);
766 sprintf(tmp, "%u", val);
769 errx(1,"Unknown lookup base");
776 xlookup(struct xlat *xlat, int val)
779 return (lookup(xlat, val, 16));
783 * Searches an xlat array containing bitfield values. Remaining bits
784 * set after removing the known ones are printed at the end:
788 xlookup_bits(struct xlat *xlat, int val)
791 static char str[512];
795 for (; xlat->str != NULL; xlat++) {
796 if ((xlat->val & rem) == xlat->val) {
798 * Don't print the "all-bits-zero" string unless all
799 * bits are really zero.
801 if (xlat->val == 0 && val != 0)
803 len += sprintf(str + len, "%s|", xlat->str);
809 * If we have leftover bits or didn't match anything, print
813 len += sprintf(str + len, "0x%x", rem);
814 if (len && str[len - 1] == '|')
821 print_integer_arg(const char *(*decoder)(int), FILE *fp, int value)
825 str = decoder(value);
829 fprintf(fp, "%d", value);
833 print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value)
837 if (!decoder(fp, value, &rem))
838 fprintf(fp, "0x%x", rem);
840 fprintf(fp, "|0x%x", rem);
844 print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), FILE *fp,
849 if (!decoder(fp, value, &rem))
850 fprintf(fp, "0x%x", rem);
852 fprintf(fp, "|0x%x", rem);
857 * Add argument padding to subsequent system calls afater a Quad
858 * syscall arguments as needed. This used to be done by hand in the
859 * decoded_syscalls table which was ugly and error prone. It is
860 * simpler to do the fixup of offsets at initalization time than when
861 * decoding arguments.
864 quad_fixup(struct syscall *sc)
871 for (i = 0; i < sc->nargs; i++) {
872 /* This arg type is a dummy that doesn't use offset. */
873 if ((sc->args[i].type & ARG_MASK) == PipeFds)
876 assert(prev < sc->args[i].offset);
877 prev = sc->args[i].offset;
878 sc->args[i].offset += offset;
879 switch (sc->args[i].type & ARG_MASK) {
884 * 64-bit arguments on 32-bit powerpc must be
885 * 64-bit aligned. If the current offset is
886 * not aligned, the calling convention inserts
887 * a 32-bit pad argument that should be skipped.
889 if (sc->args[i].offset % 2 == 1) {
890 sc->args[i].offset++;
907 STAILQ_INIT(&syscalls);
908 for (sc = decoded_syscalls; sc->name != NULL; sc++) {
912 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
916 static struct syscall *
917 find_syscall(struct procabi *abi, u_int number)
919 struct extra_syscall *es;
921 if (number < nitems(abi->syscalls))
922 return (abi->syscalls[number]);
923 STAILQ_FOREACH(es, &abi->extra_syscalls, entries) {
924 if (es->number == number)
931 add_syscall(struct procabi *abi, u_int number, struct syscall *sc)
933 struct extra_syscall *es;
935 if (number < nitems(abi->syscalls)) {
936 assert(abi->syscalls[number] == NULL);
937 abi->syscalls[number] = sc;
939 es = malloc(sizeof(*es));
942 STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries);
947 * If/when the list gets big, it might be desirable to do it
948 * as a hash table or binary search.
951 get_syscall(struct threadinfo *t, u_int number, u_int nargs)
958 sc = find_syscall(t->proc->abi, number);
962 name = sysdecode_syscallname(t->proc->abi->abi, number);
964 asprintf(&new_name, "#%d", number);
968 STAILQ_FOREACH(sc, &syscalls, entries) {
969 if (strcmp(name, sc->name) == 0) {
970 add_syscall(t->proc->abi, number, sc);
976 /* It is unknown. Add it into the list. */
978 fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
982 sc = calloc(1, sizeof(struct syscall));
984 if (new_name != NULL)
988 for (i = 0; i < nargs; i++) {
989 sc->args[i].offset = i;
990 /* Treat all unknown arguments as LongHex. */
991 sc->args[i].type = LongHex;
993 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
994 add_syscall(t->proc->abi, number, sc);
1000 * Copy a fixed amount of bytes from the process.
1003 get_struct(pid_t pid, void *offset, void *buf, int len)
1005 struct ptrace_io_desc iorequest;
1007 iorequest.piod_op = PIOD_READ_D;
1008 iorequest.piod_offs = offset;
1009 iorequest.piod_addr = buf;
1010 iorequest.piod_len = len;
1011 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
1016 #define MAXSIZE 4096
1019 * Copy a string from the process. Note that it is
1020 * expected to be a C string, but if max is set, it will
1021 * only get that much.
1024 get_string(pid_t pid, void *addr, int max)
1026 struct ptrace_io_desc iorequest;
1028 size_t offset, size, totalsize;
1034 /* Read up to the end of the current page. */
1035 size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE);
1040 buf = malloc(totalsize);
1044 iorequest.piod_op = PIOD_READ_D;
1045 iorequest.piod_offs = (char *)addr + offset;
1046 iorequest.piod_addr = buf + offset;
1047 iorequest.piod_len = size;
1048 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
1052 if (memchr(buf + offset, '\0', size) != NULL)
1055 if (totalsize < MAXSIZE && max == 0) {
1056 size = MAXSIZE - totalsize;
1057 if (size > PAGE_SIZE)
1059 nbuf = realloc(buf, totalsize + size);
1061 buf[totalsize - 1] = '\0';
1067 buf[totalsize - 1] = '\0';
1076 static char tmp[32];
1077 const char *signame;
1079 signame = sysdecode_signal(sig);
1080 if (signame == NULL) {
1081 snprintf(tmp, sizeof(tmp), "%d", sig);
1088 print_kevent(FILE *fp, struct kevent *ke, int input)
1091 switch (ke->filter) {
1097 case EVFILT_PROCDESC:
1098 fprintf(fp, "%ju", (uintmax_t)ke->ident);
1101 fputs(strsig2(ke->ident), fp);
1104 fprintf(fp, "%p", (void *)ke->ident);
1106 fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter),
1107 xlookup_bits(kevent_flags, ke->flags));
1108 switch (ke->filter) {
1111 fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp);
1114 fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp);
1117 case EVFILT_PROCDESC:
1118 fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp);
1121 fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp);
1126 ctrl = ke->fflags & NOTE_FFCTRLMASK;
1127 data = ke->fflags & NOTE_FFLAGSMASK;
1129 fputs(xlookup(kevent_user_ffctrl, ctrl), fp);
1130 if (ke->fflags & NOTE_TRIGGER)
1131 fputs("|NOTE_TRIGGER", fp);
1133 fprintf(fp, "|%#x", data);
1135 fprintf(fp, "%#x", data);
1140 fprintf(fp, "%#x", ke->fflags);
1142 fprintf(fp, ",%p,%p", (void *)ke->data, (void *)ke->udata);
1146 print_utrace(FILE *fp, void *utrace_addr, size_t len)
1148 unsigned char *utrace_buffer;
1151 if (sysdecode_utrace(fp, utrace_addr, len)) {
1156 utrace_buffer = utrace_addr;
1157 fprintf(fp, "%zu:", len);
1159 fprintf(fp, " %02x", *utrace_buffer++);
1164 * Converts a syscall argument into a string. Said string is
1165 * allocated via malloc(), so needs to be free()'d. sc is
1166 * a pointer to the syscall description (see above); args is
1167 * an array of all of the system call arguments.
1170 print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
1171 struct trussinfo *trussinfo)
1178 fp = open_memstream(&tmp, &tmplen);
1179 pid = trussinfo->curthread->proc->pid;
1180 switch (sc->type & ARG_MASK) {
1182 fprintf(fp, "0x%x", (int)args[sc->offset]);
1185 fprintf(fp, "0%o", (int)args[sc->offset]);
1188 fprintf(fp, "%d", (int)args[sc->offset]);
1191 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1194 fprintf(fp, "0x%lx", args[sc->offset]);
1197 fprintf(fp, "%ld", args[sc->offset]);
1200 fprintf(fp, "%zu", (size_t)args[sc->offset]);
1203 /* NULL-terminated string. */
1206 tmp2 = get_string(pid, (void*)args[sc->offset], 0);
1207 fprintf(fp, "\"%s\"", tmp2);
1213 * Binary block of data that might have printable characters.
1214 * XXX If type|OUT, assume that the length is the syscall's
1215 * return value. Otherwise, assume that the length of the block
1216 * is in the next syscall argument.
1218 int max_string = trussinfo->strsize;
1219 char tmp2[max_string + 1], *tmp3;
1226 len = args[sc->offset + 1];
1229 * Don't print more than max_string characters, to avoid word
1230 * wrap. If we have to truncate put some ... after the string.
1232 if (len > max_string) {
1236 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
1238 tmp3 = malloc(len * 4 + 1);
1240 if (strvisx(tmp3, tmp2, len,
1241 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1246 fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1250 fprintf(fp, "0x%lx", args[sc->offset]);
1260 char buf[PAGE_SIZE];
1267 * Only parse argv[] and environment arrays from exec calls
1270 if (((sc->type & ARG_MASK) == ExecArgs &&
1271 (trussinfo->flags & EXECVEARGS) == 0) ||
1272 ((sc->type & ARG_MASK) == ExecEnv &&
1273 (trussinfo->flags & EXECVEENVS) == 0)) {
1274 fprintf(fp, "0x%lx", args[sc->offset]);
1279 * Read a page of pointers at a time. Punt if the top-level
1280 * pointer is not aligned. Note that the first read is of
1283 addr = args[sc->offset];
1284 if (addr % sizeof(char *) != 0) {
1285 fprintf(fp, "0x%lx", args[sc->offset]);
1289 len = PAGE_SIZE - (addr & PAGE_MASK);
1290 if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
1291 fprintf(fp, "0x%lx", args[sc->offset]);
1298 while (u.strarray[i] != NULL) {
1299 string = get_string(pid, u.strarray[i], 0);
1300 fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1305 if (i == len / sizeof(char *)) {
1308 if (get_struct(pid, (void *)addr, u.buf, len) ==
1310 fprintf(fp, ", <inval>");
1321 fprintf(fp, "%ld", args[sc->offset]);
1324 fprintf(fp, "0x%lx", args[sc->offset]);
1329 unsigned long long ll;
1331 #if _BYTE_ORDER == _LITTLE_ENDIAN
1332 ll = (unsigned long long)args[sc->offset + 1] << 32 |
1335 ll = (unsigned long long)args[sc->offset] << 32 |
1336 args[sc->offset + 1];
1338 if ((sc->type & ARG_MASK) == Quad)
1339 fprintf(fp, "%lld", ll);
1341 fprintf(fp, "0x%llx", ll);
1346 fprintf(fp, "0x%lx", args[sc->offset]);
1351 if (retval[0] == -1)
1353 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
1354 fprintf(fp, "\"%s\"", tmp2);
1362 cmd = args[sc->offset];
1363 temp = sysdecode_ioctlname(cmd);
1367 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1368 cmd, cmd & IOC_OUT ? "R" : "",
1369 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1370 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1371 cmd & 0xFF, IOCPARM_LEN(cmd));
1378 if (get_struct(pid, (void *)args[sc->offset], &ts,
1380 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1383 fprintf(fp, "0x%lx", args[sc->offset]);
1387 struct timespec ts[2];
1391 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
1395 for (i = 0; i < nitems(ts); i++) {
1398 switch (ts[i].tv_nsec) {
1400 fprintf(fp, "UTIME_NOW");
1403 fprintf(fp, "UTIME_OMIT");
1406 fprintf(fp, "%jd.%09ld",
1407 (intmax_t)ts[i].tv_sec,
1414 fprintf(fp, "0x%lx", args[sc->offset]);
1420 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1422 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1425 fprintf(fp, "0x%lx", args[sc->offset]);
1429 struct timeval tv[2];
1431 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1433 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1434 (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1435 (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1437 fprintf(fp, "0x%lx", args[sc->offset]);
1441 struct itimerval itv;
1443 if (get_struct(pid, (void *)args[sc->offset], &itv,
1445 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1446 (intmax_t)itv.it_interval.tv_sec,
1447 itv.it_interval.tv_usec,
1448 (intmax_t)itv.it_value.tv_sec,
1449 itv.it_value.tv_usec);
1451 fprintf(fp, "0x%lx", args[sc->offset]);
1456 struct linux_socketcall_args largs;
1458 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
1459 sizeof(largs)) != -1)
1460 fprintf(fp, "{ %s, 0x%lx }",
1461 lookup(linux_socketcall_ops, largs.what, 10),
1462 (long unsigned int)largs.args);
1464 fprintf(fp, "0x%lx", args[sc->offset]);
1469 * XXX: A Pollfd argument expects the /next/ syscall argument
1470 * to be the number of fds in the array. This matches the poll
1474 int numfds = args[sc->offset + 1];
1475 size_t bytes = sizeof(struct pollfd) * numfds;
1478 if ((pfd = malloc(bytes)) == NULL)
1479 err(1, "Cannot malloc %zu bytes for pollfd array",
1481 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
1484 for (i = 0; i < numfds; i++) {
1485 fprintf(fp, " %d/%s", pfd[i].fd,
1486 xlookup_bits(poll_flags, pfd[i].events));
1490 fprintf(fp, "0x%lx", args[sc->offset]);
1497 * XXX: A Fd_set argument expects the /first/ syscall argument
1498 * to be the number of fds in the array. This matches the
1502 int numfds = args[0];
1503 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1506 if ((fds = malloc(bytes)) == NULL)
1507 err(1, "Cannot malloc %zu bytes for fd_set array",
1509 if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
1512 for (i = 0; i < numfds; i++) {
1513 if (FD_ISSET(i, fds))
1514 fprintf(fp, " %d", i);
1518 fprintf(fp, "0x%lx", args[sc->offset]);
1523 fputs(strsig2(args[sc->offset]), fp);
1530 sig = args[sc->offset];
1531 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
1532 sizeof(ss)) == -1) {
1533 fprintf(fp, "0x%lx", args[sc->offset]);
1538 for (i = 1; i < sys_nsig; i++) {
1539 if (sigismember(&ss, i)) {
1540 fprintf(fp, "%s%s", !first ? "|" : "",
1551 print_integer_arg(sysdecode_sigprocmask_how, fp,
1555 /* XXX: Output depends on the value of the previous argument. */
1556 if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
1557 sysdecode_fcntl_arg(fp, args[sc->offset - 1],
1558 args[sc->offset], 16);
1561 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
1564 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
1567 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
1570 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
1573 print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
1576 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
1579 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
1582 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
1585 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
1588 fputs(xlookup(pathconf_arg, args[sc->offset]), fp);
1591 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
1595 struct sockaddr_in *lsin;
1596 struct sockaddr_in6 *lsin6;
1597 struct sockaddr_un *sun;
1598 struct sockaddr *sa;
1602 if (args[sc->offset] == 0) {
1608 * Extract the address length from the next argument. If
1609 * this is an output sockaddr (OUT is set), then the
1610 * next argument is a pointer to a socklen_t. Otherwise
1611 * the next argument contains a socklen_t by value.
1613 if (sc->type & OUT) {
1614 if (get_struct(pid, (void *)args[sc->offset + 1],
1615 &len, sizeof(len)) == -1) {
1616 fprintf(fp, "0x%lx", args[sc->offset]);
1620 len = args[sc->offset + 1];
1622 /* If the length is too small, just bail. */
1623 if (len < sizeof(*sa)) {
1624 fprintf(fp, "0x%lx", args[sc->offset]);
1628 sa = calloc(1, len);
1629 if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) {
1631 fprintf(fp, "0x%lx", args[sc->offset]);
1635 switch (sa->sa_family) {
1637 if (len < sizeof(*lsin))
1638 goto sockaddr_short;
1639 lsin = (struct sockaddr_in *)(void *)sa;
1640 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1641 fprintf(fp, "{ AF_INET %s:%d }", addr,
1642 htons(lsin->sin_port));
1645 if (len < sizeof(*lsin6))
1646 goto sockaddr_short;
1647 lsin6 = (struct sockaddr_in6 *)(void *)sa;
1648 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1650 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1651 htons(lsin6->sin6_port));
1654 sun = (struct sockaddr_un *)sa;
1655 fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1656 (int)(len - offsetof(struct sockaddr_un, sun_path)),
1662 "{ sa_len = %d, sa_family = %d, sa_data = {",
1663 (int)sa->sa_len, (int)sa->sa_family);
1664 for (q = (u_char *)sa->sa_data;
1665 q < (u_char *)sa + len; q++)
1666 fprintf(fp, "%s 0x%02x",
1667 q == (u_char *)sa->sa_data ? "" : ",",
1675 struct sigaction sa;
1677 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
1680 if (sa.sa_handler == SIG_DFL)
1681 fputs("SIG_DFL", fp);
1682 else if (sa.sa_handler == SIG_IGN)
1683 fputs("SIG_IGN", fp);
1685 fprintf(fp, "%p", sa.sa_handler);
1686 fprintf(fp, " %s ss_t }",
1687 xlookup_bits(sigaction_flags, sa.sa_flags));
1689 fprintf(fp, "0x%lx", args[sc->offset]);
1694 * XXX XXX: The size of the array is determined by either the
1695 * next syscall argument, or by the syscall return value,
1696 * depending on which argument number we are. This matches the
1697 * kevent syscall, but luckily that's the only syscall that uses
1705 if (sc->offset == 1)
1706 numevents = args[sc->offset+1];
1707 else if (sc->offset == 3 && retval[0] != -1)
1708 numevents = retval[0];
1710 if (numevents >= 0) {
1711 bytes = sizeof(struct kevent) * numevents;
1712 if ((ke = malloc(bytes)) == NULL)
1714 "Cannot malloc %zu bytes for kevent array",
1718 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
1721 for (i = 0; i < numevents; i++) {
1723 print_kevent(fp, &ke[i], sc->offset == 1);
1727 fprintf(fp, "0x%lx", args[sc->offset]);
1735 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1739 strmode(st.st_mode, mode);
1741 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1742 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1743 (long)st.st_blksize);
1745 fprintf(fp, "0x%lx", args[sc->offset]);
1753 if (get_struct(pid, (void *)args[sc->offset], &buf,
1754 sizeof(buf)) != -1) {
1757 bzero(fsid, sizeof(fsid));
1758 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
1759 for (i = 0; i < sizeof(buf.f_fsid); i++)
1760 snprintf(&fsid[i*2],
1761 sizeof(fsid) - (i*2), "%02x",
1762 ((u_char *)&buf.f_fsid)[i]);
1765 "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
1766 "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
1767 buf.f_mntfromname, fsid);
1769 fprintf(fp, "0x%lx", args[sc->offset]);
1776 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
1779 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
1780 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
1781 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
1782 ru.ru_inblock, ru.ru_oublock);
1784 fprintf(fp, "0x%lx", args[sc->offset]);
1790 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
1792 fprintf(fp, "{ cur=%ju,max=%ju }",
1793 rl.rlim_cur, rl.rlim_max);
1795 fprintf(fp, "0x%lx", args[sc->offset]);
1801 if (get_struct(pid, (void *)args[sc->offset], &status,
1802 sizeof(status)) != -1) {
1804 if (WIFCONTINUED(status))
1805 fputs("CONTINUED", fp);
1806 else if (WIFEXITED(status))
1807 fprintf(fp, "EXITED,val=%d",
1808 WEXITSTATUS(status));
1809 else if (WIFSIGNALED(status))
1810 fprintf(fp, "SIGNALED,sig=%s%s",
1811 strsig2(WTERMSIG(status)),
1812 WCOREDUMP(status) ? ",cored" : "");
1814 fprintf(fp, "STOPPED,sig=%s",
1815 strsig2(WTERMSIG(status)));
1818 fprintf(fp, "0x%lx", args[sc->offset]);
1822 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]);
1825 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]);
1828 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]);
1831 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]);
1834 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]);
1837 fputs(xlookup_bits(at_flags, args[sc->offset]), fp);
1840 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]);
1843 fputs(xlookup(sysarch_ops, args[sc->offset]), fp);
1847 * The pipe() system call in the kernel returns its
1848 * two file descriptors via return values. However,
1849 * the interface exposed by libc is that pipe()
1850 * accepts a pointer to an array of descriptors.
1851 * Format the output to match the libc API by printing
1852 * the returned file descriptors as a fake argument.
1854 * Overwrite the first retval to signal a successful
1857 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
1864 len = args[sc->offset + 1];
1865 utrace_addr = calloc(1, len);
1866 if (get_struct(pid, (void *)args[sc->offset],
1867 (void *)utrace_addr, len) != -1)
1868 print_utrace(fp, utrace_addr, len);
1870 fprintf(fp, "0x%lx", args[sc->offset]);
1875 int descriptors[16];
1876 unsigned long i, ndescriptors;
1879 ndescriptors = args[sc->offset + 1];
1881 if (ndescriptors > nitems(descriptors)) {
1882 ndescriptors = nitems(descriptors);
1885 if (get_struct(pid, (void *)args[sc->offset],
1886 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
1888 for (i = 0; i < ndescriptors; i++)
1889 fprintf(fp, i == 0 ? " %d" : ", %d",
1891 fprintf(fp, truncated ? ", ... }" : " }");
1893 fprintf(fp, "0x%lx", args[sc->offset]);
1897 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]);
1899 case CapFcntlRights: {
1902 if (sc->type & OUT) {
1903 if (get_struct(pid, (void *)args[sc->offset], &rights,
1904 sizeof(rights)) == -1) {
1905 fprintf(fp, "0x%lx", args[sc->offset]);
1909 rights = args[sc->offset];
1910 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights);
1914 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]);
1919 if (!sysdecode_fileflags(fp, args[sc->offset], &rem))
1920 fprintf(fp, "0x%x", rem);
1922 fprintf(fp, "|0x%x", rem);
1926 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]);
1929 print_integer_arg(sysdecode_getfsstat_mode, fp,
1933 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]);
1935 case Kldunloadflags:
1936 print_integer_arg(sysdecode_kldunload_flags, fp,
1940 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]);
1943 fprintf(fp, "%u", (socklen_t)args[sc->offset]);
1945 case Sockprotocol: {
1947 int domain, protocol;
1949 domain = args[sc->offset - 2];
1950 protocol = args[sc->offset];
1951 if (protocol == 0) {
1954 temp = sysdecode_socket_protocol(domain, protocol);
1958 fprintf(fp, "%d", protocol);
1964 print_integer_arg(sysdecode_sockopt_level, fp,
1971 level = args[sc->offset - 1];
1972 name = args[sc->offset];
1973 temp = sysdecode_sockopt_name(level, name);
1977 fprintf(fp, "%d", name);
1982 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]);
1985 cap_rights_t rights;
1987 if (get_struct(pid, (void *)args[sc->offset], &rights,
1988 sizeof(rights)) != -1) {
1990 sysdecode_cap_rights(fp, &rights);
1993 fprintf(fp, "0x%lx", args[sc->offset]);
1997 case CloudABIAdvice:
1998 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
2000 case CloudABIClockID:
2001 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2003 case ClouduABIFDSFlags:
2004 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2006 case CloudABIFDStat: {
2007 cloudabi_fdstat_t fds;
2008 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds))
2010 fprintf(fp, "{ %s, ",
2011 xlookup(cloudabi_filetype, fds.fs_filetype));
2012 fprintf(fp, "%s, ... }",
2013 xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2015 fprintf(fp, "0x%lx", args[sc->offset]);
2018 case CloudABIFileStat: {
2019 cloudabi_filestat_t fsb;
2020 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb))
2022 fprintf(fp, "{ %s, %ju }",
2023 xlookup(cloudabi_filetype, fsb.st_filetype),
2024 (uintmax_t)fsb.st_size);
2026 fprintf(fp, "0x%lx", args[sc->offset]);
2029 case CloudABIFileType:
2030 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2032 case CloudABIFSFlags:
2033 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2035 case CloudABILookup:
2036 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2037 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2038 (int)args[sc->offset]);
2040 fprintf(fp, "%d", (int)args[sc->offset]);
2042 case CloudABIMFlags:
2043 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2046 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2048 case CloudABIMSFlags:
2049 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2051 case CloudABIOFlags:
2052 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2054 case CloudABISDFlags:
2055 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2057 case CloudABISignal:
2058 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2060 case CloudABISockStat: {
2061 cloudabi_sockstat_t ss;
2062 if (get_struct(pid, (void *)args[sc->offset], &ss, sizeof(ss))
2064 fprintf(fp, "{ %s, ", xlookup(
2065 cloudabi_sa_family, ss.ss_sockname.sa_family));
2066 fprintf(fp, "%s, ", xlookup(
2067 cloudabi_sa_family, ss.ss_peername.sa_family));
2068 fprintf(fp, "%s, ", xlookup(
2069 cloudabi_errno, ss.ss_error));
2070 fprintf(fp, "%s }", xlookup_bits(
2071 cloudabi_ssstate, ss.ss_state));
2073 fprintf(fp, "0x%lx", args[sc->offset]);
2076 case CloudABISSFlags:
2077 fputs(xlookup_bits(cloudabi_ssflags, args[sc->offset]), fp);
2079 case CloudABITimestamp:
2080 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2081 args[sc->offset] % 1000000000);
2083 case CloudABIULFlags:
2084 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2086 case CloudABIWhence:
2087 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2091 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2098 * Print (to outfile) the system call and its arguments.
2101 print_syscall(struct trussinfo *trussinfo)
2103 struct threadinfo *t;
2108 t = trussinfo->curthread;
2110 name = t->cs.sc->name;
2111 nargs = t->cs.nargs;
2112 s_args = t->cs.s_args;
2114 len = print_line_prefix(trussinfo);
2115 len += fprintf(trussinfo->outfile, "%s(", name);
2117 for (i = 0; i < nargs; i++) {
2118 if (s_args[i] != NULL)
2119 len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2121 len += fprintf(trussinfo->outfile,
2122 "<missing argument>");
2123 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2126 len += fprintf(trussinfo->outfile, ")");
2127 for (i = 0; i < 6 - (len / 8); i++)
2128 fprintf(trussinfo->outfile, "\t");
2132 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
2134 struct timespec timediff;
2135 struct threadinfo *t;
2139 t = trussinfo->curthread;
2141 if (trussinfo->flags & COUNTONLY) {
2142 timespecsubt(&t->after, &t->before, &timediff);
2143 timespecadd(&sc->time, &timediff, &sc->time);
2150 print_syscall(trussinfo);
2151 fflush(trussinfo->outfile);
2153 if (retval == NULL) {
2155 * This system call resulted in the current thread's exit,
2156 * so there is no return value or error to display.
2158 fprintf(trussinfo->outfile, "\n");
2163 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi,
2165 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
2166 error == INT_MAX ? "Unknown error" : strerror(error));
2169 else if (sc->ret_type == 2) {
2172 #if _BYTE_ORDER == _LITTLE_ENDIAN
2173 off = (off_t)retval[1] << 32 | retval[0];
2175 off = (off_t)retval[0] << 32 | retval[1];
2177 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2182 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
2187 print_summary(struct trussinfo *trussinfo)
2189 struct timespec total = {0, 0};
2193 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2194 "syscall", "seconds", "calls", "errors");
2196 STAILQ_FOREACH(sc, &syscalls, entries)
2198 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2199 sc->name, (intmax_t)sc->time.tv_sec,
2200 sc->time.tv_nsec, sc->ncalls, sc->nerror);
2201 timespecadd(&total, &sc->time, &total);
2202 ncall += sc->ncalls;
2203 nerror += sc->nerror;
2205 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2206 "", "-------------", "-------", "-------");
2207 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2208 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);