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 <netinet/in.h>
52 #include <netinet/sctp.h>
53 #include <arpa/inet.h>
66 #include <sysdecode.h>
70 #include <contrib/cloudabi/cloudabi_types_common.h>
77 * This should probably be in its own file, sorted alphabetically.
79 static struct syscall decoded_syscalls[] = {
81 { .name = "__acl_aclcheck_fd", .ret_type = 1, .nargs = 3,
82 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
83 { .name = "__acl_aclcheck_file", .ret_type = 1, .nargs = 3,
84 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
85 { .name = "__acl_aclcheck_link", .ret_type = 1, .nargs = 3,
86 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
87 { .name = "__acl_delete_fd", .ret_type = 1, .nargs = 2,
88 .args = { { Int, 0 }, { Acltype, 1 } } },
89 { .name = "__acl_delete_file", .ret_type = 1, .nargs = 2,
90 .args = { { Name, 0 }, { Acltype, 1 } } },
91 { .name = "__acl_delete_link", .ret_type = 1, .nargs = 2,
92 .args = { { Name, 0 }, { Acltype, 1 } } },
93 { .name = "__acl_get_fd", .ret_type = 1, .nargs = 3,
94 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
95 { .name = "__acl_get_file", .ret_type = 1, .nargs = 3,
96 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
97 { .name = "__acl_get_link", .ret_type = 1, .nargs = 3,
98 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
99 { .name = "__acl_set_fd", .ret_type = 1, .nargs = 3,
100 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
101 { .name = "__acl_set_file", .ret_type = 1, .nargs = 3,
102 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
103 { .name = "__acl_set_link", .ret_type = 1, .nargs = 3,
104 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
105 { .name = "__cap_rights_get", .ret_type = 1, .nargs = 3,
106 .args = { { Int, 0 }, { Int, 1 }, { CapRights | OUT, 2 } } },
107 { .name = "__getcwd", .ret_type = 1, .nargs = 2,
108 .args = { { Name | OUT, 0 }, { Int, 1 } } },
109 { .name = "_umtx_op", .ret_type = 1, .nargs = 5,
110 .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
112 { .name = "accept", .ret_type = 1, .nargs = 3,
113 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
114 { .name = "access", .ret_type = 1, .nargs = 2,
115 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
116 { .name = "bind", .ret_type = 1, .nargs = 3,
117 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
118 { .name = "bindat", .ret_type = 1, .nargs = 4,
119 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
121 { .name = "break", .ret_type = 1, .nargs = 1,
122 .args = { { Ptr, 0 } } },
123 { .name = "cap_fcntls_get", .ret_type = 1, .nargs = 2,
124 .args = { { Int, 0 }, { CapFcntlRights | OUT, 1 } } },
125 { .name = "cap_fcntls_limit", .ret_type = 1, .nargs = 2,
126 .args = { { Int, 0 }, { CapFcntlRights, 1 } } },
127 { .name = "cap_getmode", .ret_type = 1, .nargs = 1,
128 .args = { { PUInt | OUT, 0 } } },
129 { .name = "cap_rights_limit", .ret_type = 1, .nargs = 2,
130 .args = { { Int, 0 }, { CapRights, 1 } } },
131 { .name = "chdir", .ret_type = 1, .nargs = 1,
132 .args = { { Name, 0 } } },
133 { .name = "chflags", .ret_type = 1, .nargs = 2,
134 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
135 { .name = "chflagsat", .ret_type = 1, .nargs = 4,
136 .args = { { Atfd, 0 }, { Name | IN, 1 }, { FileFlags, 2 },
138 { .name = "chmod", .ret_type = 1, .nargs = 2,
139 .args = { { Name, 0 }, { Octal, 1 } } },
140 { .name = "chown", .ret_type = 1, .nargs = 3,
141 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
142 { .name = "chroot", .ret_type = 1, .nargs = 1,
143 .args = { { Name, 0 } } },
144 { .name = "clock_gettime", .ret_type = 1, .nargs = 2,
145 .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
146 { .name = "close", .ret_type = 1, .nargs = 1,
147 .args = { { Int, 0 } } },
148 { .name = "connect", .ret_type = 1, .nargs = 3,
149 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
150 { .name = "connectat", .ret_type = 1, .nargs = 4,
151 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
153 { .name = "dup", .ret_type = 1, .nargs = 1,
154 .args = { { Int, 0 } } },
155 { .name = "dup2", .ret_type = 1, .nargs = 2,
156 .args = { { Int, 0 }, { Int, 1 } } },
157 { .name = "eaccess", .ret_type = 1, .nargs = 2,
158 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
159 { .name = "execve", .ret_type = 1, .nargs = 3,
160 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
161 { ExecEnv | IN, 2 } } },
162 { .name = "exit", .ret_type = 0, .nargs = 1,
163 .args = { { Hex, 0 } } },
164 { .name = "extattr_delete_fd", .ret_type = 1, .nargs = 3,
165 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
166 { .name = "extattr_delete_file", .ret_type = 1, .nargs = 3,
167 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
168 { .name = "extattr_delete_link", .ret_type = 1, .nargs = 3,
169 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
170 { .name = "extattr_get_fd", .ret_type = 1, .nargs = 5,
171 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
172 { BinString | OUT, 3 }, { Sizet, 4 } } },
173 { .name = "extattr_get_file", .ret_type = 1, .nargs = 5,
174 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
175 { BinString | OUT, 3 }, { Sizet, 4 } } },
176 { .name = "extattr_get_link", .ret_type = 1, .nargs = 5,
177 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
178 { BinString | OUT, 3 }, { Sizet, 4 } } },
179 { .name = "extattr_list_fd", .ret_type = 1, .nargs = 4,
180 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
182 { .name = "extattr_list_file", .ret_type = 1, .nargs = 4,
183 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
185 { .name = "extattr_list_link", .ret_type = 1, .nargs = 4,
186 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
188 { .name = "extattr_set_fd", .ret_type = 1, .nargs = 5,
189 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
190 { BinString | IN, 3 }, { Sizet, 4 } } },
191 { .name = "extattr_set_file", .ret_type = 1, .nargs = 5,
192 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
193 { BinString | IN, 3 }, { Sizet, 4 } } },
194 { .name = "extattr_set_link", .ret_type = 1, .nargs = 5,
195 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
196 { BinString | IN, 3 }, { Sizet, 4 } } },
197 { .name = "extattrctl", .ret_type = 1, .nargs = 5,
198 .args = { { Name, 0 }, { Hex, 1 }, { Name, 2 },
199 { Extattrnamespace, 3 }, { Name, 4 } } },
200 { .name = "faccessat", .ret_type = 1, .nargs = 4,
201 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
203 { .name = "fchflags", .ret_type = 1, .nargs = 2,
204 .args = { { Int, 0 }, { FileFlags, 1 } } },
205 { .name = "fchmod", .ret_type = 1, .nargs = 2,
206 .args = { { Int, 0 }, { Octal, 1 } } },
207 { .name = "fchmodat", .ret_type = 1, .nargs = 4,
208 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
209 { .name = "fchown", .ret_type = 1, .nargs = 3,
210 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
211 { .name = "fchownat", .ret_type = 1, .nargs = 5,
212 .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
214 { .name = "fcntl", .ret_type = 1, .nargs = 3,
215 .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
216 { .name = "flock", .ret_type = 1, .nargs = 2,
217 .args = { { Int, 0 }, { Flockop, 1 } } },
218 { .name = "fstat", .ret_type = 1, .nargs = 2,
219 .args = { { Int, 0 }, { Stat | OUT, 1 } } },
220 { .name = "fstatat", .ret_type = 1, .nargs = 4,
221 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
223 { .name = "fstatfs", .ret_type = 1, .nargs = 2,
224 .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
225 { .name = "ftruncate", .ret_type = 1, .nargs = 2,
226 .args = { { Int | IN, 0 }, { QuadHex | IN, 1 } } },
227 { .name = "futimens", .ret_type = 1, .nargs = 2,
228 .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
229 { .name = "futimes", .ret_type = 1, .nargs = 2,
230 .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
231 { .name = "futimesat", .ret_type = 1, .nargs = 3,
232 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
233 { .name = "getdirentries", .ret_type = 1, .nargs = 4,
234 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
235 { PQuadHex | OUT, 3 } } },
236 { .name = "getfsstat", .ret_type = 1, .nargs = 3,
237 .args = { { Ptr, 0 }, { Long, 1 }, { Getfsstatmode, 2 } } },
238 { .name = "getitimer", .ret_type = 1, .nargs = 2,
239 .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
240 { .name = "getpeername", .ret_type = 1, .nargs = 3,
241 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
242 { .name = "getpgid", .ret_type = 1, .nargs = 1,
243 .args = { { Int, 0 } } },
244 { .name = "getpriority", .ret_type = 1, .nargs = 2,
245 .args = { { Priowhich, 0 }, { Int, 1 } } },
246 { .name = "getrlimit", .ret_type = 1, .nargs = 2,
247 .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
248 { .name = "getrusage", .ret_type = 1, .nargs = 2,
249 .args = { { RusageWho, 0 }, { Rusage | OUT, 1 } } },
250 { .name = "getsid", .ret_type = 1, .nargs = 1,
251 .args = { { Int, 0 } } },
252 { .name = "getsockname", .ret_type = 1, .nargs = 3,
253 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
254 { .name = "getsockopt", .ret_type = 1, .nargs = 5,
255 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
256 { Ptr | OUT, 3 }, { Ptr | OUT, 4 } } },
257 { .name = "gettimeofday", .ret_type = 1, .nargs = 2,
258 .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
259 { .name = "ioctl", .ret_type = 1, .nargs = 3,
260 .args = { { Int, 0 }, { Ioctl, 1 }, { Ptr, 2 } } },
261 { .name = "kevent", .ret_type = 1, .nargs = 6,
262 .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
263 { Int, 4 }, { Timespec, 5 } } },
264 { .name = "kill", .ret_type = 1, .nargs = 2,
265 .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
266 { .name = "kldfind", .ret_type = 1, .nargs = 1,
267 .args = { { Name | IN, 0 } } },
268 { .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
269 .args = { { Int, 0 } } },
270 { .name = "kldload", .ret_type = 1, .nargs = 1,
271 .args = { { Name | IN, 0 } } },
272 { .name = "kldnext", .ret_type = 1, .nargs = 1,
273 .args = { { Int, 0 } } },
274 { .name = "kldstat", .ret_type = 1, .nargs = 2,
275 .args = { { Int, 0 }, { Ptr, 1 } } },
276 { .name = "kldsym", .ret_type = 1, .nargs = 3,
277 .args = { { Int, 0 }, { Kldsymcmd, 1 }, { Ptr, 2 } } },
278 { .name = "kldunload", .ret_type = 1, .nargs = 1,
279 .args = { { Int, 0 } } },
280 { .name = "kldunloadf", .ret_type = 1, .nargs = 2,
281 .args = { { Int, 0 }, { Kldunloadflags, 1 } } },
282 { .name = "kse_release", .ret_type = 0, .nargs = 1,
283 .args = { { Timespec, 0 } } },
284 { .name = "lchflags", .ret_type = 1, .nargs = 2,
285 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
286 { .name = "lchmod", .ret_type = 1, .nargs = 2,
287 .args = { { Name, 0 }, { Octal, 1 } } },
288 { .name = "lchown", .ret_type = 1, .nargs = 3,
289 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
290 { .name = "link", .ret_type = 1, .nargs = 2,
291 .args = { { Name, 0 }, { Name, 1 } } },
292 { .name = "linkat", .ret_type = 1, .nargs = 5,
293 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
295 { .name = "listen", .ret_type = 1, .nargs = 2,
296 .args = { { Int, 0 }, { Int, 1 } } },
297 { .name = "lseek", .ret_type = 2, .nargs = 3,
298 .args = { { Int, 0 }, { QuadHex, 1 }, { Whence, 2 } } },
299 { .name = "lstat", .ret_type = 1, .nargs = 2,
300 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
301 { .name = "lutimes", .ret_type = 1, .nargs = 2,
302 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
303 { .name = "madvise", .ret_type = 1, .nargs = 3,
304 .args = { { Ptr, 0 }, { Sizet, 1 }, { Madvice, 2 } } },
305 { .name = "minherit", .ret_type = 1, .nargs = 3,
306 .args = { { Ptr, 0 }, { Sizet, 1 }, { Minherit, 2 } } },
307 { .name = "mkdir", .ret_type = 1, .nargs = 2,
308 .args = { { Name, 0 }, { Octal, 1 } } },
309 { .name = "mkdirat", .ret_type = 1, .nargs = 3,
310 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
311 { .name = "mkfifo", .ret_type = 1, .nargs = 2,
312 .args = { { Name, 0 }, { Octal, 1 } } },
313 { .name = "mkfifoat", .ret_type = 1, .nargs = 3,
314 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
315 { .name = "mknod", .ret_type = 1, .nargs = 3,
316 .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
317 { .name = "mknodat", .ret_type = 1, .nargs = 4,
318 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
319 { .name = "mlock", .ret_type = 1, .nargs = 2,
320 .args = { { Ptr, 0 }, { Sizet, 1 } } },
321 { .name = "mlockall", .ret_type = 1, .nargs = 1,
322 .args = { { Mlockall, 0 } } },
323 { .name = "mmap", .ret_type = 1, .nargs = 6,
324 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
325 { Int, 4 }, { QuadHex, 5 } } },
326 { .name = "modfind", .ret_type = 1, .nargs = 1,
327 .args = { { Name | IN, 0 } } },
328 { .name = "mount", .ret_type = 1, .nargs = 4,
329 .args = { { Name, 0 }, { Name, 1 }, { Mountflags, 2 }, { Ptr, 3 } } },
330 { .name = "mprotect", .ret_type = 1, .nargs = 3,
331 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 } } },
332 { .name = "msync", .ret_type = 1, .nargs = 3,
333 .args = { { Ptr, 0 }, { Sizet, 1 }, { Msync, 2 } } },
334 { .name = "munlock", .ret_type = 1, .nargs = 2,
335 .args = { { Ptr, 0 }, { Sizet, 1 } } },
336 { .name = "munmap", .ret_type = 1, .nargs = 2,
337 .args = { { Ptr, 0 }, { Sizet, 1 } } },
338 { .name = "nanosleep", .ret_type = 1, .nargs = 1,
339 .args = { { Timespec, 0 } } },
340 { .name = "nmount", .ret_type = 1, .nargs = 3,
341 .args = { { Ptr, 0 }, { UInt, 1 }, { Mountflags, 2 } } },
342 { .name = "open", .ret_type = 1, .nargs = 3,
343 .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
344 { .name = "openat", .ret_type = 1, .nargs = 4,
345 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
347 { .name = "pathconf", .ret_type = 1, .nargs = 2,
348 .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
349 { .name = "pipe", .ret_type = 1, .nargs = 1,
350 .args = { { PipeFds | OUT, 0 } } },
351 { .name = "pipe2", .ret_type = 1, .nargs = 2,
352 .args = { { Ptr, 0 }, { Pipe2, 1 } } },
353 { .name = "poll", .ret_type = 1, .nargs = 3,
354 .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
355 { .name = "posix_fadvise", .ret_type = 1, .nargs = 4,
356 .args = { { Int, 0 }, { QuadHex, 1 }, { QuadHex, 2 },
358 { .name = "posix_openpt", .ret_type = 1, .nargs = 1,
359 .args = { { Open, 0 } } },
360 { .name = "pread", .ret_type = 1, .nargs = 4,
361 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
363 { .name = "procctl", .ret_type = 1, .nargs = 4,
364 .args = { { Idtype, 0 }, { Quad, 1 }, { Procctl, 2 }, { Ptr, 3 } } },
365 { .name = "ptrace", .ret_type = 1, .nargs = 4,
366 .args = { { Ptraceop, 0 }, { Int, 1 }, { Ptr, 2 }, { Int, 3 } } },
367 { .name = "pwrite", .ret_type = 1, .nargs = 4,
368 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
370 { .name = "quotactl", .ret_type = 1, .nargs = 4,
371 .args = { { Name, 0 }, { Quotactlcmd, 1 }, { Int, 2 }, { Ptr, 3 } } },
372 { .name = "read", .ret_type = 1, .nargs = 3,
373 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 } } },
374 { .name = "readv", .ret_type = 1, .nargs = 3,
375 .args = { { Int, 0 }, { Iovec | OUT, 1 }, { Int, 2 } } },
376 { .name = "readlink", .ret_type = 1, .nargs = 3,
377 .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Sizet, 2 } } },
378 { .name = "readlinkat", .ret_type = 1, .nargs = 4,
379 .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
381 { .name = "reboot", .ret_type = 1, .nargs = 1,
382 .args = { { Reboothowto, 0 } } },
383 { .name = "recvfrom", .ret_type = 1, .nargs = 6,
384 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
385 { Msgflags, 3 }, { Sockaddr | OUT, 4 },
386 { Ptr | OUT, 5 } } },
387 { .name = "recvmsg", .ret_type = 1, .nargs = 3,
388 .args = { { Int, 0 }, { Msghdr | OUT, 1 }, { Msgflags, 2 } } },
389 { .name = "rename", .ret_type = 1, .nargs = 2,
390 .args = { { Name, 0 }, { Name, 1 } } },
391 { .name = "renameat", .ret_type = 1, .nargs = 4,
392 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
393 { .name = "rfork", .ret_type = 1, .nargs = 1,
394 .args = { { Rforkflags, 0 } } },
395 { .name = "rmdir", .ret_type = 1, .nargs = 1,
396 .args = { { Name, 0 } } },
397 { .name = "rtprio", .ret_type = 1, .nargs = 3,
398 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
399 { .name = "rtprio_thread", .ret_type = 1, .nargs = 3,
400 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
401 { .name = "sched_get_priority_max", .ret_type = 1, .nargs = 1,
402 .args = { { Schedpolicy, 0 } } },
403 { .name = "sched_get_priority_min", .ret_type = 1, .nargs = 1,
404 .args = { { Schedpolicy, 0 } } },
405 { .name = "sched_getparam", .ret_type = 1, .nargs = 2,
406 .args = { { Int, 0 }, { Schedparam | OUT, 1 } } },
407 { .name = "sched_getscheduler", .ret_type = 1, .nargs = 1,
408 .args = { { Int, 0 } } },
409 { .name = "sched_rr_get_interval", .ret_type = 1, .nargs = 2,
410 .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
411 { .name = "sched_setparam", .ret_type = 1, .nargs = 2,
412 .args = { { Int, 0 }, { Schedparam, 1 } } },
413 { .name = "sched_setscheduler", .ret_type = 1, .nargs = 3,
414 .args = { { Int, 0 }, { Schedpolicy, 1 }, { Schedparam, 2 } } },
415 { .name = "sctp_generic_recvmsg", .ret_type = 1, .nargs = 7,
416 .args = { { Int, 0 }, { Iovec | OUT, 1 }, { Int, 2 },
417 { Sockaddr | OUT, 3 }, { Ptr | OUT, 4 },
418 { Sctpsndrcvinfo | OUT, 5 }, { Ptr | OUT, 6 } } },
419 { .name = "sctp_generic_sendmsg", .ret_type = 1, .nargs = 7,
420 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
421 { Sockaddr | IN, 3 }, { Socklent, 4 },
422 { Sctpsndrcvinfo | IN, 5 }, { Msgflags, 6 } } },
423 { .name = "sctp_generic_sendmsg_iov", .ret_type = 1, .nargs = 7,
424 .args = { { Int, 0 }, { Iovec | IN, 1 }, { Int, 2 },
425 { Sockaddr | IN, 3 }, { Socklent, 4 },
426 { Sctpsndrcvinfo | IN, 5 }, { Msgflags, 6 } } },
427 { .name = "select", .ret_type = 1, .nargs = 5,
428 .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
430 { .name = "sendmsg", .ret_type = 1, .nargs = 3,
431 .args = { { Int, 0 }, { Msghdr | IN, 1 }, { Msgflags, 2 } } },
432 { .name = "sendto", .ret_type = 1, .nargs = 6,
433 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
434 { Msgflags, 3 }, { Sockaddr | IN, 4 },
435 { Socklent | IN, 5 } } },
436 { .name = "setitimer", .ret_type = 1, .nargs = 3,
437 .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
438 { .name = "setpriority", .ret_type = 1, .nargs = 3,
439 .args = { { Priowhich, 0 }, { Int, 1 }, { Int, 2 } } },
440 { .name = "setrlimit", .ret_type = 1, .nargs = 2,
441 .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
442 { .name = "setsockopt", .ret_type = 1, .nargs = 5,
443 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
444 { Ptr | IN, 3 }, { Socklent, 4 } } },
445 { .name = "shutdown", .ret_type = 1, .nargs = 2,
446 .args = { { Int, 0 }, { Shutdown, 1 } } },
447 { .name = "sigaction", .ret_type = 1, .nargs = 3,
448 .args = { { Signal, 0 }, { Sigaction | IN, 1 },
449 { Sigaction | OUT, 2 } } },
450 { .name = "sigpending", .ret_type = 1, .nargs = 1,
451 .args = { { Sigset | OUT, 0 } } },
452 { .name = "sigprocmask", .ret_type = 1, .nargs = 3,
453 .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
454 { .name = "sigqueue", .ret_type = 1, .nargs = 3,
455 .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
456 { .name = "sigreturn", .ret_type = 1, .nargs = 1,
457 .args = { { Ptr, 0 } } },
458 { .name = "sigsuspend", .ret_type = 1, .nargs = 1,
459 .args = { { Sigset | IN, 0 } } },
460 { .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
461 .args = { { Sigset | IN, 0 }, { Siginfo | OUT, 1 },
462 { Timespec | IN, 2 } } },
463 { .name = "sigwait", .ret_type = 1, .nargs = 2,
464 .args = { { Sigset | IN, 0 }, { PSig | OUT, 1 } } },
465 { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
466 .args = { { Sigset | IN, 0 }, { Siginfo | OUT, 1 } } },
467 { .name = "socket", .ret_type = 1, .nargs = 3,
468 .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Sockprotocol, 2 } } },
469 { .name = "stat", .ret_type = 1, .nargs = 2,
470 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
471 { .name = "statfs", .ret_type = 1, .nargs = 2,
472 .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } },
473 { .name = "symlink", .ret_type = 1, .nargs = 2,
474 .args = { { Name, 0 }, { Name, 1 } } },
475 { .name = "symlinkat", .ret_type = 1, .nargs = 3,
476 .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } },
477 { .name = "sysarch", .ret_type = 1, .nargs = 2,
478 .args = { { Sysarch, 0 }, { Ptr, 1 } } },
479 { .name = "thr_kill", .ret_type = 1, .nargs = 2,
480 .args = { { Long, 0 }, { Signal, 1 } } },
481 { .name = "thr_self", .ret_type = 1, .nargs = 1,
482 .args = { { Ptr, 0 } } },
483 { .name = "thr_set_name", .ret_type = 1, .nargs = 2,
484 .args = { { Long, 0 }, { Name, 1 } } },
485 { .name = "truncate", .ret_type = 1, .nargs = 2,
486 .args = { { Name | IN, 0 }, { QuadHex | IN, 1 } } },
489 { .name = "umount", .ret_type = 1, .nargs = 2,
490 .args = { { Name, 0 }, { Int, 2 } } },
492 { .name = "unlink", .ret_type = 1, .nargs = 1,
493 .args = { { Name, 0 } } },
494 { .name = "unlinkat", .ret_type = 1, .nargs = 3,
495 .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
496 { .name = "unmount", .ret_type = 1, .nargs = 2,
497 .args = { { Name, 0 }, { Mountflags, 1 } } },
498 { .name = "utimensat", .ret_type = 1, .nargs = 4,
499 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
501 { .name = "utimes", .ret_type = 1, .nargs = 2,
502 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
503 { .name = "utrace", .ret_type = 1, .nargs = 1,
504 .args = { { Utrace, 0 } } },
505 { .name = "wait4", .ret_type = 1, .nargs = 4,
506 .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
507 { Rusage | OUT, 3 } } },
508 { .name = "wait6", .ret_type = 1, .nargs = 6,
509 .args = { { Idtype, 0 }, { Quad, 1 }, { ExitStatus | OUT, 2 },
510 { Waitoptions, 3 }, { Rusage | OUT, 4 },
511 { Siginfo | OUT, 5 } } },
512 { .name = "write", .ret_type = 1, .nargs = 3,
513 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 } } },
514 { .name = "writev", .ret_type = 1, .nargs = 3,
515 .args = { { Int, 0 }, { Iovec | IN, 1 }, { Int, 2 } } },
518 { .name = "linux_access", .ret_type = 1, .nargs = 2,
519 .args = { { Name, 0 }, { Accessmode, 1 } } },
520 { .name = "linux_execve", .ret_type = 1, .nargs = 3,
521 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
522 { ExecEnv | IN, 2 } } },
523 { .name = "linux_lseek", .ret_type = 2, .nargs = 3,
524 .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
525 { .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
526 .args = { { Name | IN, 0 }, { Int, 1 } } },
527 { .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
528 .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
529 { .name = "linux_newstat", .ret_type = 1, .nargs = 2,
530 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
531 { .name = "linux_open", .ret_type = 1, .nargs = 3,
532 .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
533 { .name = "linux_readlink", .ret_type = 1, .nargs = 3,
534 .args = { { Name, 0 }, { Name | OUT, 1 }, { Sizet, 2 } } },
535 { .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
536 .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
537 { .name = "linux_stat64", .ret_type = 1, .nargs = 2,
538 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
540 /* CloudABI system calls. */
541 { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
542 .args = { { CloudABIClockID, 0 } } },
543 { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
544 .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
545 { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
546 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
547 { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
548 .args = { { Int, 0 } } },
549 { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
550 .args = { { CloudABIFileType, 0 } } },
551 { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
552 .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
553 { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
554 .args = { { Int, 0 } } },
555 { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
556 .args = { { Int, 0 } } },
557 { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
558 .args = { { Int, 0 }, { Int, 1 } } },
559 { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
560 .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
561 { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
562 .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
563 { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
564 .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
565 { ClouduABIFDSFlags, 2 } } },
566 { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
567 .args = { { Int, 0 } } },
568 { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
569 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
570 { CloudABIAdvice, 3 } } },
571 { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
572 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
573 { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
574 .args = { { Int, 0 }, { BinString | IN, 1 },
575 { CloudABIFileType, 3 } } },
576 { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
577 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
578 { Int, 3 }, { BinString | IN, 4 } } },
579 { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
580 .args = { { Int, 0 }, { BinString | IN, 1 },
581 { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
582 { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
583 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
585 { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
586 .args = { { Int, 0 }, { BinString | IN, 1 },
587 { BinString | OUT, 3 }, { Int, 4 } } },
588 { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
589 .args = { { Int, 0 }, { BinString | IN, 1 },
590 { Int, 3 }, { BinString | IN, 4 } } },
591 { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
592 .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
593 { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
594 .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
595 { CloudABIFSFlags, 2 } } },
596 { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
597 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
598 { CloudABIFileStat | OUT, 3 } } },
599 { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
600 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
601 { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
602 { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
603 .args = { { BinString | IN, 0 },
604 { Int, 2 }, { BinString | IN, 3 } } },
605 { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
606 .args = { { Int, 0 }, { BinString | IN, 1 },
607 { CloudABIULFlags, 3 } } },
608 { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
609 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
610 { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
611 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
612 { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
613 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
614 { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
615 { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
616 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
617 { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
618 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
619 { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
620 .args = { { Ptr, 0 }, { Int, 1 } } },
621 { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
622 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
623 { IntArray, 3 }, { Int, 4 } } },
624 { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
625 .args = { { Int, 0 } } },
626 { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
627 { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
628 .args = { { CloudABISignal, 0 } } },
629 { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
630 .args = { { BinString | OUT, 0 }, { Int, 1 } } },
631 { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
632 .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
633 { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
634 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
635 { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
639 static STAILQ_HEAD(, syscall) syscalls;
641 /* Xlat idea taken from strace */
647 #define X(a) { a, #a },
648 #define XEND { 0, NULL }
650 static struct xlat poll_flags[] = {
651 X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
652 X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
653 X(POLLWRBAND) X(POLLINIGNEOF) XEND
656 static struct xlat sigaction_flags[] = {
657 X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
658 X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
661 static struct xlat linux_socketcall_ops[] = {
662 X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
663 X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
664 X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
665 X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
666 X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
671 #define X(a) { CLOUDABI_##a, #a },
673 static struct xlat cloudabi_advice[] = {
674 X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
675 X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
679 static struct xlat cloudabi_clockid[] = {
680 X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
681 X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
685 static struct xlat cloudabi_fdflags[] = {
686 X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
687 X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
691 static struct xlat cloudabi_fdsflags[] = {
692 X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
696 static struct xlat cloudabi_filetype[] = {
697 X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
698 X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
699 X(FILETYPE_PROCESS) X(FILETYPE_REGULAR_FILE)
700 X(FILETYPE_SHARED_MEMORY) X(FILETYPE_SOCKET_DGRAM)
701 X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK)
705 static struct xlat cloudabi_fsflags[] = {
706 X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
707 X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
711 static struct xlat cloudabi_mflags[] = {
712 X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
716 static struct xlat cloudabi_mprot[] = {
717 X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
721 static struct xlat cloudabi_msflags[] = {
722 X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
726 static struct xlat cloudabi_oflags[] = {
727 X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
731 static struct xlat cloudabi_sdflags[] = {
732 X(SHUT_RD) X(SHUT_WR)
736 static struct xlat cloudabi_signal[] = {
737 X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
738 X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
739 X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
740 X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
741 X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
745 static struct xlat cloudabi_ulflags[] = {
750 static struct xlat cloudabi_whence[] = {
751 X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
759 * Searches an xlat array for a value, and returns it if found. Otherwise
760 * return a string representation.
763 lookup(struct xlat *xlat, int val, int base)
767 for (; xlat->str != NULL; xlat++)
768 if (xlat->val == val)
772 sprintf(tmp, "0%o", val);
775 sprintf(tmp, "0x%x", val);
778 sprintf(tmp, "%u", val);
781 errx(1,"Unknown lookup base");
788 xlookup(struct xlat *xlat, int val)
791 return (lookup(xlat, val, 16));
795 * Searches an xlat array containing bitfield values. Remaining bits
796 * set after removing the known ones are printed at the end:
800 xlookup_bits(struct xlat *xlat, int val)
803 static char str[512];
807 for (; xlat->str != NULL; xlat++) {
808 if ((xlat->val & rem) == xlat->val) {
810 * Don't print the "all-bits-zero" string unless all
811 * bits are really zero.
813 if (xlat->val == 0 && val != 0)
815 len += sprintf(str + len, "%s|", xlat->str);
821 * If we have leftover bits or didn't match anything, print
825 len += sprintf(str + len, "0x%x", rem);
826 if (len && str[len - 1] == '|')
833 print_integer_arg(const char *(*decoder)(int), FILE *fp, int value)
837 str = decoder(value);
841 fprintf(fp, "%d", value);
845 print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value)
849 if (!decoder(fp, value, &rem))
850 fprintf(fp, "0x%x", rem);
852 fprintf(fp, "|0x%x", rem);
856 print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), FILE *fp,
861 if (!decoder(fp, value, &rem))
862 fprintf(fp, "0x%x", rem);
864 fprintf(fp, "|0x%x", rem);
869 * Add argument padding to subsequent system calls afater a Quad
870 * syscall arguments as needed. This used to be done by hand in the
871 * decoded_syscalls table which was ugly and error prone. It is
872 * simpler to do the fixup of offsets at initalization time than when
873 * decoding arguments.
876 quad_fixup(struct syscall *sc)
883 for (i = 0; i < sc->nargs; i++) {
884 /* This arg type is a dummy that doesn't use offset. */
885 if ((sc->args[i].type & ARG_MASK) == PipeFds)
888 assert(prev < sc->args[i].offset);
889 prev = sc->args[i].offset;
890 sc->args[i].offset += offset;
891 switch (sc->args[i].type & ARG_MASK) {
896 * 64-bit arguments on 32-bit powerpc must be
897 * 64-bit aligned. If the current offset is
898 * not aligned, the calling convention inserts
899 * a 32-bit pad argument that should be skipped.
901 if (sc->args[i].offset % 2 == 1) {
902 sc->args[i].offset++;
919 STAILQ_INIT(&syscalls);
920 for (sc = decoded_syscalls; sc->name != NULL; sc++) {
924 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
928 static struct syscall *
929 find_syscall(struct procabi *abi, u_int number)
931 struct extra_syscall *es;
933 if (number < nitems(abi->syscalls))
934 return (abi->syscalls[number]);
935 STAILQ_FOREACH(es, &abi->extra_syscalls, entries) {
936 if (es->number == number)
943 add_syscall(struct procabi *abi, u_int number, struct syscall *sc)
945 struct extra_syscall *es;
947 if (number < nitems(abi->syscalls)) {
948 assert(abi->syscalls[number] == NULL);
949 abi->syscalls[number] = sc;
951 es = malloc(sizeof(*es));
954 STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries);
959 * If/when the list gets big, it might be desirable to do it
960 * as a hash table or binary search.
963 get_syscall(struct threadinfo *t, u_int number, u_int nargs)
970 sc = find_syscall(t->proc->abi, number);
974 name = sysdecode_syscallname(t->proc->abi->abi, number);
976 asprintf(&new_name, "#%d", number);
980 STAILQ_FOREACH(sc, &syscalls, entries) {
981 if (strcmp(name, sc->name) == 0) {
982 add_syscall(t->proc->abi, number, sc);
988 /* It is unknown. Add it into the list. */
990 fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
994 sc = calloc(1, sizeof(struct syscall));
996 if (new_name != NULL)
1000 for (i = 0; i < nargs; i++) {
1001 sc->args[i].offset = i;
1002 /* Treat all unknown arguments as LongHex. */
1003 sc->args[i].type = LongHex;
1005 STAILQ_INSERT_HEAD(&syscalls, sc, entries);
1006 add_syscall(t->proc->abi, number, sc);
1012 * Copy a fixed amount of bytes from the process.
1015 get_struct(pid_t pid, void *offset, void *buf, int len)
1017 struct ptrace_io_desc iorequest;
1019 iorequest.piod_op = PIOD_READ_D;
1020 iorequest.piod_offs = offset;
1021 iorequest.piod_addr = buf;
1022 iorequest.piod_len = len;
1023 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
1028 #define MAXSIZE 4096
1031 * Copy a string from the process. Note that it is
1032 * expected to be a C string, but if max is set, it will
1033 * only get that much.
1036 get_string(pid_t pid, void *addr, int max)
1038 struct ptrace_io_desc iorequest;
1040 size_t offset, size, totalsize;
1046 /* Read up to the end of the current page. */
1047 size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE);
1052 buf = malloc(totalsize);
1056 iorequest.piod_op = PIOD_READ_D;
1057 iorequest.piod_offs = (char *)addr + offset;
1058 iorequest.piod_addr = buf + offset;
1059 iorequest.piod_len = size;
1060 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
1064 if (memchr(buf + offset, '\0', size) != NULL)
1067 if (totalsize < MAXSIZE && max == 0) {
1068 size = MAXSIZE - totalsize;
1069 if (size > PAGE_SIZE)
1071 nbuf = realloc(buf, totalsize + size);
1073 buf[totalsize - 1] = '\0';
1079 buf[totalsize - 1] = '\0';
1088 static char tmp[32];
1089 const char *signame;
1091 signame = sysdecode_signal(sig);
1092 if (signame == NULL) {
1093 snprintf(tmp, sizeof(tmp), "%d", sig);
1100 print_kevent(FILE *fp, struct kevent *ke)
1103 switch (ke->filter) {
1109 case EVFILT_PROCDESC:
1110 fprintf(fp, "%ju", (uintmax_t)ke->ident);
1113 fputs(strsig2(ke->ident), fp);
1116 fprintf(fp, "%p", (void *)ke->ident);
1119 print_integer_arg(sysdecode_kevent_filter, fp, ke->filter);
1121 print_mask_arg(sysdecode_kevent_flags, fp, ke->flags);
1123 sysdecode_kevent_fflags(fp, ke->filter, ke->fflags, 16);
1124 fprintf(fp, ",%p,%p", (void *)ke->data, (void *)ke->udata);
1128 print_utrace(FILE *fp, void *utrace_addr, size_t len)
1130 unsigned char *utrace_buffer;
1133 if (sysdecode_utrace(fp, utrace_addr, len)) {
1138 utrace_buffer = utrace_addr;
1139 fprintf(fp, "%zu:", len);
1141 fprintf(fp, " %02x", *utrace_buffer++);
1146 print_sockaddr(FILE *fp, struct trussinfo *trussinfo, void *arg, socklen_t len)
1149 struct sockaddr_in *lsin;
1150 struct sockaddr_in6 *lsin6;
1151 struct sockaddr_un *sun;
1152 struct sockaddr *sa;
1154 pid_t pid = trussinfo->curthread->proc->pid;
1160 /* If the length is too small, just bail. */
1161 if (len < sizeof(*sa)) {
1162 fprintf(fp, "%p", arg);
1166 sa = calloc(1, len);
1167 if (get_struct(pid, arg, sa, len) == -1) {
1169 fprintf(fp, "%p", arg);
1173 switch (sa->sa_family) {
1175 if (len < sizeof(*lsin))
1176 goto sockaddr_short;
1177 lsin = (struct sockaddr_in *)(void *)sa;
1178 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1179 fprintf(fp, "{ AF_INET %s:%d }", addr,
1180 htons(lsin->sin_port));
1183 if (len < sizeof(*lsin6))
1184 goto sockaddr_short;
1185 lsin6 = (struct sockaddr_in6 *)(void *)sa;
1186 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1188 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1189 htons(lsin6->sin6_port));
1192 sun = (struct sockaddr_un *)sa;
1193 fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1194 (int)(len - offsetof(struct sockaddr_un, sun_path)),
1200 "{ sa_len = %d, sa_family = %d, sa_data = {",
1201 (int)sa->sa_len, (int)sa->sa_family);
1202 for (q = (u_char *)sa->sa_data;
1203 q < (u_char *)sa + len; q++)
1204 fprintf(fp, "%s 0x%02x",
1205 q == (u_char *)sa->sa_data ? "" : ",",
1212 #define IOV_LIMIT 16
1215 print_iovec(FILE *fp, struct trussinfo *trussinfo, void *arg, int iovcnt)
1217 struct iovec iov[IOV_LIMIT];
1218 size_t max_string = trussinfo->strsize;
1219 char tmp2[max_string + 1], *tmp3;
1221 pid_t pid = trussinfo->curthread->proc->pid;
1223 bool buf_truncated, iov_truncated;
1226 fprintf(fp, "%p", arg);
1229 if (iovcnt > IOV_LIMIT) {
1231 iov_truncated = true;
1233 iov_truncated = false;
1235 if (get_struct(pid, arg, &iov, iovcnt * sizeof(struct iovec)) == -1) {
1236 fprintf(fp, "%p", arg);
1241 for (i = 0; i < iovcnt; i++) {
1242 len = iov[i].iov_len;
1243 if (len > max_string) {
1245 buf_truncated = true;
1247 buf_truncated = false;
1249 fprintf(fp, "%s{", (i > 0) ? "," : "");
1250 if (len && get_struct(pid, iov[i].iov_base, &tmp2, len) != -1) {
1251 tmp3 = malloc(len * 4 + 1);
1253 if (strvisx(tmp3, tmp2, len,
1254 VIS_CSTYLE|VIS_TAB|VIS_NL) <=
1258 buf_truncated = true;
1260 fprintf(fp, "\"%s\"%s", tmp3,
1261 buf_truncated ? "..." : "");
1264 fprintf(fp, "%p", iov[i].iov_base);
1266 fprintf(fp, ",%zu}", iov[i].iov_len);
1268 fprintf(fp, "%s%s", iov_truncated ? ",..." : "", "]");
1272 print_gen_cmsg(FILE *fp, struct cmsghdr *cmsghdr)
1277 for (q = CMSG_DATA(cmsghdr);
1278 q < (u_char *)cmsghdr + cmsghdr->cmsg_len; q++) {
1279 fprintf(fp, "%s0x%02x", q == CMSG_DATA(cmsghdr) ? "" : ",", *q);
1285 print_sctp_initmsg(FILE *fp, struct sctp_initmsg *init)
1287 fprintf(fp, "{out=%u,", init->sinit_num_ostreams);
1288 fprintf(fp, "in=%u,", init->sinit_max_instreams);
1289 fprintf(fp, "max_rtx=%u,", init->sinit_max_attempts);
1290 fprintf(fp, "max_rto=%u}", init->sinit_max_init_timeo);
1294 print_sctp_sndrcvinfo(FILE *fp, bool recv, struct sctp_sndrcvinfo *info)
1296 fprintf(fp, "{sid=%u,", info->sinfo_stream);
1298 fprintf(fp, "ssn=%u,", info->sinfo_ssn);
1301 sysdecode_sctp_sinfo_flags(fp, info->sinfo_flags);
1302 fprintf(fp, ",ppid=%u,", ntohl(info->sinfo_ppid));
1304 fprintf(fp, "ctx=%u,", info->sinfo_context);
1305 fprintf(fp, "ttl=%u,", info->sinfo_timetolive);
1308 fprintf(fp, "tsn=%u,", info->sinfo_tsn);
1309 fprintf(fp, "cumtsn=%u,", info->sinfo_cumtsn);
1311 fprintf(fp, "id=%u}", info->sinfo_assoc_id);
1315 print_sctp_sndinfo(FILE *fp, struct sctp_sndinfo *info)
1317 fprintf(fp, "{sid=%u,", info->snd_sid);
1319 print_mask_arg(sysdecode_sctp_snd_flags, fp, info->snd_flags);
1320 fprintf(fp, ",ppid=%u,", ntohl(info->snd_ppid));
1321 fprintf(fp, "ctx=%u,", info->snd_context);
1322 fprintf(fp, "id=%u}", info->snd_assoc_id);
1326 print_sctp_rcvinfo(FILE *fp, struct sctp_rcvinfo *info)
1328 fprintf(fp, "{sid=%u,", info->rcv_sid);
1329 fprintf(fp, "ssn=%u,", info->rcv_ssn);
1331 print_mask_arg(sysdecode_sctp_rcv_flags, fp, info->rcv_flags);
1332 fprintf(fp, ",ppid=%u,", ntohl(info->rcv_ppid));
1333 fprintf(fp, "tsn=%u,", info->rcv_tsn);
1334 fprintf(fp, "cumtsn=%u,", info->rcv_cumtsn);
1335 fprintf(fp, "ctx=%u,", info->rcv_context);
1336 fprintf(fp, "id=%u}", info->rcv_assoc_id);
1340 print_sctp_nxtinfo(FILE *fp, struct sctp_nxtinfo *info)
1342 fprintf(fp, "{sid=%u,", info->nxt_sid);
1344 print_mask_arg(sysdecode_sctp_nxt_flags, fp, info->nxt_flags);
1345 fprintf(fp, ",ppid=%u,", ntohl(info->nxt_ppid));
1346 fprintf(fp, "len=%u,", info->nxt_length);
1347 fprintf(fp, "id=%u}", info->nxt_assoc_id);
1351 print_sctp_prinfo(FILE *fp, struct sctp_prinfo *info)
1354 print_integer_arg(sysdecode_sctp_pr_policy, fp, info->pr_policy);
1355 fprintf(fp, ",val=%u}", info->pr_value);
1359 print_sctp_authinfo(FILE *fp, struct sctp_authinfo *info)
1361 fprintf(fp, "{num=%u}", info->auth_keynumber);
1365 print_sctp_ipv4_addr(FILE *fp, struct in_addr *addr)
1367 char buf[INET_ADDRSTRLEN];
1370 s = inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN);
1372 fprintf(fp, "{addr=%s}", s);
1374 fputs("{addr=???}", fp);
1378 print_sctp_ipv6_addr(FILE *fp, struct in6_addr *addr)
1380 char buf[INET6_ADDRSTRLEN];
1383 s = inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN);
1385 fprintf(fp, "{addr=%s}", s);
1387 fputs("{addr=???}", fp);
1391 print_sctp_cmsg(FILE *fp, bool recv, struct cmsghdr *cmsghdr)
1396 len = cmsghdr->cmsg_len;
1397 data = CMSG_DATA(cmsghdr);
1398 switch (cmsghdr->cmsg_type) {
1400 if (len == CMSG_LEN(sizeof(struct sctp_initmsg)))
1401 print_sctp_initmsg(fp, (struct sctp_initmsg *)data);
1403 print_gen_cmsg(fp, cmsghdr);
1406 if (len == CMSG_LEN(sizeof(struct sctp_sndrcvinfo)))
1407 print_sctp_sndrcvinfo(fp, recv,
1408 (struct sctp_sndrcvinfo *)data);
1410 print_gen_cmsg(fp, cmsghdr);
1414 if (len == CMSG_LEN(sizeof(struct sctp_extrcvinfo)))
1415 print_sctp_extrcvinfo(fp,
1416 (struct sctp_extrcvinfo *)data);
1418 print_gen_cmsg(fp, cmsghdr);
1422 if (len == CMSG_LEN(sizeof(struct sctp_sndinfo)))
1423 print_sctp_sndinfo(fp, (struct sctp_sndinfo *)data);
1425 print_gen_cmsg(fp, cmsghdr);
1428 if (len == CMSG_LEN(sizeof(struct sctp_rcvinfo)))
1429 print_sctp_rcvinfo(fp, (struct sctp_rcvinfo *)data);
1431 print_gen_cmsg(fp, cmsghdr);
1434 if (len == CMSG_LEN(sizeof(struct sctp_nxtinfo)))
1435 print_sctp_nxtinfo(fp, (struct sctp_nxtinfo *)data);
1437 print_gen_cmsg(fp, cmsghdr);
1440 if (len == CMSG_LEN(sizeof(struct sctp_prinfo)))
1441 print_sctp_prinfo(fp, (struct sctp_prinfo *)data);
1443 print_gen_cmsg(fp, cmsghdr);
1446 if (len == CMSG_LEN(sizeof(struct sctp_authinfo)))
1447 print_sctp_authinfo(fp, (struct sctp_authinfo *)data);
1449 print_gen_cmsg(fp, cmsghdr);
1451 case SCTP_DSTADDRV4:
1452 if (len == CMSG_LEN(sizeof(struct in_addr)))
1453 print_sctp_ipv4_addr(fp, (struct in_addr *)data);
1455 print_gen_cmsg(fp, cmsghdr);
1457 case SCTP_DSTADDRV6:
1458 if (len == CMSG_LEN(sizeof(struct in6_addr)))
1459 print_sctp_ipv6_addr(fp, (struct in6_addr *)data);
1461 print_gen_cmsg(fp, cmsghdr);
1464 print_gen_cmsg(fp, cmsghdr);
1469 print_cmsgs(FILE *fp, pid_t pid, bool recv, struct msghdr *msghdr)
1471 struct cmsghdr *cmsghdr;
1478 len = msghdr->msg_controllen;
1483 cmsgbuf = calloc(1, len);
1484 if (get_struct(pid, msghdr->msg_control, cmsgbuf, len) == -1) {
1485 fprintf(fp, "%p", msghdr->msg_control);
1489 msghdr->msg_control = cmsgbuf;
1492 for (cmsghdr = CMSG_FIRSTHDR(msghdr);
1494 cmsghdr = CMSG_NXTHDR(msghdr, cmsghdr)) {
1495 level = cmsghdr->cmsg_level;
1496 type = cmsghdr->cmsg_type;
1497 len = cmsghdr->cmsg_len;
1498 fprintf(fp, "%s{level=", first ? "" : ",");
1499 print_integer_arg(sysdecode_sockopt_level, fp, level);
1500 fputs(",type=", fp);
1501 temp = sysdecode_cmsg_type(level, type);
1505 fprintf(fp, "%d", type);
1507 fputs(",data=", fp);
1510 print_sctp_cmsg(fp, recv, cmsghdr);
1513 print_gen_cmsg(fp, cmsghdr);
1523 * Converts a syscall argument into a string. Said string is
1524 * allocated via malloc(), so needs to be free()'d. sc is
1525 * a pointer to the syscall description (see above); args is
1526 * an array of all of the system call arguments.
1529 print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
1530 struct trussinfo *trussinfo)
1537 fp = open_memstream(&tmp, &tmplen);
1538 pid = trussinfo->curthread->proc->pid;
1539 switch (sc->type & ARG_MASK) {
1541 fprintf(fp, "0x%x", (int)args[sc->offset]);
1544 fprintf(fp, "0%o", (int)args[sc->offset]);
1547 fprintf(fp, "%d", (int)args[sc->offset]);
1550 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1555 if (get_struct(pid, (void *)args[sc->offset], &val,
1557 fprintf(fp, "{ %u }", val);
1559 fprintf(fp, "0x%lx", args[sc->offset]);
1563 fprintf(fp, "0x%lx", args[sc->offset]);
1566 fprintf(fp, "%ld", args[sc->offset]);
1569 fprintf(fp, "%zu", (size_t)args[sc->offset]);
1572 /* NULL-terminated string. */
1575 tmp2 = get_string(pid, (void*)args[sc->offset], 0);
1576 fprintf(fp, "\"%s\"", tmp2);
1582 * Binary block of data that might have printable characters.
1583 * XXX If type|OUT, assume that the length is the syscall's
1584 * return value. Otherwise, assume that the length of the block
1585 * is in the next syscall argument.
1587 int max_string = trussinfo->strsize;
1588 char tmp2[max_string + 1], *tmp3;
1595 len = args[sc->offset + 1];
1598 * Don't print more than max_string characters, to avoid word
1599 * wrap. If we have to truncate put some ... after the string.
1601 if (len > max_string) {
1605 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
1607 tmp3 = malloc(len * 4 + 1);
1609 if (strvisx(tmp3, tmp2, len,
1610 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1615 fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1619 fprintf(fp, "0x%lx", args[sc->offset]);
1629 char buf[PAGE_SIZE];
1636 * Only parse argv[] and environment arrays from exec calls
1639 if (((sc->type & ARG_MASK) == ExecArgs &&
1640 (trussinfo->flags & EXECVEARGS) == 0) ||
1641 ((sc->type & ARG_MASK) == ExecEnv &&
1642 (trussinfo->flags & EXECVEENVS) == 0)) {
1643 fprintf(fp, "0x%lx", args[sc->offset]);
1648 * Read a page of pointers at a time. Punt if the top-level
1649 * pointer is not aligned. Note that the first read is of
1652 addr = args[sc->offset];
1653 if (addr % sizeof(char *) != 0) {
1654 fprintf(fp, "0x%lx", args[sc->offset]);
1658 len = PAGE_SIZE - (addr & PAGE_MASK);
1659 if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
1660 fprintf(fp, "0x%lx", args[sc->offset]);
1667 while (u.strarray[i] != NULL) {
1668 string = get_string(pid, u.strarray[i], 0);
1669 fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1674 if (i == len / sizeof(char *)) {
1677 if (get_struct(pid, (void *)addr, u.buf, len) ==
1679 fprintf(fp, ", <inval>");
1690 fprintf(fp, "%ld", args[sc->offset]);
1693 fprintf(fp, "0x%lx", args[sc->offset]);
1698 unsigned long long ll;
1700 #if _BYTE_ORDER == _LITTLE_ENDIAN
1701 ll = (unsigned long long)args[sc->offset + 1] << 32 |
1704 ll = (unsigned long long)args[sc->offset] << 32 |
1705 args[sc->offset + 1];
1707 if ((sc->type & ARG_MASK) == Quad)
1708 fprintf(fp, "%lld", ll);
1710 fprintf(fp, "0x%llx", ll);
1717 if (get_struct(pid, (void *)args[sc->offset], &val,
1719 fprintf(fp, "{ 0x%jx }", (uintmax_t)val);
1721 fprintf(fp, "0x%lx", args[sc->offset]);
1725 fprintf(fp, "0x%lx", args[sc->offset]);
1730 if (retval[0] == -1)
1732 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
1733 fprintf(fp, "\"%s\"", tmp2);
1741 cmd = args[sc->offset];
1742 temp = sysdecode_ioctlname(cmd);
1746 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1747 cmd, cmd & IOC_OUT ? "R" : "",
1748 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1749 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1750 cmd & 0xFF, IOCPARM_LEN(cmd));
1757 if (get_struct(pid, (void *)args[sc->offset], &ts,
1759 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1762 fprintf(fp, "0x%lx", args[sc->offset]);
1766 struct timespec ts[2];
1770 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
1774 for (i = 0; i < nitems(ts); i++) {
1777 switch (ts[i].tv_nsec) {
1779 fprintf(fp, "UTIME_NOW");
1782 fprintf(fp, "UTIME_OMIT");
1785 fprintf(fp, "%jd.%09ld",
1786 (intmax_t)ts[i].tv_sec,
1793 fprintf(fp, "0x%lx", args[sc->offset]);
1799 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1801 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1804 fprintf(fp, "0x%lx", args[sc->offset]);
1808 struct timeval tv[2];
1810 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1812 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1813 (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1814 (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1816 fprintf(fp, "0x%lx", args[sc->offset]);
1820 struct itimerval itv;
1822 if (get_struct(pid, (void *)args[sc->offset], &itv,
1824 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1825 (intmax_t)itv.it_interval.tv_sec,
1826 itv.it_interval.tv_usec,
1827 (intmax_t)itv.it_value.tv_sec,
1828 itv.it_value.tv_usec);
1830 fprintf(fp, "0x%lx", args[sc->offset]);
1835 struct linux_socketcall_args largs;
1837 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
1838 sizeof(largs)) != -1)
1839 fprintf(fp, "{ %s, 0x%lx }",
1840 lookup(linux_socketcall_ops, largs.what, 10),
1841 (long unsigned int)largs.args);
1843 fprintf(fp, "0x%lx", args[sc->offset]);
1848 * XXX: A Pollfd argument expects the /next/ syscall argument
1849 * to be the number of fds in the array. This matches the poll
1853 int numfds = args[sc->offset + 1];
1854 size_t bytes = sizeof(struct pollfd) * numfds;
1857 if ((pfd = malloc(bytes)) == NULL)
1858 err(1, "Cannot malloc %zu bytes for pollfd array",
1860 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
1863 for (i = 0; i < numfds; i++) {
1864 fprintf(fp, " %d/%s", pfd[i].fd,
1865 xlookup_bits(poll_flags, pfd[i].events));
1869 fprintf(fp, "0x%lx", args[sc->offset]);
1876 * XXX: A Fd_set argument expects the /first/ syscall argument
1877 * to be the number of fds in the array. This matches the
1881 int numfds = args[0];
1882 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1885 if ((fds = malloc(bytes)) == NULL)
1886 err(1, "Cannot malloc %zu bytes for fd_set array",
1888 if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
1891 for (i = 0; i < numfds; i++) {
1892 if (FD_ISSET(i, fds))
1893 fprintf(fp, " %d", i);
1897 fprintf(fp, "0x%lx", args[sc->offset]);
1902 fputs(strsig2(args[sc->offset]), fp);
1909 sig = args[sc->offset];
1910 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
1911 sizeof(ss)) == -1) {
1912 fprintf(fp, "0x%lx", args[sc->offset]);
1917 for (i = 1; i < sys_nsig; i++) {
1918 if (sigismember(&ss, i)) {
1919 fprintf(fp, "%s%s", !first ? "|" : "",
1930 print_integer_arg(sysdecode_sigprocmask_how, fp,
1934 /* XXX: Output depends on the value of the previous argument. */
1935 if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
1936 sysdecode_fcntl_arg(fp, args[sc->offset - 1],
1937 args[sc->offset], 16);
1940 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
1943 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
1946 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
1949 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
1952 print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
1955 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
1958 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
1961 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
1964 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
1967 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]);
1970 print_integer_arg(sysdecode_pathconf_name, fp, args[sc->offset]);
1973 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
1978 if (args[sc->offset] == 0) {
1984 * Extract the address length from the next argument. If
1985 * this is an output sockaddr (OUT is set), then the
1986 * next argument is a pointer to a socklen_t. Otherwise
1987 * the next argument contains a socklen_t by value.
1989 if (sc->type & OUT) {
1990 if (get_struct(pid, (void *)args[sc->offset + 1],
1991 &len, sizeof(len)) == -1) {
1992 fprintf(fp, "0x%lx", args[sc->offset]);
1996 len = args[sc->offset + 1];
1998 print_sockaddr(fp, trussinfo, (void *)args[sc->offset], len);
2002 struct sigaction sa;
2004 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
2007 if (sa.sa_handler == SIG_DFL)
2008 fputs("SIG_DFL", fp);
2009 else if (sa.sa_handler == SIG_IGN)
2010 fputs("SIG_IGN", fp);
2012 fprintf(fp, "%p", sa.sa_handler);
2013 fprintf(fp, " %s ss_t }",
2014 xlookup_bits(sigaction_flags, sa.sa_flags));
2016 fprintf(fp, "0x%lx", args[sc->offset]);
2021 * XXX XXX: The size of the array is determined by either the
2022 * next syscall argument, or by the syscall return value,
2023 * depending on which argument number we are. This matches the
2024 * kevent syscall, but luckily that's the only syscall that uses
2032 if (sc->offset == 1)
2033 numevents = args[sc->offset+1];
2034 else if (sc->offset == 3 && retval[0] != -1)
2035 numevents = retval[0];
2037 if (numevents >= 0) {
2038 bytes = sizeof(struct kevent) * numevents;
2039 if ((ke = malloc(bytes)) == NULL)
2041 "Cannot malloc %zu bytes for kevent array",
2045 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
2048 for (i = 0; i < numevents; i++) {
2050 print_kevent(fp, &ke[i]);
2054 fprintf(fp, "0x%lx", args[sc->offset]);
2062 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
2066 strmode(st.st_mode, mode);
2068 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
2069 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
2070 (long)st.st_blksize);
2072 fprintf(fp, "0x%lx", args[sc->offset]);
2080 if (get_struct(pid, (void *)args[sc->offset], &buf,
2081 sizeof(buf)) != -1) {
2084 bzero(fsid, sizeof(fsid));
2085 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
2086 for (i = 0; i < sizeof(buf.f_fsid); i++)
2087 snprintf(&fsid[i*2],
2088 sizeof(fsid) - (i*2), "%02x",
2089 ((u_char *)&buf.f_fsid)[i]);
2092 "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
2093 "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
2094 buf.f_mntfromname, fsid);
2096 fprintf(fp, "0x%lx", args[sc->offset]);
2103 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
2106 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
2107 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
2108 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
2109 ru.ru_inblock, ru.ru_oublock);
2111 fprintf(fp, "0x%lx", args[sc->offset]);
2117 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
2119 fprintf(fp, "{ cur=%ju,max=%ju }",
2120 rl.rlim_cur, rl.rlim_max);
2122 fprintf(fp, "0x%lx", args[sc->offset]);
2128 if (get_struct(pid, (void *)args[sc->offset], &status,
2129 sizeof(status)) != -1) {
2131 if (WIFCONTINUED(status))
2132 fputs("CONTINUED", fp);
2133 else if (WIFEXITED(status))
2134 fprintf(fp, "EXITED,val=%d",
2135 WEXITSTATUS(status));
2136 else if (WIFSIGNALED(status))
2137 fprintf(fp, "SIGNALED,sig=%s%s",
2138 strsig2(WTERMSIG(status)),
2139 WCOREDUMP(status) ? ",cored" : "");
2141 fprintf(fp, "STOPPED,sig=%s",
2142 strsig2(WTERMSIG(status)));
2145 fprintf(fp, "0x%lx", args[sc->offset]);
2149 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]);
2152 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]);
2155 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]);
2158 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]);
2161 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]);
2164 print_mask_arg(sysdecode_atflags, fp, args[sc->offset]);
2167 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]);
2170 print_integer_arg(sysdecode_sysarch_number, fp,
2175 * The pipe() system call in the kernel returns its
2176 * two file descriptors via return values. However,
2177 * the interface exposed by libc is that pipe()
2178 * accepts a pointer to an array of descriptors.
2179 * Format the output to match the libc API by printing
2180 * the returned file descriptors as a fake argument.
2182 * Overwrite the first retval to signal a successful
2185 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
2192 len = args[sc->offset + 1];
2193 utrace_addr = calloc(1, len);
2194 if (get_struct(pid, (void *)args[sc->offset],
2195 (void *)utrace_addr, len) != -1)
2196 print_utrace(fp, utrace_addr, len);
2198 fprintf(fp, "0x%lx", args[sc->offset]);
2203 int descriptors[16];
2204 unsigned long i, ndescriptors;
2207 ndescriptors = args[sc->offset + 1];
2209 if (ndescriptors > nitems(descriptors)) {
2210 ndescriptors = nitems(descriptors);
2213 if (get_struct(pid, (void *)args[sc->offset],
2214 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
2216 for (i = 0; i < ndescriptors; i++)
2217 fprintf(fp, i == 0 ? " %d" : ", %d",
2219 fprintf(fp, truncated ? ", ... }" : " }");
2221 fprintf(fp, "0x%lx", args[sc->offset]);
2225 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]);
2227 case CapFcntlRights: {
2230 if (sc->type & OUT) {
2231 if (get_struct(pid, (void *)args[sc->offset], &rights,
2232 sizeof(rights)) == -1) {
2233 fprintf(fp, "0x%lx", args[sc->offset]);
2237 rights = args[sc->offset];
2238 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights);
2242 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]);
2247 if (!sysdecode_fileflags(fp, args[sc->offset], &rem))
2248 fprintf(fp, "0x%x", rem);
2250 fprintf(fp, "|0x%x", rem);
2254 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]);
2257 print_integer_arg(sysdecode_getfsstat_mode, fp,
2261 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]);
2263 case Kldunloadflags:
2264 print_integer_arg(sysdecode_kldunload_flags, fp,
2268 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]);
2271 fprintf(fp, "%u", (socklen_t)args[sc->offset]);
2273 case Sockprotocol: {
2275 int domain, protocol;
2277 domain = args[sc->offset - 2];
2278 protocol = args[sc->offset];
2279 if (protocol == 0) {
2282 temp = sysdecode_socket_protocol(domain, protocol);
2286 fprintf(fp, "%d", protocol);
2292 print_integer_arg(sysdecode_sockopt_level, fp,
2299 level = args[sc->offset - 1];
2300 name = args[sc->offset];
2301 temp = sysdecode_sockopt_name(level, name);
2305 fprintf(fp, "%d", name);
2310 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]);
2313 cap_rights_t rights;
2315 if (get_struct(pid, (void *)args[sc->offset], &rights,
2316 sizeof(rights)) != -1) {
2318 sysdecode_cap_rights(fp, &rights);
2321 fprintf(fp, "0x%lx", args[sc->offset]);
2325 print_integer_arg(sysdecode_acltype, fp, args[sc->offset]);
2327 case Extattrnamespace:
2328 print_integer_arg(sysdecode_extattrnamespace, fp,
2332 print_integer_arg(sysdecode_minherit_inherit, fp,
2336 print_mask_arg(sysdecode_mlockall_flags, fp, args[sc->offset]);
2339 print_mask_arg(sysdecode_mount_flags, fp, args[sc->offset]);
2342 print_mask_arg(sysdecode_msync_flags, fp, args[sc->offset]);
2345 print_integer_arg(sysdecode_prio_which, fp, args[sc->offset]);
2348 print_integer_arg(sysdecode_ptrace_request, fp,
2352 if (!sysdecode_quotactl_cmd(fp, args[sc->offset]))
2353 fprintf(fp, "%#x", (int)args[sc->offset]);
2356 print_mask_arg(sysdecode_reboot_howto, fp, args[sc->offset]);
2359 print_integer_arg(sysdecode_rtprio_function, fp,
2363 print_integer_arg(sysdecode_scheduler_policy, fp,
2367 struct sched_param sp;
2369 if (get_struct(pid, (void *)args[sc->offset], &sp,
2371 fprintf(fp, "{ %d }", sp.sched_priority);
2373 fprintf(fp, "0x%lx", args[sc->offset]);
2379 if (get_struct(pid, (void *)args[sc->offset], &sig,
2381 fprintf(fp, "{ %s }", strsig2(sig));
2383 fprintf(fp, "0x%lx", args[sc->offset]);
2389 if (get_struct(pid, (void *)args[sc->offset], &si,
2390 sizeof(si)) != -1) {
2391 fprintf(fp, "{ signo=%s", strsig2(si.si_signo));
2392 decode_siginfo(fp, &si);
2395 fprintf(fp, "0x%lx", args[sc->offset]);
2400 * Print argument as an array of struct iovec, where the next
2401 * syscall argument is the number of elements of the array.
2404 print_iovec(fp, trussinfo, (void *)args[sc->offset],
2405 (int)args[sc->offset + 1]);
2407 case Sctpsndrcvinfo: {
2408 struct sctp_sndrcvinfo info;
2410 if (get_struct(pid, (void *)args[sc->offset],
2411 &info, sizeof(struct sctp_sndrcvinfo)) == -1) {
2412 fprintf(fp, "0x%lx", args[sc->offset]);
2415 print_sctp_sndrcvinfo(fp, sc->type & OUT, &info);
2419 struct msghdr msghdr;
2421 if (get_struct(pid, (void *)args[sc->offset],
2422 &msghdr, sizeof(struct msghdr)) == -1) {
2423 fprintf(fp, "0x%lx", args[sc->offset]);
2427 print_sockaddr(fp, trussinfo, msghdr.msg_name, msghdr.msg_namelen);
2428 fprintf(fp, ",%d,", msghdr.msg_namelen);
2429 print_iovec(fp, trussinfo, msghdr.msg_iov, msghdr.msg_iovlen);
2430 fprintf(fp, ",%d,", msghdr.msg_iovlen);
2431 print_cmsgs(fp, pid, sc->type & OUT, &msghdr);
2432 fprintf(fp, ",%u,", msghdr.msg_controllen);
2433 print_mask_arg(sysdecode_msg_flags, fp, msghdr.msg_flags);
2438 case CloudABIAdvice:
2439 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
2441 case CloudABIClockID:
2442 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2444 case ClouduABIFDSFlags:
2445 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2447 case CloudABIFDStat: {
2448 cloudabi_fdstat_t fds;
2449 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds))
2451 fprintf(fp, "{ %s, ",
2452 xlookup(cloudabi_filetype, fds.fs_filetype));
2453 fprintf(fp, "%s, ... }",
2454 xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2456 fprintf(fp, "0x%lx", args[sc->offset]);
2459 case CloudABIFileStat: {
2460 cloudabi_filestat_t fsb;
2461 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb))
2463 fprintf(fp, "{ %s, %ju }",
2464 xlookup(cloudabi_filetype, fsb.st_filetype),
2465 (uintmax_t)fsb.st_size);
2467 fprintf(fp, "0x%lx", args[sc->offset]);
2470 case CloudABIFileType:
2471 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2473 case CloudABIFSFlags:
2474 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2476 case CloudABILookup:
2477 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2478 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2479 (int)args[sc->offset]);
2481 fprintf(fp, "%d", (int)args[sc->offset]);
2483 case CloudABIMFlags:
2484 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2487 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2489 case CloudABIMSFlags:
2490 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2492 case CloudABIOFlags:
2493 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2495 case CloudABISDFlags:
2496 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2498 case CloudABISignal:
2499 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2501 case CloudABITimestamp:
2502 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2503 args[sc->offset] % 1000000000);
2505 case CloudABIULFlags:
2506 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2508 case CloudABIWhence:
2509 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2513 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2520 * Print (to outfile) the system call and its arguments.
2523 print_syscall(struct trussinfo *trussinfo)
2525 struct threadinfo *t;
2530 t = trussinfo->curthread;
2532 name = t->cs.sc->name;
2533 nargs = t->cs.nargs;
2534 s_args = t->cs.s_args;
2536 len = print_line_prefix(trussinfo);
2537 len += fprintf(trussinfo->outfile, "%s(", name);
2539 for (i = 0; i < nargs; i++) {
2540 if (s_args[i] != NULL)
2541 len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2543 len += fprintf(trussinfo->outfile,
2544 "<missing argument>");
2545 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2548 len += fprintf(trussinfo->outfile, ")");
2549 for (i = 0; i < 6 - (len / 8); i++)
2550 fprintf(trussinfo->outfile, "\t");
2554 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
2556 struct timespec timediff;
2557 struct threadinfo *t;
2561 t = trussinfo->curthread;
2563 if (trussinfo->flags & COUNTONLY) {
2564 timespecsubt(&t->after, &t->before, &timediff);
2565 timespecadd(&sc->time, &timediff, &sc->time);
2572 print_syscall(trussinfo);
2573 fflush(trussinfo->outfile);
2575 if (retval == NULL) {
2577 * This system call resulted in the current thread's exit,
2578 * so there is no return value or error to display.
2580 fprintf(trussinfo->outfile, "\n");
2585 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi,
2587 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
2588 error == INT_MAX ? "Unknown error" : strerror(error));
2591 else if (sc->ret_type == 2) {
2594 #if _BYTE_ORDER == _LITTLE_ENDIAN
2595 off = (off_t)retval[1] << 32 | retval[0];
2597 off = (off_t)retval[0] << 32 | retval[1];
2599 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2604 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
2609 print_summary(struct trussinfo *trussinfo)
2611 struct timespec total = {0, 0};
2615 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2616 "syscall", "seconds", "calls", "errors");
2618 STAILQ_FOREACH(sc, &syscalls, entries)
2620 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2621 sc->name, (intmax_t)sc->time.tv_sec,
2622 sc->time.tv_nsec, sc->ncalls, sc->nerror);
2623 timespecadd(&total, &sc->time, &total);
2624 ncall += sc->ncalls;
2625 nerror += sc->nerror;
2627 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2628 "", "-------------", "-------", "-------");
2629 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2630 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);