libc/{i386,amd64}: Do not export .cerror when building WITHOUT_SYMVER
[freebsd-src.git] / usr.bin / truss / syscalls.c
blobb3a4c423f7b70ed9835a9cd865352e9dcf09f649
1 /*
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
6 * are met:
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
17 * permission.
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
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
36 * This file has routines used to print out system calls and their
37 * arguments.
40 #include <sys/types.h>
41 #include <sys/event.h>
42 #include <sys/ioccom.h>
43 #include <sys/mman.h>
44 #include <sys/mount.h>
45 #include <sys/procctl.h>
46 #include <sys/ptrace.h>
47 #include <sys/resource.h>
48 #include <sys/socket.h>
49 #include <sys/stat.h>
50 #include <sys/umtx.h>
51 #include <sys/un.h>
52 #include <sys/wait.h>
53 #include <machine/sysarch.h>
54 #include <netinet/in.h>
55 #include <arpa/inet.h>
57 #include <ctype.h>
58 #include <err.h>
59 #include <fcntl.h>
60 #include <poll.h>
61 #include <signal.h>
62 #include <stdbool.h>
63 #include <stddef.h>
64 #include <stdint.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include <sysdecode.h>
69 #include <time.h>
70 #include <unistd.h>
71 #include <vis.h>
73 #include <compat/cloudabi/cloudabi_syscalldefs.h>
75 #include "truss.h"
76 #include "extern.h"
77 #include "syscall.h"
79 /* 64-bit alignment on 32-bit platforms. */
80 #if !defined(__LP64__) && defined(__powerpc__)
81 #define QUAD_ALIGN 1
82 #else
83 #define QUAD_ALIGN 0
84 #endif
86 /* Number of slots needed for a 64-bit argument. */
87 #ifdef __LP64__
88 #define QUAD_SLOTS 1
89 #else
90 #define QUAD_SLOTS 2
91 #endif
94 * This should probably be in its own file, sorted alphabetically.
96 static struct syscall decoded_syscalls[] = {
97 /* Native ABI */
98 { .name = "__getcwd", .ret_type = 1, .nargs = 2,
99 .args = { { Name | OUT, 0 }, { Int, 1 } } },
100 { .name = "_umtx_op", .ret_type = 1, .nargs = 5,
101 .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
102 { Ptr, 4 } } },
103 { .name = "accept", .ret_type = 1, .nargs = 3,
104 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
105 { .name = "access", .ret_type = 1, .nargs = 2,
106 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
107 { .name = "bind", .ret_type = 1, .nargs = 3,
108 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
109 { .name = "bindat", .ret_type = 1, .nargs = 4,
110 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
111 { Int, 3 } } },
112 { .name = "break", .ret_type = 1, .nargs = 1,
113 .args = { { Ptr, 0 } } },
114 { .name = "chdir", .ret_type = 1, .nargs = 1,
115 .args = { { Name, 0 } } },
116 { .name = "chflags", .ret_type = 1, .nargs = 2,
117 .args = { { Name | IN, 0 }, { Hex, 1 } } },
118 { .name = "chmod", .ret_type = 1, .nargs = 2,
119 .args = { { Name, 0 }, { Octal, 1 } } },
120 { .name = "chown", .ret_type = 1, .nargs = 3,
121 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
122 { .name = "chroot", .ret_type = 1, .nargs = 1,
123 .args = { { Name, 0 } } },
124 { .name = "clock_gettime", .ret_type = 1, .nargs = 2,
125 .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
126 { .name = "close", .ret_type = 1, .nargs = 1,
127 .args = { { Int, 0 } } },
128 { .name = "connect", .ret_type = 1, .nargs = 3,
129 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
130 { .name = "connectat", .ret_type = 1, .nargs = 4,
131 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
132 { Int, 3 } } },
133 { .name = "eaccess", .ret_type = 1, .nargs = 2,
134 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
135 { .name = "execve", .ret_type = 1, .nargs = 3,
136 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
137 { ExecEnv | IN, 2 } } },
138 { .name = "exit", .ret_type = 0, .nargs = 1,
139 .args = { { Hex, 0 } } },
140 { .name = "faccessat", .ret_type = 1, .nargs = 4,
141 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
142 { Atflags, 3 } } },
143 { .name = "fchmod", .ret_type = 1, .nargs = 2,
144 .args = { { Int, 0 }, { Octal, 1 } } },
145 { .name = "fchmodat", .ret_type = 1, .nargs = 4,
146 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
147 { .name = "fchown", .ret_type = 1, .nargs = 3,
148 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
149 { .name = "fchownat", .ret_type = 1, .nargs = 5,
150 .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
151 { Atflags, 4 } } },
152 { .name = "fcntl", .ret_type = 1, .nargs = 3,
153 .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
154 { .name = "fstat", .ret_type = 1, .nargs = 2,
155 .args = { { Int, 0 }, { Stat | OUT, 1 } } },
156 { .name = "fstatat", .ret_type = 1, .nargs = 4,
157 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
158 { Atflags, 3 } } },
159 { .name = "fstatfs", .ret_type = 1, .nargs = 2,
160 .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
161 { .name = "ftruncate", .ret_type = 1, .nargs = 2,
162 .args = { { Int | IN, 0 }, { QuadHex | IN, 1 + QUAD_ALIGN } } },
163 { .name = "futimens", .ret_type = 1, .nargs = 2,
164 .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
165 { .name = "futimes", .ret_type = 1, .nargs = 2,
166 .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
167 { .name = "futimesat", .ret_type = 1, .nargs = 3,
168 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
169 { .name = "getitimer", .ret_type = 1, .nargs = 2,
170 .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
171 { .name = "getpeername", .ret_type = 1, .nargs = 3,
172 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
173 { .name = "getpgid", .ret_type = 1, .nargs = 1,
174 .args = { { Int, 0 } } },
175 { .name = "getrlimit", .ret_type = 1, .nargs = 2,
176 .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
177 { .name = "getrusage", .ret_type = 1, .nargs = 2,
178 .args = { { Int, 0 }, { Rusage | OUT, 1 } } },
179 { .name = "getsid", .ret_type = 1, .nargs = 1,
180 .args = { { Int, 0 } } },
181 { .name = "getsockname", .ret_type = 1, .nargs = 3,
182 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
183 { .name = "gettimeofday", .ret_type = 1, .nargs = 2,
184 .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
185 { .name = "ioctl", .ret_type = 1, .nargs = 3,
186 .args = { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 } } },
187 { .name = "kevent", .ret_type = 1, .nargs = 6,
188 .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
189 { Int, 4 }, { Timespec, 5 } } },
190 { .name = "kill", .ret_type = 1, .nargs = 2,
191 .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
192 { .name = "kldfind", .ret_type = 1, .nargs = 1,
193 .args = { { Name | IN, 0 } } },
194 { .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
195 .args = { { Int, 0 } } },
196 { .name = "kldload", .ret_type = 1, .nargs = 1,
197 .args = { { Name | IN, 0 } } },
198 { .name = "kldnext", .ret_type = 1, .nargs = 1,
199 .args = { { Int, 0 } } },
200 { .name = "kldstat", .ret_type = 1, .nargs = 2,
201 .args = { { Int, 0 }, { Ptr, 1 } } },
202 { .name = "kldunload", .ret_type = 1, .nargs = 1,
203 .args = { { Int, 0 } } },
204 { .name = "kse_release", .ret_type = 0, .nargs = 1,
205 .args = { { Timespec, 0 } } },
206 { .name = "lchflags", .ret_type = 1, .nargs = 2,
207 .args = { { Name | IN, 0 }, { Hex, 1 } } },
208 { .name = "lchmod", .ret_type = 1, .nargs = 2,
209 .args = { { Name, 0 }, { Octal, 1 } } },
210 { .name = "lchown", .ret_type = 1, .nargs = 3,
211 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
212 { .name = "link", .ret_type = 1, .nargs = 2,
213 .args = { { Name, 0 }, { Name, 1 } } },
214 { .name = "linkat", .ret_type = 1, .nargs = 5,
215 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
216 { Atflags, 4 } } },
217 { .name = "lseek", .ret_type = 2, .nargs = 3,
218 .args = { { Int, 0 }, { QuadHex, 1 + QUAD_ALIGN },
219 { Whence, 1 + QUAD_SLOTS + QUAD_ALIGN } } },
220 { .name = "lstat", .ret_type = 1, .nargs = 2,
221 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
222 { .name = "lutimes", .ret_type = 1, .nargs = 2,
223 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
224 { .name = "mkdir", .ret_type = 1, .nargs = 2,
225 .args = { { Name, 0 }, { Octal, 1 } } },
226 { .name = "mkdirat", .ret_type = 1, .nargs = 3,
227 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
228 { .name = "mkfifo", .ret_type = 1, .nargs = 2,
229 .args = { { Name, 0 }, { Octal, 1 } } },
230 { .name = "mkfifoat", .ret_type = 1, .nargs = 3,
231 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
232 { .name = "mknod", .ret_type = 1, .nargs = 3,
233 .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
234 { .name = "mknodat", .ret_type = 1, .nargs = 4,
235 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
236 { .name = "mmap", .ret_type = 1, .nargs = 6,
237 .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
238 { Int, 4 }, { QuadHex, 5 + QUAD_ALIGN } } },
239 { .name = "modfind", .ret_type = 1, .nargs = 1,
240 .args = { { Name | IN, 0 } } },
241 { .name = "mount", .ret_type = 1, .nargs = 4,
242 .args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } },
243 { .name = "mprotect", .ret_type = 1, .nargs = 3,
244 .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 } } },
245 { .name = "munmap", .ret_type = 1, .nargs = 2,
246 .args = { { Ptr, 0 }, { Int, 1 } } },
247 { .name = "nanosleep", .ret_type = 1, .nargs = 1,
248 .args = { { Timespec, 0 } } },
249 { .name = "open", .ret_type = 1, .nargs = 3,
250 .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
251 { .name = "openat", .ret_type = 1, .nargs = 4,
252 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
253 { Octal, 3 } } },
254 { .name = "pathconf", .ret_type = 1, .nargs = 2,
255 .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
256 { .name = "pipe", .ret_type = 1, .nargs = 1,
257 .args = { { PipeFds | OUT, 0 } } },
258 { .name = "pipe2", .ret_type = 1, .nargs = 2,
259 .args = { { Ptr, 0 }, { Open, 1 } } },
260 { .name = "poll", .ret_type = 1, .nargs = 3,
261 .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
262 { .name = "posix_openpt", .ret_type = 1, .nargs = 1,
263 .args = { { Open, 0 } } },
264 { .name = "procctl", .ret_type = 1, .nargs = 4,
265 .args = { { Idtype, 0 }, { Quad, 1 + QUAD_ALIGN },
266 { Procctl, 1 + QUAD_ALIGN + QUAD_SLOTS },
267 { Ptr, 2 + QUAD_ALIGN + QUAD_SLOTS } } },
268 { .name = "read", .ret_type = 1, .nargs = 3,
269 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 } } },
270 { .name = "readlink", .ret_type = 1, .nargs = 3,
271 .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Int, 2 } } },
272 { .name = "readlinkat", .ret_type = 1, .nargs = 4,
273 .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
274 { Int, 3 } } },
275 { .name = "recvfrom", .ret_type = 1, .nargs = 6,
276 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Hex, 3 },
277 { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } },
278 { .name = "rename", .ret_type = 1, .nargs = 2,
279 .args = { { Name, 0 }, { Name, 1 } } },
280 { .name = "renameat", .ret_type = 1, .nargs = 4,
281 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
282 { .name = "rfork", .ret_type = 1, .nargs = 1,
283 .args = { { Rforkflags, 0 } } },
284 { .name = "select", .ret_type = 1, .nargs = 5,
285 .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
286 { Timeval, 4 } } },
287 { .name = "sendto", .ret_type = 1, .nargs = 6,
288 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Hex, 3 },
289 { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } },
290 { .name = "setitimer", .ret_type = 1, .nargs = 3,
291 .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
292 { .name = "setrlimit", .ret_type = 1, .nargs = 2,
293 .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
294 { .name = "shutdown", .ret_type = 1, .nargs = 2,
295 .args = { { Int, 0 }, { Shutdown, 1 } } },
296 { .name = "sigaction", .ret_type = 1, .nargs = 3,
297 .args = { { Signal, 0 }, { Sigaction | IN, 1 },
298 { Sigaction | OUT, 2 } } },
299 { .name = "sigpending", .ret_type = 1, .nargs = 1,
300 .args = { { Sigset | OUT, 0 } } },
301 { .name = "sigprocmask", .ret_type = 1, .nargs = 3,
302 .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
303 { .name = "sigqueue", .ret_type = 1, .nargs = 3,
304 .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
305 { .name = "sigreturn", .ret_type = 1, .nargs = 1,
306 .args = { { Ptr, 0 } } },
307 { .name = "sigsuspend", .ret_type = 1, .nargs = 1,
308 .args = { { Sigset | IN, 0 } } },
309 { .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
310 .args = { { Sigset | IN, 0 }, { Ptr, 1 }, { Timespec | IN, 2 } } },
311 { .name = "sigwait", .ret_type = 1, .nargs = 2,
312 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
313 { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
314 .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
315 { .name = "socket", .ret_type = 1, .nargs = 3,
316 .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Int, 2 } } },
317 { .name = "stat", .ret_type = 1, .nargs = 2,
318 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
319 { .name = "statfs", .ret_type = 1, .nargs = 2,
320 .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } },
321 { .name = "symlink", .ret_type = 1, .nargs = 2,
322 .args = { { Name, 0 }, { Name, 1 } } },
323 { .name = "symlinkat", .ret_type = 1, .nargs = 3,
324 .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } },
325 { .name = "sysarch", .ret_type = 1, .nargs = 2,
326 .args = { { Sysarch, 0 }, { Ptr, 1 } } },
327 { .name = "thr_kill", .ret_type = 1, .nargs = 2,
328 .args = { { Long, 0 }, { Signal, 1 } } },
329 { .name = "thr_self", .ret_type = 1, .nargs = 1,
330 .args = { { Ptr, 0 } } },
331 { .name = "truncate", .ret_type = 1, .nargs = 2,
332 .args = { { Name | IN, 0 }, { QuadHex | IN, 1 + QUAD_ALIGN } } },
333 #if 0
334 /* Does not exist */
335 { .name = "umount", .ret_type = 1, .nargs = 2,
336 .args = { { Name, 0 }, { Int, 2 } } },
337 #endif
338 { .name = "unlink", .ret_type = 1, .nargs = 1,
339 .args = { { Name, 0 } } },
340 { .name = "unlinkat", .ret_type = 1, .nargs = 3,
341 .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
342 { .name = "unmount", .ret_type = 1, .nargs = 2,
343 .args = { { Name, 0 }, { Int, 1 } } },
344 { .name = "utimensat", .ret_type = 1, .nargs = 4,
345 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
346 { Atflags, 3 } } },
347 { .name = "utimes", .ret_type = 1, .nargs = 2,
348 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
349 { .name = "utrace", .ret_type = 1, .nargs = 1,
350 .args = { { Utrace, 0 } } },
351 { .name = "wait4", .ret_type = 1, .nargs = 4,
352 .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
353 { Rusage | OUT, 3 } } },
354 { .name = "wait6", .ret_type = 1, .nargs = 6,
355 .args = { { Idtype, 0 }, { Quad, 1 + QUAD_ALIGN },
356 { ExitStatus | OUT, 1 + QUAD_ALIGN + QUAD_SLOTS },
357 { Waitoptions, 2 + QUAD_ALIGN + QUAD_SLOTS },
358 { Rusage | OUT, 3 + QUAD_ALIGN + QUAD_SLOTS },
359 { Ptr, 4 + QUAD_ALIGN + QUAD_SLOTS } } },
360 { .name = "write", .ret_type = 1, .nargs = 3,
361 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 } } },
363 /* Linux ABI */
364 { .name = "linux_access", .ret_type = 1, .nargs = 2,
365 .args = { { Name, 0 }, { Accessmode, 1 } } },
366 { .name = "linux_execve", .ret_type = 1, .nargs = 3,
367 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
368 { ExecEnv | IN, 2 } } },
369 { .name = "linux_lseek", .ret_type = 2, .nargs = 3,
370 .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
371 { .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
372 .args = { { Name | IN, 0 }, { Int, 1 } } },
373 { .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
374 .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
375 { .name = "linux_newstat", .ret_type = 1, .nargs = 2,
376 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
377 { .name = "linux_open", .ret_type = 1, .nargs = 3,
378 .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
379 { .name = "linux_readlink", .ret_type = 1, .nargs = 3,
380 .args = { { Name, 0 }, { Name | OUT, 1 }, { Int, 2 } } },
381 { .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
382 .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
383 { .name = "linux_stat64", .ret_type = 1, .nargs = 3,
384 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 }, { Ptr | IN, 1 } } },
386 /* CloudABI system calls. */
387 { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
388 .args = { { CloudABIClockID, 0 } } },
389 { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
390 .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
391 { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
392 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
393 { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
394 .args = { { Int, 0 } } },
395 { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
396 .args = { { CloudABIFileType, 0 } } },
397 { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
398 .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
399 { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
400 .args = { { Int, 0 } } },
401 { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
402 .args = { { Int, 0 } } },
403 { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
404 .args = { { Int, 0 }, { Int, 1 } } },
405 { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
406 .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
407 { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
408 .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
409 { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
410 .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
411 { ClouduABIFDSFlags, 2 } } },
412 { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
413 .args = { { Int, 0 } } },
414 { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
415 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
416 { CloudABIAdvice, 3 } } },
417 { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
418 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
419 { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
420 .args = { { Int, 0 }, { BinString | IN, 1 },
421 { CloudABIFileType, 3 } } },
422 { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
423 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
424 { Int, 3 }, { BinString | IN, 4 } } },
425 { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
426 .args = { { Int, 0 }, { BinString | IN, 1 },
427 { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
428 { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
429 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
430 { Int, 3 } } },
431 { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
432 .args = { { Int, 0 }, { BinString | IN, 1 },
433 { BinString | OUT, 3 }, { Int, 4 } } },
434 { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
435 .args = { { Int, 0 }, { BinString | IN, 1 },
436 { Int, 3 }, { BinString | IN, 4 } } },
437 { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
438 .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
439 { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
440 .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
441 { CloudABIFSFlags, 2 } } },
442 { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
443 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
444 { CloudABIFileStat | OUT, 3 } } },
445 { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
446 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
447 { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
448 { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
449 .args = { { BinString | IN, 0 },
450 { Int, 2 }, { BinString | IN, 3 } } },
451 { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
452 .args = { { Int, 0 }, { BinString | IN, 1 },
453 { CloudABIULFlags, 3 } } },
454 { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
455 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
456 { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
457 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
458 { .name = "cloudabi_sys_mem_lock", .ret_type = 1, .nargs = 2,
459 .args = { { Ptr, 0 }, { Int, 1 } } },
460 { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
461 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
462 { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
463 { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
464 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
465 { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
466 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
467 { .name = "cloudabi_sys_mem_unlock", .ret_type = 1, .nargs = 2,
468 .args = { { Ptr, 0 }, { Int, 1 } } },
469 { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
470 .args = { { Ptr, 0 }, { Int, 1 } } },
471 { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
472 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
473 { IntArray, 3 }, { Int, 4 } } },
474 { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
475 .args = { { Int, 0 } } },
476 { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
477 { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
478 .args = { { CloudABISignal, 0 } } },
479 { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
480 .args = { { BinString | OUT, 0 }, { Int, 1 } } },
481 { .name = "cloudabi_sys_sock_accept", .ret_type = 1, .nargs = 2,
482 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 } } },
483 { .name = "cloudabi_sys_sock_bind", .ret_type = 1, .nargs = 3,
484 .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
485 { .name = "cloudabi_sys_sock_connect", .ret_type = 1, .nargs = 3,
486 .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
487 { .name = "cloudabi_sys_sock_listen", .ret_type = 1, .nargs = 2,
488 .args = { { Int, 0 }, { Int, 1 } } },
489 { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
490 .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
491 { .name = "cloudabi_sys_sock_stat_get", .ret_type = 1, .nargs = 3,
492 .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 },
493 { CloudABISSFlags, 2 } } },
494 { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
495 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
496 { .name = "cloudabi_sys_thread_tcb_set", .ret_type = 1, .nargs = 1,
497 .args = { { Ptr, 0 } } },
498 { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
500 { .name = 0 },
502 static STAILQ_HEAD(, syscall) syscalls;
504 /* Xlat idea taken from strace */
505 struct xlat {
506 int val;
507 const char *str;
510 #define X(a) { a, #a },
511 #define XEND { 0, NULL }
513 static struct xlat kevent_filters[] = {
514 X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
515 X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
516 X(EVFILT_PROCDESC) X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER)
517 X(EVFILT_SENDFILE) XEND
520 static struct xlat kevent_flags[] = {
521 X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
522 X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH) X(EV_FORCEONESHOT)
523 X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
526 static struct xlat kevent_user_ffctrl[] = {
527 X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
528 XEND
531 static struct xlat kevent_rdwr_fflags[] = {
532 X(NOTE_LOWAT) X(NOTE_FILE_POLL) XEND
535 static struct xlat kevent_vnode_fflags[] = {
536 X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB)
537 X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND
540 static struct xlat kevent_proc_fflags[] = {
541 X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR)
542 X(NOTE_CHILD) XEND
545 static struct xlat kevent_timer_fflags[] = {
546 X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS)
547 XEND
550 static struct xlat poll_flags[] = {
551 X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
552 X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
553 X(POLLWRBAND) X(POLLINIGNEOF) XEND
556 static struct xlat mmap_flags[] = {
557 X(MAP_SHARED) X(MAP_PRIVATE) X(MAP_FIXED) X(MAP_RESERVED0020)
558 X(MAP_RESERVED0040) X(MAP_RESERVED0080) X(MAP_RESERVED0100)
559 X(MAP_HASSEMAPHORE) X(MAP_STACK) X(MAP_NOSYNC) X(MAP_ANON)
560 X(MAP_EXCL) X(MAP_NOCORE) X(MAP_PREFAULT_READ)
561 #ifdef MAP_32BIT
562 X(MAP_32BIT)
563 #endif
564 XEND
567 static struct xlat mprot_flags[] = {
568 X(PROT_NONE) X(PROT_READ) X(PROT_WRITE) X(PROT_EXEC) XEND
571 static struct xlat whence_arg[] = {
572 X(SEEK_SET) X(SEEK_CUR) X(SEEK_END) X(SEEK_DATA) X(SEEK_HOLE) XEND
575 static struct xlat sigaction_flags[] = {
576 X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
577 X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
580 static struct xlat fcntl_arg[] = {
581 X(F_DUPFD) X(F_GETFD) X(F_SETFD) X(F_GETFL) X(F_SETFL)
582 X(F_GETOWN) X(F_SETOWN) X(F_OGETLK) X(F_OSETLK) X(F_OSETLKW)
583 X(F_DUP2FD) X(F_GETLK) X(F_SETLK) X(F_SETLKW) X(F_SETLK_REMOTE)
584 X(F_READAHEAD) X(F_RDAHEAD) X(F_DUPFD_CLOEXEC) X(F_DUP2FD_CLOEXEC)
585 XEND
588 static struct xlat fcntlfd_arg[] = {
589 X(FD_CLOEXEC) XEND
592 static struct xlat fcntlfl_arg[] = {
593 X(O_APPEND) X(O_ASYNC) X(O_FSYNC) X(O_NONBLOCK) X(O_NOFOLLOW)
594 X(FRDAHEAD) X(O_DIRECT) XEND
597 static struct xlat sockdomain_arg[] = {
598 X(PF_UNSPEC) X(PF_LOCAL) X(PF_UNIX) X(PF_INET) X(PF_IMPLINK)
599 X(PF_PUP) X(PF_CHAOS) X(PF_NETBIOS) X(PF_ISO) X(PF_OSI)
600 X(PF_ECMA) X(PF_DATAKIT) X(PF_CCITT) X(PF_SNA) X(PF_DECnet)
601 X(PF_DLI) X(PF_LAT) X(PF_HYLINK) X(PF_APPLETALK) X(PF_ROUTE)
602 X(PF_LINK) X(PF_XTP) X(PF_COIP) X(PF_CNT) X(PF_SIP) X(PF_IPX)
603 X(PF_RTIP) X(PF_PIP) X(PF_ISDN) X(PF_KEY) X(PF_INET6)
604 X(PF_NATM) X(PF_ATM) X(PF_NETGRAPH) X(PF_SLOW) X(PF_SCLUSTER)
605 X(PF_ARP) X(PF_BLUETOOTH) X(PF_IEEE80211) X(PF_INET_SDP)
606 X(PF_INET6_SDP) XEND
609 static struct xlat socktype_arg[] = {
610 X(SOCK_STREAM) X(SOCK_DGRAM) X(SOCK_RAW) X(SOCK_RDM)
611 X(SOCK_SEQPACKET) XEND
614 static struct xlat open_flags[] = {
615 X(O_RDONLY) X(O_WRONLY) X(O_RDWR) X(O_ACCMODE) X(O_NONBLOCK)
616 X(O_APPEND) X(O_SHLOCK) X(O_EXLOCK) X(O_ASYNC) X(O_FSYNC)
617 X(O_NOFOLLOW) X(O_CREAT) X(O_TRUNC) X(O_EXCL) X(O_NOCTTY)
618 X(O_DIRECT) X(O_DIRECTORY) X(O_EXEC) X(O_TTY_INIT) X(O_CLOEXEC)
619 X(O_VERIFY) XEND
622 static struct xlat shutdown_arg[] = {
623 X(SHUT_RD) X(SHUT_WR) X(SHUT_RDWR) XEND
626 static struct xlat resource_arg[] = {
627 X(RLIMIT_CPU) X(RLIMIT_FSIZE) X(RLIMIT_DATA) X(RLIMIT_STACK)
628 X(RLIMIT_CORE) X(RLIMIT_RSS) X(RLIMIT_MEMLOCK) X(RLIMIT_NPROC)
629 X(RLIMIT_NOFILE) X(RLIMIT_SBSIZE) X(RLIMIT_VMEM) X(RLIMIT_NPTS)
630 X(RLIMIT_SWAP) X(RLIMIT_KQUEUES) XEND
633 static struct xlat pathconf_arg[] = {
634 X(_PC_LINK_MAX) X(_PC_MAX_CANON) X(_PC_MAX_INPUT)
635 X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF)
636 X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE)
637 X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO)
638 X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS)
639 X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE)
640 X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
641 X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
642 X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
643 X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND
646 static struct xlat rfork_flags[] = {
647 X(RFFDG) X(RFPROC) X(RFMEM) X(RFNOWAIT) X(RFCFDG) X(RFTHREAD)
648 X(RFSIGSHARE) X(RFLINUXTHPN) X(RFTSIGZMB) X(RFPPWAIT) XEND
651 static struct xlat wait_options[] = {
652 X(WNOHANG) X(WUNTRACED) X(WCONTINUED) X(WNOWAIT) X(WEXITED)
653 X(WTRAPPED) XEND
656 static struct xlat idtype_arg[] = {
657 X(P_PID) X(P_PPID) X(P_PGID) X(P_SID) X(P_CID) X(P_UID) X(P_GID)
658 X(P_ALL) X(P_LWPID) X(P_TASKID) X(P_PROJID) X(P_POOLID) X(P_JAILID)
659 X(P_CTID) X(P_CPUID) X(P_PSETID) XEND
662 static struct xlat procctl_arg[] = {
663 X(PROC_SPROTECT) X(PROC_REAP_ACQUIRE) X(PROC_REAP_RELEASE)
664 X(PROC_REAP_STATUS) X(PROC_REAP_GETPIDS) X(PROC_REAP_KILL)
665 X(PROC_TRACE_CTL) X(PROC_TRACE_STATUS) XEND
668 static struct xlat umtx_ops[] = {
669 X(UMTX_OP_RESERVED0) X(UMTX_OP_RESERVED1) X(UMTX_OP_WAIT)
670 X(UMTX_OP_WAKE) X(UMTX_OP_MUTEX_TRYLOCK) X(UMTX_OP_MUTEX_LOCK)
671 X(UMTX_OP_MUTEX_UNLOCK) X(UMTX_OP_SET_CEILING) X(UMTX_OP_CV_WAIT)
672 X(UMTX_OP_CV_SIGNAL) X(UMTX_OP_CV_BROADCAST) X(UMTX_OP_WAIT_UINT)
673 X(UMTX_OP_RW_RDLOCK) X(UMTX_OP_RW_WRLOCK) X(UMTX_OP_RW_UNLOCK)
674 X(UMTX_OP_WAIT_UINT_PRIVATE) X(UMTX_OP_WAKE_PRIVATE)
675 X(UMTX_OP_MUTEX_WAIT) X(UMTX_OP_MUTEX_WAKE) X(UMTX_OP_SEM_WAIT)
676 X(UMTX_OP_SEM_WAKE) X(UMTX_OP_NWAKE_PRIVATE) X(UMTX_OP_MUTEX_WAKE2)
677 X(UMTX_OP_SEM2_WAIT) X(UMTX_OP_SEM2_WAKE)
678 XEND
681 static struct xlat at_flags[] = {
682 X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW)
683 X(AT_REMOVEDIR) XEND
686 static struct xlat access_modes[] = {
687 X(R_OK) X(W_OK) X(X_OK) XEND
690 static struct xlat sysarch_ops[] = {
691 #if defined(__i386__) || defined(__amd64__)
692 X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM)
693 X(I386_VM86) X(I386_GET_FSBASE) X(I386_SET_FSBASE) X(I386_GET_GSBASE)
694 X(I386_SET_GSBASE) X(I386_GET_XFPUSTATE) X(AMD64_GET_FSBASE)
695 X(AMD64_SET_FSBASE) X(AMD64_GET_GSBASE) X(AMD64_SET_GSBASE)
696 X(AMD64_GET_XFPUSTATE)
697 #endif
698 XEND
701 static struct xlat linux_socketcall_ops[] = {
702 X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
703 X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
704 X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
705 X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
706 X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
707 XEND
710 static struct xlat sigprocmask_ops[] = {
711 X(SIG_BLOCK) X(SIG_UNBLOCK) X(SIG_SETMASK)
712 XEND
715 #undef X
716 #define X(a) { CLOUDABI_##a, #a },
718 static struct xlat cloudabi_advice[] = {
719 X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
720 X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
721 XEND
724 static struct xlat cloudabi_clockid[] = {
725 X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
726 X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
727 XEND
730 static struct xlat cloudabi_errno[] = {
731 X(E2BIG) X(EACCES) X(EADDRINUSE) X(EADDRNOTAVAIL)
732 X(EAFNOSUPPORT) X(EAGAIN) X(EALREADY) X(EBADF) X(EBADMSG)
733 X(EBUSY) X(ECANCELED) X(ECHILD) X(ECONNABORTED) X(ECONNREFUSED)
734 X(ECONNRESET) X(EDEADLK) X(EDESTADDRREQ) X(EDOM) X(EDQUOT)
735 X(EEXIST) X(EFAULT) X(EFBIG) X(EHOSTUNREACH) X(EIDRM) X(EILSEQ)
736 X(EINPROGRESS) X(EINTR) X(EINVAL) X(EIO) X(EISCONN) X(EISDIR)
737 X(ELOOP) X(EMFILE) X(EMLINK) X(EMSGSIZE) X(EMULTIHOP)
738 X(ENAMETOOLONG) X(ENETDOWN) X(ENETRESET) X(ENETUNREACH)
739 X(ENFILE) X(ENOBUFS) X(ENODEV) X(ENOENT) X(ENOEXEC) X(ENOLCK)
740 X(ENOLINK) X(ENOMEM) X(ENOMSG) X(ENOPROTOOPT) X(ENOSPC)
741 X(ENOSYS) X(ENOTCONN) X(ENOTDIR) X(ENOTEMPTY) X(ENOTRECOVERABLE)
742 X(ENOTSOCK) X(ENOTSUP) X(ENOTTY) X(ENXIO) X(EOVERFLOW)
743 X(EOWNERDEAD) X(EPERM) X(EPIPE) X(EPROTO) X(EPROTONOSUPPORT)
744 X(EPROTOTYPE) X(ERANGE) X(EROFS) X(ESPIPE) X(ESRCH) X(ESTALE)
745 X(ETIMEDOUT) X(ETXTBSY) X(EXDEV) X(ENOTCAPABLE)
746 XEND
749 static struct xlat cloudabi_fdflags[] = {
750 X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
751 X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
752 XEND
755 static struct xlat cloudabi_fdsflags[] = {
756 X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
757 XEND
760 static struct xlat cloudabi_filetype[] = {
761 X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
762 X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
763 X(FILETYPE_FIFO) X(FILETYPE_POLL) X(FILETYPE_PROCESS)
764 X(FILETYPE_REGULAR_FILE) X(FILETYPE_SHARED_MEMORY)
765 X(FILETYPE_SOCKET_DGRAM) X(FILETYPE_SOCKET_SEQPACKET)
766 X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK)
767 XEND
770 static struct xlat cloudabi_fsflags[] = {
771 X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
772 X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
773 XEND
776 static struct xlat cloudabi_mflags[] = {
777 X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
778 XEND
781 static struct xlat cloudabi_mprot[] = {
782 X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
783 XEND
786 static struct xlat cloudabi_msflags[] = {
787 X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
788 XEND
791 static struct xlat cloudabi_oflags[] = {
792 X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
793 XEND
796 static struct xlat cloudabi_sa_family[] = {
797 X(AF_UNSPEC) X(AF_INET) X(AF_INET6) X(AF_UNIX)
798 XEND
801 static struct xlat cloudabi_sdflags[] = {
802 X(SHUT_RD) X(SHUT_WR)
803 XEND
806 static struct xlat cloudabi_signal[] = {
807 X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
808 X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
809 X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
810 X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
811 X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
812 XEND
815 static struct xlat cloudabi_ssflags[] = {
816 X(SOCKSTAT_CLEAR_ERROR)
817 XEND
820 static struct xlat cloudabi_ssstate[] = {
821 X(SOCKSTAT_ACCEPTCONN)
822 XEND
825 static struct xlat cloudabi_ulflags[] = {
826 X(UNLINK_REMOVEDIR)
827 XEND
830 static struct xlat cloudabi_whence[] = {
831 X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
832 XEND
835 #undef X
836 #undef XEND
839 * Searches an xlat array for a value, and returns it if found. Otherwise
840 * return a string representation.
842 static const char *
843 lookup(struct xlat *xlat, int val, int base)
845 static char tmp[16];
847 for (; xlat->str != NULL; xlat++)
848 if (xlat->val == val)
849 return (xlat->str);
850 switch (base) {
851 case 8:
852 sprintf(tmp, "0%o", val);
853 break;
854 case 16:
855 sprintf(tmp, "0x%x", val);
856 break;
857 case 10:
858 sprintf(tmp, "%u", val);
859 break;
860 default:
861 errx(1,"Unknown lookup base");
862 break;
864 return (tmp);
867 static const char *
868 xlookup(struct xlat *xlat, int val)
871 return (lookup(xlat, val, 16));
875 * Searches an xlat array containing bitfield values. Remaining bits
876 * set after removing the known ones are printed at the end:
877 * IN|0x400.
879 static char *
880 xlookup_bits(struct xlat *xlat, int val)
882 int len, rem;
883 static char str[512];
885 len = 0;
886 rem = val;
887 for (; xlat->str != NULL; xlat++) {
888 if ((xlat->val & rem) == xlat->val) {
890 * Don't print the "all-bits-zero" string unless all
891 * bits are really zero.
893 if (xlat->val == 0 && val != 0)
894 continue;
895 len += sprintf(str + len, "%s|", xlat->str);
896 rem &= ~(xlat->val);
901 * If we have leftover bits or didn't match anything, print
902 * the remainder.
904 if (rem || len == 0)
905 len += sprintf(str + len, "0x%x", rem);
906 if (len && str[len - 1] == '|')
907 len--;
908 str[len] = 0;
909 return (str);
912 void
913 init_syscalls(void)
915 struct syscall *sc;
917 STAILQ_INIT(&syscalls);
918 for (sc = decoded_syscalls; sc->name != NULL; sc++)
919 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
922 * If/when the list gets big, it might be desirable to do it
923 * as a hash table or binary search.
925 struct syscall *
926 get_syscall(const char *name, int nargs)
928 struct syscall *sc;
929 int i;
931 if (name == NULL)
932 return (NULL);
933 STAILQ_FOREACH(sc, &syscalls, entries)
934 if (strcmp(name, sc->name) == 0)
935 return (sc);
937 /* It is unknown. Add it into the list. */
938 #if DEBUG
939 fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
940 nargs);
941 #endif
943 sc = calloc(1, sizeof(struct syscall));
944 sc->name = strdup(name);
945 sc->ret_type = 1;
946 sc->nargs = nargs;
947 for (i = 0; i < nargs; i++) {
948 sc->args[i].offset = i;
949 /* Treat all unknown arguments as LongHex. */
950 sc->args[i].type = LongHex;
952 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
954 return (sc);
958 * Copy a fixed amount of bytes from the process.
960 static int
961 get_struct(pid_t pid, void *offset, void *buf, int len)
963 struct ptrace_io_desc iorequest;
965 iorequest.piod_op = PIOD_READ_D;
966 iorequest.piod_offs = offset;
967 iorequest.piod_addr = buf;
968 iorequest.piod_len = len;
969 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
970 return (-1);
971 return (0);
974 #define MAXSIZE 4096
977 * Copy a string from the process. Note that it is
978 * expected to be a C string, but if max is set, it will
979 * only get that much.
981 static char *
982 get_string(pid_t pid, void *addr, int max)
984 struct ptrace_io_desc iorequest;
985 char *buf, *nbuf;
986 size_t offset, size, totalsize;
988 offset = 0;
989 if (max)
990 size = max + 1;
991 else {
992 /* Read up to the end of the current page. */
993 size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE);
994 if (size > MAXSIZE)
995 size = MAXSIZE;
997 totalsize = size;
998 buf = malloc(totalsize);
999 if (buf == NULL)
1000 return (NULL);
1001 for (;;) {
1002 iorequest.piod_op = PIOD_READ_D;
1003 iorequest.piod_offs = (char *)addr + offset;
1004 iorequest.piod_addr = buf + offset;
1005 iorequest.piod_len = size;
1006 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
1007 free(buf);
1008 return (NULL);
1010 if (memchr(buf + offset, '\0', size) != NULL)
1011 return (buf);
1012 offset += size;
1013 if (totalsize < MAXSIZE && max == 0) {
1014 size = MAXSIZE - totalsize;
1015 if (size > PAGE_SIZE)
1016 size = PAGE_SIZE;
1017 nbuf = realloc(buf, totalsize + size);
1018 if (nbuf == NULL) {
1019 buf[totalsize - 1] = '\0';
1020 return (buf);
1022 buf = nbuf;
1023 totalsize += size;
1024 } else {
1025 buf[totalsize - 1] = '\0';
1026 return (buf);
1031 static char *
1032 strsig2(int sig)
1034 static char tmp[sizeof(int) * 3 + 1];
1035 char *ret;
1037 ret = strsig(sig);
1038 if (ret == NULL) {
1039 snprintf(tmp, sizeof(tmp), "%d", sig);
1040 ret = tmp;
1042 return (ret);
1045 static void
1046 print_kevent(FILE *fp, struct kevent *ke, int input)
1049 switch (ke->filter) {
1050 case EVFILT_READ:
1051 case EVFILT_WRITE:
1052 case EVFILT_VNODE:
1053 case EVFILT_PROC:
1054 case EVFILT_TIMER:
1055 case EVFILT_PROCDESC:
1056 fprintf(fp, "%ju", (uintmax_t)ke->ident);
1057 break;
1058 case EVFILT_SIGNAL:
1059 fputs(strsig2(ke->ident), fp);
1060 break;
1061 default:
1062 fprintf(fp, "%p", (void *)ke->ident);
1064 fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter),
1065 xlookup_bits(kevent_flags, ke->flags));
1066 switch (ke->filter) {
1067 case EVFILT_READ:
1068 case EVFILT_WRITE:
1069 fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp);
1070 break;
1071 case EVFILT_VNODE:
1072 fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp);
1073 break;
1074 case EVFILT_PROC:
1075 case EVFILT_PROCDESC:
1076 fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp);
1077 break;
1078 case EVFILT_TIMER:
1079 fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp);
1080 break;
1081 case EVFILT_USER: {
1082 int ctrl, data;
1084 ctrl = ke->fflags & NOTE_FFCTRLMASK;
1085 data = ke->fflags & NOTE_FFLAGSMASK;
1086 if (input) {
1087 fputs(xlookup(kevent_user_ffctrl, ctrl), fp);
1088 if (ke->fflags & NOTE_TRIGGER)
1089 fputs("|NOTE_TRIGGER", fp);
1090 if (data != 0)
1091 fprintf(fp, "|%#x", data);
1092 } else {
1093 fprintf(fp, "%#x", data);
1095 break;
1097 default:
1098 fprintf(fp, "%#x", ke->fflags);
1100 fprintf(fp, ",%p,%p", (void *)ke->data, (void *)ke->udata);
1103 static void
1104 print_utrace(FILE *fp, void *utrace_addr, size_t len)
1106 unsigned char *utrace_buffer;
1108 fprintf(fp, "{ ");
1109 if (sysdecode_utrace(fp, utrace_addr, len)) {
1110 fprintf(fp, " }");
1111 return;
1114 utrace_buffer = utrace_addr;
1115 fprintf(fp, "%zu:", len);
1116 while (len--)
1117 fprintf(fp, " %02x", *utrace_buffer++);
1118 fprintf(fp, " }");
1122 * Converts a syscall argument into a string. Said string is
1123 * allocated via malloc(), so needs to be free()'d. sc is
1124 * a pointer to the syscall description (see above); args is
1125 * an array of all of the system call arguments.
1127 char *
1128 print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
1129 struct trussinfo *trussinfo)
1131 FILE *fp;
1132 char *tmp;
1133 size_t tmplen;
1134 pid_t pid;
1136 fp = open_memstream(&tmp, &tmplen);
1137 pid = trussinfo->curthread->proc->pid;
1138 switch (sc->type & ARG_MASK) {
1139 case Hex:
1140 fprintf(fp, "0x%x", (int)args[sc->offset]);
1141 break;
1142 case Octal:
1143 fprintf(fp, "0%o", (int)args[sc->offset]);
1144 break;
1145 case Int:
1146 fprintf(fp, "%d", (int)args[sc->offset]);
1147 break;
1148 case UInt:
1149 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1150 break;
1151 case LongHex:
1152 fprintf(fp, "0x%lx", args[sc->offset]);
1153 break;
1154 case Long:
1155 fprintf(fp, "%ld", args[sc->offset]);
1156 break;
1157 case Name: {
1158 /* NULL-terminated string. */
1159 char *tmp2;
1161 tmp2 = get_string(pid, (void*)args[sc->offset], 0);
1162 fprintf(fp, "\"%s\"", tmp2);
1163 free(tmp2);
1164 break;
1166 case BinString: {
1168 * Binary block of data that might have printable characters.
1169 * XXX If type|OUT, assume that the length is the syscall's
1170 * return value. Otherwise, assume that the length of the block
1171 * is in the next syscall argument.
1173 int max_string = trussinfo->strsize;
1174 char tmp2[max_string + 1], *tmp3;
1175 int len;
1176 int truncated = 0;
1178 if (sc->type & OUT)
1179 len = retval[0];
1180 else
1181 len = args[sc->offset + 1];
1184 * Don't print more than max_string characters, to avoid word
1185 * wrap. If we have to truncate put some ... after the string.
1187 if (len > max_string) {
1188 len = max_string;
1189 truncated = 1;
1191 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
1192 != -1) {
1193 tmp3 = malloc(len * 4 + 1);
1194 while (len) {
1195 if (strvisx(tmp3, tmp2, len,
1196 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1197 break;
1198 len--;
1199 truncated = 1;
1201 fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1202 "..." : "");
1203 free(tmp3);
1204 } else {
1205 fprintf(fp, "0x%lx", args[sc->offset]);
1207 break;
1209 case ExecArgs:
1210 case ExecEnv:
1211 case StringArray: {
1212 uintptr_t addr;
1213 union {
1214 char *strarray[0];
1215 char buf[PAGE_SIZE];
1216 } u;
1217 char *string;
1218 size_t len;
1219 u_int first, i;
1222 * Only parse argv[] and environment arrays from exec calls
1223 * if requested.
1225 if (((sc->type & ARG_MASK) == ExecArgs &&
1226 (trussinfo->flags & EXECVEARGS) == 0) ||
1227 ((sc->type & ARG_MASK) == ExecEnv &&
1228 (trussinfo->flags & EXECVEENVS) == 0)) {
1229 fprintf(fp, "0x%lx", args[sc->offset]);
1230 break;
1234 * Read a page of pointers at a time. Punt if the top-level
1235 * pointer is not aligned. Note that the first read is of
1236 * a partial page.
1238 addr = args[sc->offset];
1239 if (addr % sizeof(char *) != 0) {
1240 fprintf(fp, "0x%lx", args[sc->offset]);
1241 break;
1244 len = PAGE_SIZE - (addr & PAGE_MASK);
1245 if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
1246 fprintf(fp, "0x%lx", args[sc->offset]);
1247 break;
1250 fputc('[', fp);
1251 first = 1;
1252 i = 0;
1253 while (u.strarray[i] != NULL) {
1254 string = get_string(pid, u.strarray[i], 0);
1255 fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1256 free(string);
1257 first = 0;
1259 i++;
1260 if (i == len / sizeof(char *)) {
1261 addr += len;
1262 len = PAGE_SIZE;
1263 if (get_struct(pid, (void *)addr, u.buf, len) ==
1264 -1) {
1265 fprintf(fp, ", <inval>");
1266 break;
1268 i = 0;
1271 fputs(" ]", fp);
1272 break;
1274 #ifdef __LP64__
1275 case Quad:
1276 fprintf(fp, "%ld", args[sc->offset]);
1277 break;
1278 case QuadHex:
1279 fprintf(fp, "0x%lx", args[sc->offset]);
1280 break;
1281 #else
1282 case Quad:
1283 case QuadHex: {
1284 unsigned long long ll;
1286 #if _BYTE_ORDER == _LITTLE_ENDIAN
1287 ll = (unsigned long long)args[sc->offset + 1] << 32 |
1288 args[sc->offset];
1289 #else
1290 ll = (unsigned long long)args[sc->offset] << 32 |
1291 args[sc->offset + 1];
1292 #endif
1293 if ((sc->type & ARG_MASK) == Quad)
1294 fprintf(fp, "%lld", ll);
1295 else
1296 fprintf(fp, "0x%llx", ll);
1297 break;
1299 #endif
1300 case Ptr:
1301 fprintf(fp, "0x%lx", args[sc->offset]);
1302 break;
1303 case Readlinkres: {
1304 char *tmp2;
1306 if (retval[0] == -1)
1307 break;
1308 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
1309 fprintf(fp, "\"%s\"", tmp2);
1310 free(tmp2);
1311 break;
1313 case Ioctl: {
1314 const char *temp;
1315 unsigned long cmd;
1317 cmd = args[sc->offset];
1318 temp = sysdecode_ioctlname(cmd);
1319 if (temp)
1320 fputs(temp, fp);
1321 else {
1322 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1323 cmd, cmd & IOC_OUT ? "R" : "",
1324 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1325 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1326 cmd & 0xFF, IOCPARM_LEN(cmd));
1328 break;
1330 case Timespec: {
1331 struct timespec ts;
1333 if (get_struct(pid, (void *)args[sc->offset], &ts,
1334 sizeof(ts)) != -1)
1335 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1336 ts.tv_nsec);
1337 else
1338 fprintf(fp, "0x%lx", args[sc->offset]);
1339 break;
1341 case Timespec2: {
1342 struct timespec ts[2];
1343 const char *sep;
1344 unsigned int i;
1346 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
1347 != -1) {
1348 fputs("{ ", fp);
1349 sep = "";
1350 for (i = 0; i < nitems(ts); i++) {
1351 fputs(sep, fp);
1352 sep = ", ";
1353 switch (ts[i].tv_nsec) {
1354 case UTIME_NOW:
1355 fprintf(fp, "UTIME_NOW");
1356 break;
1357 case UTIME_OMIT:
1358 fprintf(fp, "UTIME_OMIT");
1359 break;
1360 default:
1361 fprintf(fp, "%jd.%09ld",
1362 (intmax_t)ts[i].tv_sec,
1363 ts[i].tv_nsec);
1364 break;
1367 fputs(" }", fp);
1368 } else
1369 fprintf(fp, "0x%lx", args[sc->offset]);
1370 break;
1372 case Timeval: {
1373 struct timeval tv;
1375 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1376 != -1)
1377 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1378 tv.tv_usec);
1379 else
1380 fprintf(fp, "0x%lx", args[sc->offset]);
1381 break;
1383 case Timeval2: {
1384 struct timeval tv[2];
1386 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1387 != -1)
1388 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1389 (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1390 (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1391 else
1392 fprintf(fp, "0x%lx", args[sc->offset]);
1393 break;
1395 case Itimerval: {
1396 struct itimerval itv;
1398 if (get_struct(pid, (void *)args[sc->offset], &itv,
1399 sizeof(itv)) != -1)
1400 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1401 (intmax_t)itv.it_interval.tv_sec,
1402 itv.it_interval.tv_usec,
1403 (intmax_t)itv.it_value.tv_sec,
1404 itv.it_value.tv_usec);
1405 else
1406 fprintf(fp, "0x%lx", args[sc->offset]);
1407 break;
1409 case LinuxSockArgs:
1411 struct linux_socketcall_args largs;
1413 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
1414 sizeof(largs)) != -1)
1415 fprintf(fp, "{ %s, 0x%lx }",
1416 lookup(linux_socketcall_ops, largs.what, 10),
1417 (long unsigned int)largs.args);
1418 else
1419 fprintf(fp, "0x%lx", args[sc->offset]);
1420 break;
1422 case Pollfd: {
1424 * XXX: A Pollfd argument expects the /next/ syscall argument
1425 * to be the number of fds in the array. This matches the poll
1426 * syscall.
1428 struct pollfd *pfd;
1429 int numfds = args[sc->offset + 1];
1430 size_t bytes = sizeof(struct pollfd) * numfds;
1431 int i;
1433 if ((pfd = malloc(bytes)) == NULL)
1434 err(1, "Cannot malloc %zu bytes for pollfd array",
1435 bytes);
1436 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
1437 != -1) {
1438 fputs("{", fp);
1439 for (i = 0; i < numfds; i++) {
1440 fprintf(fp, " %d/%s", pfd[i].fd,
1441 xlookup_bits(poll_flags, pfd[i].events));
1443 fputs(" }", fp);
1444 } else {
1445 fprintf(fp, "0x%lx", args[sc->offset]);
1447 free(pfd);
1448 break;
1450 case Fd_set: {
1452 * XXX: A Fd_set argument expects the /first/ syscall argument
1453 * to be the number of fds in the array. This matches the
1454 * select syscall.
1456 fd_set *fds;
1457 int numfds = args[0];
1458 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1459 int i;
1461 if ((fds = malloc(bytes)) == NULL)
1462 err(1, "Cannot malloc %zu bytes for fd_set array",
1463 bytes);
1464 if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
1465 != -1) {
1466 fputs("{", fp);
1467 for (i = 0; i < numfds; i++) {
1468 if (FD_ISSET(i, fds))
1469 fprintf(fp, " %d", i);
1471 fputs(" }", fp);
1472 } else
1473 fprintf(fp, "0x%lx", args[sc->offset]);
1474 free(fds);
1475 break;
1477 case Signal:
1478 fputs(strsig2(args[sc->offset]), fp);
1479 break;
1480 case Sigset: {
1481 long sig;
1482 sigset_t ss;
1483 int i, first;
1485 sig = args[sc->offset];
1486 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
1487 sizeof(ss)) == -1) {
1488 fprintf(fp, "0x%lx", args[sc->offset]);
1489 break;
1491 fputs("{ ", fp);
1492 first = 1;
1493 for (i = 1; i < sys_nsig; i++) {
1494 if (sigismember(&ss, i)) {
1495 fprintf(fp, "%s%s", !first ? "|" : "",
1496 strsig(i));
1497 first = 0;
1500 if (!first)
1501 fputc(' ', fp);
1502 fputc('}', fp);
1503 break;
1505 case Sigprocmask: {
1506 fputs(xlookup(sigprocmask_ops, args[sc->offset]), fp);
1507 break;
1509 case Fcntlflag: {
1510 /* XXX: Output depends on the value of the previous argument. */
1511 switch (args[sc->offset - 1]) {
1512 case F_SETFD:
1513 fputs(xlookup_bits(fcntlfd_arg, args[sc->offset]), fp);
1514 break;
1515 case F_SETFL:
1516 fputs(xlookup_bits(fcntlfl_arg, args[sc->offset]), fp);
1517 break;
1518 case F_GETFD:
1519 case F_GETFL:
1520 case F_GETOWN:
1521 break;
1522 default:
1523 fprintf(fp, "0x%lx", args[sc->offset]);
1524 break;
1526 break;
1528 case Open:
1529 fputs(xlookup_bits(open_flags, args[sc->offset]), fp);
1530 break;
1531 case Fcntl:
1532 fputs(xlookup(fcntl_arg, args[sc->offset]), fp);
1533 break;
1534 case Mprot:
1535 fputs(xlookup_bits(mprot_flags, args[sc->offset]), fp);
1536 break;
1537 case Mmapflags: {
1538 int align, flags;
1541 * MAP_ALIGNED can't be handled by xlookup_bits(), so
1542 * generate that string manually and prepend it to the
1543 * string from xlookup_bits(). Have to be careful to
1544 * avoid outputting MAP_ALIGNED|0 if MAP_ALIGNED is
1545 * the only flag.
1547 flags = args[sc->offset] & ~MAP_ALIGNMENT_MASK;
1548 align = args[sc->offset] & MAP_ALIGNMENT_MASK;
1549 if (align != 0) {
1550 if (align == MAP_ALIGNED_SUPER)
1551 fputs("MAP_ALIGNED_SUPER", fp);
1552 else
1553 fprintf(fp, "MAP_ALIGNED(%d)",
1554 align >> MAP_ALIGNMENT_SHIFT);
1555 if (flags == 0)
1556 break;
1557 fputc('|', fp);
1559 fputs(xlookup_bits(mmap_flags, flags), fp);
1560 break;
1562 case Whence:
1563 fputs(xlookup(whence_arg, args[sc->offset]), fp);
1564 break;
1565 case Sockdomain:
1566 fputs(xlookup(sockdomain_arg, args[sc->offset]), fp);
1567 break;
1568 case Socktype: {
1569 int type, flags;
1571 flags = args[sc->offset] & (SOCK_CLOEXEC | SOCK_NONBLOCK);
1572 type = args[sc->offset] & ~flags;
1573 fputs(xlookup(socktype_arg, type), fp);
1574 if (flags & SOCK_CLOEXEC)
1575 fprintf(fp, "|SOCK_CLOEXEC");
1576 if (flags & SOCK_NONBLOCK)
1577 fprintf(fp, "|SOCK_NONBLOCK");
1578 break;
1580 case Shutdown:
1581 fputs(xlookup(shutdown_arg, args[sc->offset]), fp);
1582 break;
1583 case Resource:
1584 fputs(xlookup(resource_arg, args[sc->offset]), fp);
1585 break;
1586 case Pathconf:
1587 fputs(xlookup(pathconf_arg, args[sc->offset]), fp);
1588 break;
1589 case Rforkflags:
1590 fputs(xlookup_bits(rfork_flags, args[sc->offset]), fp);
1591 break;
1592 case Sockaddr: {
1593 char addr[64];
1594 struct sockaddr_in *lsin;
1595 struct sockaddr_in6 *lsin6;
1596 struct sockaddr_un *sun;
1597 struct sockaddr *sa;
1598 socklen_t len;
1599 u_char *q;
1601 if (args[sc->offset] == 0) {
1602 fputs("NULL", fp);
1603 break;
1607 * Extract the address length from the next argument. If
1608 * this is an output sockaddr (OUT is set), then the
1609 * next argument is a pointer to a socklen_t. Otherwise
1610 * the next argument contains a socklen_t by value.
1612 if (sc->type & OUT) {
1613 if (get_struct(pid, (void *)args[sc->offset + 1],
1614 &len, sizeof(len)) == -1) {
1615 fprintf(fp, "0x%lx", args[sc->offset]);
1616 break;
1618 } else
1619 len = args[sc->offset + 1];
1621 /* If the length is too small, just bail. */
1622 if (len < sizeof(*sa)) {
1623 fprintf(fp, "0x%lx", args[sc->offset]);
1624 break;
1627 sa = calloc(1, len);
1628 if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) {
1629 free(sa);
1630 fprintf(fp, "0x%lx", args[sc->offset]);
1631 break;
1634 switch (sa->sa_family) {
1635 case AF_INET:
1636 if (len < sizeof(*lsin))
1637 goto sockaddr_short;
1638 lsin = (struct sockaddr_in *)(void *)sa;
1639 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1640 fprintf(fp, "{ AF_INET %s:%d }", addr,
1641 htons(lsin->sin_port));
1642 break;
1643 case AF_INET6:
1644 if (len < sizeof(*lsin6))
1645 goto sockaddr_short;
1646 lsin6 = (struct sockaddr_in6 *)(void *)sa;
1647 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1648 sizeof(addr));
1649 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1650 htons(lsin6->sin6_port));
1651 break;
1652 case AF_UNIX:
1653 sun = (struct sockaddr_un *)sa;
1654 fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1655 (int)(len - offsetof(struct sockaddr_un, sun_path)),
1656 sun->sun_path);
1657 break;
1658 default:
1659 sockaddr_short:
1660 fprintf(fp,
1661 "{ sa_len = %d, sa_family = %d, sa_data = {",
1662 (int)sa->sa_len, (int)sa->sa_family);
1663 for (q = (u_char *)sa->sa_data;
1664 q < (u_char *)sa + len; q++)
1665 fprintf(fp, "%s 0x%02x",
1666 q == (u_char *)sa->sa_data ? "" : ",",
1667 *q);
1668 fputs(" } }", fp);
1670 free(sa);
1671 break;
1673 case Sigaction: {
1674 struct sigaction sa;
1676 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
1677 != -1) {
1678 fputs("{ ", fp);
1679 if (sa.sa_handler == SIG_DFL)
1680 fputs("SIG_DFL", fp);
1681 else if (sa.sa_handler == SIG_IGN)
1682 fputs("SIG_IGN", fp);
1683 else
1684 fprintf(fp, "%p", sa.sa_handler);
1685 fprintf(fp, " %s ss_t }",
1686 xlookup_bits(sigaction_flags, sa.sa_flags));
1687 } else
1688 fprintf(fp, "0x%lx", args[sc->offset]);
1689 break;
1691 case Kevent: {
1693 * XXX XXX: The size of the array is determined by either the
1694 * next syscall argument, or by the syscall return value,
1695 * depending on which argument number we are. This matches the
1696 * kevent syscall, but luckily that's the only syscall that uses
1697 * them.
1699 struct kevent *ke;
1700 int numevents = -1;
1701 size_t bytes;
1702 int i;
1704 if (sc->offset == 1)
1705 numevents = args[sc->offset+1];
1706 else if (sc->offset == 3 && retval[0] != -1)
1707 numevents = retval[0];
1709 if (numevents >= 0) {
1710 bytes = sizeof(struct kevent) * numevents;
1711 if ((ke = malloc(bytes)) == NULL)
1712 err(1,
1713 "Cannot malloc %zu bytes for kevent array",
1714 bytes);
1715 } else
1716 ke = NULL;
1717 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
1718 ke, bytes) != -1) {
1719 fputc('{', fp);
1720 for (i = 0; i < numevents; i++) {
1721 fputc(' ', fp);
1722 print_kevent(fp, &ke[i], sc->offset == 1);
1724 fputs(" }", fp);
1725 } else {
1726 fprintf(fp, "0x%lx", args[sc->offset]);
1728 free(ke);
1729 break;
1731 case Stat: {
1732 struct stat st;
1734 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1735 != -1) {
1736 char mode[12];
1738 strmode(st.st_mode, mode);
1739 fprintf(fp,
1740 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1741 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1742 (long)st.st_blksize);
1743 } else {
1744 fprintf(fp, "0x%lx", args[sc->offset]);
1746 break;
1748 case StatFs: {
1749 unsigned int i;
1750 struct statfs buf;
1752 if (get_struct(pid, (void *)args[sc->offset], &buf,
1753 sizeof(buf)) != -1) {
1754 char fsid[17];
1756 bzero(fsid, sizeof(fsid));
1757 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
1758 for (i = 0; i < sizeof(buf.f_fsid); i++)
1759 snprintf(&fsid[i*2],
1760 sizeof(fsid) - (i*2), "%02x",
1761 ((u_char *)&buf.f_fsid)[i]);
1763 fprintf(fp,
1764 "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
1765 "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
1766 buf.f_mntfromname, fsid);
1767 } else
1768 fprintf(fp, "0x%lx", args[sc->offset]);
1769 break;
1772 case Rusage: {
1773 struct rusage ru;
1775 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
1776 != -1) {
1777 fprintf(fp,
1778 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
1779 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
1780 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
1781 ru.ru_inblock, ru.ru_oublock);
1782 } else
1783 fprintf(fp, "0x%lx", args[sc->offset]);
1784 break;
1786 case Rlimit: {
1787 struct rlimit rl;
1789 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
1790 != -1) {
1791 fprintf(fp, "{ cur=%ju,max=%ju }",
1792 rl.rlim_cur, rl.rlim_max);
1793 } else
1794 fprintf(fp, "0x%lx", args[sc->offset]);
1795 break;
1797 case ExitStatus: {
1798 int status;
1800 if (get_struct(pid, (void *)args[sc->offset], &status,
1801 sizeof(status)) != -1) {
1802 fputs("{ ", fp);
1803 if (WIFCONTINUED(status))
1804 fputs("CONTINUED", fp);
1805 else if (WIFEXITED(status))
1806 fprintf(fp, "EXITED,val=%d",
1807 WEXITSTATUS(status));
1808 else if (WIFSIGNALED(status))
1809 fprintf(fp, "SIGNALED,sig=%s%s",
1810 strsig2(WTERMSIG(status)),
1811 WCOREDUMP(status) ? ",cored" : "");
1812 else
1813 fprintf(fp, "STOPPED,sig=%s",
1814 strsig2(WTERMSIG(status)));
1815 fputs(" }", fp);
1816 } else
1817 fprintf(fp, "0x%lx", args[sc->offset]);
1818 break;
1820 case Waitoptions:
1821 fputs(xlookup_bits(wait_options, args[sc->offset]), fp);
1822 break;
1823 case Idtype:
1824 fputs(xlookup(idtype_arg, args[sc->offset]), fp);
1825 break;
1826 case Procctl:
1827 fputs(xlookup(procctl_arg, args[sc->offset]), fp);
1828 break;
1829 case Umtxop:
1830 fputs(xlookup(umtx_ops, args[sc->offset]), fp);
1831 break;
1832 case Atfd:
1833 if ((int)args[sc->offset] == AT_FDCWD)
1834 fputs("AT_FDCWD", fp);
1835 else
1836 fprintf(fp, "%d", (int)args[sc->offset]);
1837 break;
1838 case Atflags:
1839 fputs(xlookup_bits(at_flags, args[sc->offset]), fp);
1840 break;
1841 case Accessmode:
1842 if (args[sc->offset] == F_OK)
1843 fputs("F_OK", fp);
1844 else
1845 fputs(xlookup_bits(access_modes, args[sc->offset]), fp);
1846 break;
1847 case Sysarch:
1848 fputs(xlookup(sysarch_ops, args[sc->offset]), fp);
1849 break;
1850 case PipeFds:
1852 * The pipe() system call in the kernel returns its
1853 * two file descriptors via return values. However,
1854 * the interface exposed by libc is that pipe()
1855 * accepts a pointer to an array of descriptors.
1856 * Format the output to match the libc API by printing
1857 * the returned file descriptors as a fake argument.
1859 * Overwrite the first retval to signal a successful
1860 * return as well.
1862 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
1863 retval[0] = 0;
1864 break;
1865 case Utrace: {
1866 size_t len;
1867 void *utrace_addr;
1869 len = args[sc->offset + 1];
1870 utrace_addr = calloc(1, len);
1871 if (get_struct(pid, (void *)args[sc->offset],
1872 (void *)utrace_addr, len) != -1)
1873 print_utrace(fp, utrace_addr, len);
1874 else
1875 fprintf(fp, "0x%lx", args[sc->offset]);
1876 free(utrace_addr);
1877 break;
1879 case IntArray: {
1880 int descriptors[16];
1881 unsigned long i, ndescriptors;
1882 bool truncated;
1884 ndescriptors = args[sc->offset + 1];
1885 truncated = false;
1886 if (ndescriptors > nitems(descriptors)) {
1887 ndescriptors = nitems(descriptors);
1888 truncated = true;
1890 if (get_struct(pid, (void *)args[sc->offset],
1891 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
1892 fprintf(fp, "{");
1893 for (i = 0; i < ndescriptors; i++)
1894 fprintf(fp, i == 0 ? " %d" : ", %d",
1895 descriptors[i]);
1896 fprintf(fp, truncated ? ", ... }" : " }");
1897 } else
1898 fprintf(fp, "0x%lx", args[sc->offset]);
1899 break;
1902 case CloudABIAdvice:
1903 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
1904 break;
1905 case CloudABIClockID:
1906 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
1907 break;
1908 case ClouduABIFDSFlags:
1909 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
1910 break;
1911 case CloudABIFDStat: {
1912 cloudabi_fdstat_t fds;
1913 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds))
1914 != -1) {
1915 fprintf(fp, "{ %s, ",
1916 xlookup(cloudabi_filetype, fds.fs_filetype));
1917 fprintf(fp, "%s, ... }",
1918 xlookup_bits(cloudabi_fdflags, fds.fs_flags));
1919 } else
1920 fprintf(fp, "0x%lx", args[sc->offset]);
1921 break;
1923 case CloudABIFileStat: {
1924 cloudabi_filestat_t fsb;
1925 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb))
1926 != -1)
1927 fprintf(fp, "{ %s, %lu }",
1928 xlookup(cloudabi_filetype, fsb.st_filetype),
1929 fsb.st_size);
1930 else
1931 fprintf(fp, "0x%lx", args[sc->offset]);
1932 break;
1934 case CloudABIFileType:
1935 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
1936 break;
1937 case CloudABIFSFlags:
1938 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
1939 break;
1940 case CloudABILookup:
1941 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
1942 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
1943 (int)args[sc->offset]);
1944 else
1945 fprintf(fp, "%d", (int)args[sc->offset]);
1946 break;
1947 case CloudABIMFlags:
1948 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
1949 break;
1950 case CloudABIMProt:
1951 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
1952 break;
1953 case CloudABIMSFlags:
1954 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
1955 break;
1956 case CloudABIOFlags:
1957 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
1958 break;
1959 case CloudABISDFlags:
1960 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
1961 break;
1962 case CloudABISignal:
1963 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
1964 break;
1965 case CloudABISockStat: {
1966 cloudabi_sockstat_t ss;
1967 if (get_struct(pid, (void *)args[sc->offset], &ss, sizeof(ss))
1968 != -1) {
1969 fprintf(fp, "{ %s, ", xlookup(
1970 cloudabi_sa_family, ss.ss_sockname.sa_family));
1971 fprintf(fp, "%s, ", xlookup(
1972 cloudabi_sa_family, ss.ss_peername.sa_family));
1973 fprintf(fp, "%s, ", xlookup(
1974 cloudabi_errno, ss.ss_error));
1975 fprintf(fp, "%s }", xlookup_bits(
1976 cloudabi_ssstate, ss.ss_state));
1977 } else
1978 fprintf(fp, "0x%lx", args[sc->offset]);
1979 break;
1981 case CloudABISSFlags:
1982 fputs(xlookup_bits(cloudabi_ssflags, args[sc->offset]), fp);
1983 break;
1984 case CloudABITimestamp:
1985 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
1986 args[sc->offset] % 1000000000);
1987 break;
1988 case CloudABIULFlags:
1989 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
1990 break;
1991 case CloudABIWhence:
1992 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
1993 break;
1995 default:
1996 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
1998 fclose(fp);
1999 return (tmp);
2003 * Print (to outfile) the system call and its arguments.
2005 void
2006 print_syscall(struct trussinfo *trussinfo)
2008 struct threadinfo *t;
2009 const char *name;
2010 char **s_args;
2011 int i, len, nargs;
2013 t = trussinfo->curthread;
2015 name = t->cs.name;
2016 nargs = t->cs.nargs;
2017 s_args = t->cs.s_args;
2019 len = print_line_prefix(trussinfo);
2020 len += fprintf(trussinfo->outfile, "%s(", name);
2022 for (i = 0; i < nargs; i++) {
2023 if (s_args[i] != NULL)
2024 len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2025 else
2026 len += fprintf(trussinfo->outfile,
2027 "<missing argument>");
2028 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2029 "," : "");
2031 len += fprintf(trussinfo->outfile, ")");
2032 for (i = 0; i < 6 - (len / 8); i++)
2033 fprintf(trussinfo->outfile, "\t");
2036 void
2037 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
2039 struct timespec timediff;
2040 struct threadinfo *t;
2041 struct syscall *sc;
2042 int error;
2044 t = trussinfo->curthread;
2045 sc = t->cs.sc;
2046 if (trussinfo->flags & COUNTONLY) {
2047 timespecsubt(&t->after, &t->before, &timediff);
2048 timespecadd(&sc->time, &timediff, &sc->time);
2049 sc->ncalls++;
2050 if (errorp)
2051 sc->nerror++;
2052 return;
2055 print_syscall(trussinfo);
2056 fflush(trussinfo->outfile);
2057 if (errorp) {
2058 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi,
2059 retval[0]);
2060 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
2061 error == INT_MAX ? "Unknown error" : strerror(error));
2063 #ifndef __LP64__
2064 else if (sc->ret_type == 2) {
2065 off_t off;
2067 #if _BYTE_ORDER == _LITTLE_ENDIAN
2068 off = (off_t)retval[1] << 32 | retval[0];
2069 #else
2070 off = (off_t)retval[0] << 32 | retval[1];
2071 #endif
2072 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2073 (intmax_t)off);
2075 #endif
2076 else
2077 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
2078 retval[0]);
2081 void
2082 print_summary(struct trussinfo *trussinfo)
2084 struct timespec total = {0, 0};
2085 struct syscall *sc;
2086 int ncall, nerror;
2088 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2089 "syscall", "seconds", "calls", "errors");
2090 ncall = nerror = 0;
2091 STAILQ_FOREACH(sc, &syscalls, entries)
2092 if (sc->ncalls) {
2093 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2094 sc->name, (intmax_t)sc->time.tv_sec,
2095 sc->time.tv_nsec, sc->ncalls, sc->nerror);
2096 timespecadd(&total, &sc->time, &total);
2097 ncall += sc->ncalls;
2098 nerror += sc->nerror;
2100 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2101 "", "-------------", "-------", "-------");
2102 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2103 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);