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 receive, 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 receive, 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, receive,
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 receive, 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, receive, cmsghdr);
1513 print_gen_cmsg(fp, cmsghdr);
1524 * Converts a syscall argument into a string. Said string is
1525 * allocated via malloc(), so needs to be free()'d. sc is
1526 * a pointer to the syscall description (see above); args is
1527 * an array of all of the system call arguments.
1530 print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
1531 struct trussinfo *trussinfo)
1538 fp = open_memstream(&tmp, &tmplen);
1539 pid = trussinfo->curthread->proc->pid;
1540 switch (sc->type & ARG_MASK) {
1542 fprintf(fp, "0x%x", (int)args[sc->offset]);
1545 fprintf(fp, "0%o", (int)args[sc->offset]);
1548 fprintf(fp, "%d", (int)args[sc->offset]);
1551 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1556 if (get_struct(pid, (void *)args[sc->offset], &val,
1558 fprintf(fp, "{ %u }", val);
1560 fprintf(fp, "0x%lx", args[sc->offset]);
1564 fprintf(fp, "0x%lx", args[sc->offset]);
1567 fprintf(fp, "%ld", args[sc->offset]);
1570 fprintf(fp, "%zu", (size_t)args[sc->offset]);
1573 /* NULL-terminated string. */
1576 tmp2 = get_string(pid, (void*)args[sc->offset], 0);
1577 fprintf(fp, "\"%s\"", tmp2);
1583 * Binary block of data that might have printable characters.
1584 * XXX If type|OUT, assume that the length is the syscall's
1585 * return value. Otherwise, assume that the length of the block
1586 * is in the next syscall argument.
1588 int max_string = trussinfo->strsize;
1589 char tmp2[max_string + 1], *tmp3;
1596 len = args[sc->offset + 1];
1599 * Don't print more than max_string characters, to avoid word
1600 * wrap. If we have to truncate put some ... after the string.
1602 if (len > max_string) {
1606 if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
1608 tmp3 = malloc(len * 4 + 1);
1610 if (strvisx(tmp3, tmp2, len,
1611 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1616 fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1620 fprintf(fp, "0x%lx", args[sc->offset]);
1630 char buf[PAGE_SIZE];
1637 * Only parse argv[] and environment arrays from exec calls
1640 if (((sc->type & ARG_MASK) == ExecArgs &&
1641 (trussinfo->flags & EXECVEARGS) == 0) ||
1642 ((sc->type & ARG_MASK) == ExecEnv &&
1643 (trussinfo->flags & EXECVEENVS) == 0)) {
1644 fprintf(fp, "0x%lx", args[sc->offset]);
1649 * Read a page of pointers at a time. Punt if the top-level
1650 * pointer is not aligned. Note that the first read is of
1653 addr = args[sc->offset];
1654 if (addr % sizeof(char *) != 0) {
1655 fprintf(fp, "0x%lx", args[sc->offset]);
1659 len = PAGE_SIZE - (addr & PAGE_MASK);
1660 if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
1661 fprintf(fp, "0x%lx", args[sc->offset]);
1668 while (u.strarray[i] != NULL) {
1669 string = get_string(pid, u.strarray[i], 0);
1670 fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1675 if (i == len / sizeof(char *)) {
1678 if (get_struct(pid, (void *)addr, u.buf, len) ==
1680 fprintf(fp, ", <inval>");
1691 fprintf(fp, "%ld", args[sc->offset]);
1694 fprintf(fp, "0x%lx", args[sc->offset]);
1699 unsigned long long ll;
1701 #if _BYTE_ORDER == _LITTLE_ENDIAN
1702 ll = (unsigned long long)args[sc->offset + 1] << 32 |
1705 ll = (unsigned long long)args[sc->offset] << 32 |
1706 args[sc->offset + 1];
1708 if ((sc->type & ARG_MASK) == Quad)
1709 fprintf(fp, "%lld", ll);
1711 fprintf(fp, "0x%llx", ll);
1718 if (get_struct(pid, (void *)args[sc->offset], &val,
1720 fprintf(fp, "{ 0x%jx }", (uintmax_t)val);
1722 fprintf(fp, "0x%lx", args[sc->offset]);
1726 fprintf(fp, "0x%lx", args[sc->offset]);
1731 if (retval[0] == -1)
1733 tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
1734 fprintf(fp, "\"%s\"", tmp2);
1742 cmd = args[sc->offset];
1743 temp = sysdecode_ioctlname(cmd);
1747 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1748 cmd, cmd & IOC_OUT ? "R" : "",
1749 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1750 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1751 cmd & 0xFF, IOCPARM_LEN(cmd));
1758 if (get_struct(pid, (void *)args[sc->offset], &ts,
1760 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1763 fprintf(fp, "0x%lx", args[sc->offset]);
1767 struct timespec ts[2];
1771 if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
1775 for (i = 0; i < nitems(ts); i++) {
1778 switch (ts[i].tv_nsec) {
1780 fprintf(fp, "UTIME_NOW");
1783 fprintf(fp, "UTIME_OMIT");
1786 fprintf(fp, "%jd.%09ld",
1787 (intmax_t)ts[i].tv_sec,
1794 fprintf(fp, "0x%lx", args[sc->offset]);
1800 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1802 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1805 fprintf(fp, "0x%lx", args[sc->offset]);
1809 struct timeval tv[2];
1811 if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1813 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1814 (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1815 (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1817 fprintf(fp, "0x%lx", args[sc->offset]);
1821 struct itimerval itv;
1823 if (get_struct(pid, (void *)args[sc->offset], &itv,
1825 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1826 (intmax_t)itv.it_interval.tv_sec,
1827 itv.it_interval.tv_usec,
1828 (intmax_t)itv.it_value.tv_sec,
1829 itv.it_value.tv_usec);
1831 fprintf(fp, "0x%lx", args[sc->offset]);
1836 struct linux_socketcall_args largs;
1838 if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
1839 sizeof(largs)) != -1)
1840 fprintf(fp, "{ %s, 0x%lx }",
1841 lookup(linux_socketcall_ops, largs.what, 10),
1842 (long unsigned int)largs.args);
1844 fprintf(fp, "0x%lx", args[sc->offset]);
1849 * XXX: A Pollfd argument expects the /next/ syscall argument
1850 * to be the number of fds in the array. This matches the poll
1854 int numfds = args[sc->offset + 1];
1855 size_t bytes = sizeof(struct pollfd) * numfds;
1858 if ((pfd = malloc(bytes)) == NULL)
1859 err(1, "Cannot malloc %zu bytes for pollfd array",
1861 if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
1864 for (i = 0; i < numfds; i++) {
1865 fprintf(fp, " %d/%s", pfd[i].fd,
1866 xlookup_bits(poll_flags, pfd[i].events));
1870 fprintf(fp, "0x%lx", args[sc->offset]);
1877 * XXX: A Fd_set argument expects the /first/ syscall argument
1878 * to be the number of fds in the array. This matches the
1882 int numfds = args[0];
1883 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1886 if ((fds = malloc(bytes)) == NULL)
1887 err(1, "Cannot malloc %zu bytes for fd_set array",
1889 if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
1892 for (i = 0; i < numfds; i++) {
1893 if (FD_ISSET(i, fds))
1894 fprintf(fp, " %d", i);
1898 fprintf(fp, "0x%lx", args[sc->offset]);
1903 fputs(strsig2(args[sc->offset]), fp);
1910 sig = args[sc->offset];
1911 if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
1912 sizeof(ss)) == -1) {
1913 fprintf(fp, "0x%lx", args[sc->offset]);
1918 for (i = 1; i < sys_nsig; i++) {
1919 if (sigismember(&ss, i)) {
1920 fprintf(fp, "%s%s", !first ? "|" : "",
1931 print_integer_arg(sysdecode_sigprocmask_how, fp,
1935 /* XXX: Output depends on the value of the previous argument. */
1936 if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
1937 sysdecode_fcntl_arg(fp, args[sc->offset - 1],
1938 args[sc->offset], 16);
1941 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
1944 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
1947 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
1950 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
1953 print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
1956 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
1959 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
1962 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
1965 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
1968 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]);
1971 print_integer_arg(sysdecode_pathconf_name, fp, args[sc->offset]);
1974 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
1979 if (args[sc->offset] == 0) {
1985 * Extract the address length from the next argument. If
1986 * this is an output sockaddr (OUT is set), then the
1987 * next argument is a pointer to a socklen_t. Otherwise
1988 * the next argument contains a socklen_t by value.
1990 if (sc->type & OUT) {
1991 if (get_struct(pid, (void *)args[sc->offset + 1],
1992 &len, sizeof(len)) == -1) {
1993 fprintf(fp, "0x%lx", args[sc->offset]);
1997 len = args[sc->offset + 1];
1999 print_sockaddr(fp, trussinfo, (void *)args[sc->offset], len);
2003 struct sigaction sa;
2005 if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
2008 if (sa.sa_handler == SIG_DFL)
2009 fputs("SIG_DFL", fp);
2010 else if (sa.sa_handler == SIG_IGN)
2011 fputs("SIG_IGN", fp);
2013 fprintf(fp, "%p", sa.sa_handler);
2014 fprintf(fp, " %s ss_t }",
2015 xlookup_bits(sigaction_flags, sa.sa_flags));
2017 fprintf(fp, "0x%lx", args[sc->offset]);
2022 * XXX XXX: The size of the array is determined by either the
2023 * next syscall argument, or by the syscall return value,
2024 * depending on which argument number we are. This matches the
2025 * kevent syscall, but luckily that's the only syscall that uses
2033 if (sc->offset == 1)
2034 numevents = args[sc->offset+1];
2035 else if (sc->offset == 3 && retval[0] != -1)
2036 numevents = retval[0];
2038 if (numevents >= 0) {
2039 bytes = sizeof(struct kevent) * numevents;
2040 if ((ke = malloc(bytes)) == NULL)
2042 "Cannot malloc %zu bytes for kevent array",
2046 if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
2049 for (i = 0; i < numevents; i++) {
2051 print_kevent(fp, &ke[i]);
2055 fprintf(fp, "0x%lx", args[sc->offset]);
2063 if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
2067 strmode(st.st_mode, mode);
2069 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
2070 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
2071 (long)st.st_blksize);
2073 fprintf(fp, "0x%lx", args[sc->offset]);
2081 if (get_struct(pid, (void *)args[sc->offset], &buf,
2082 sizeof(buf)) != -1) {
2085 bzero(fsid, sizeof(fsid));
2086 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
2087 for (i = 0; i < sizeof(buf.f_fsid); i++)
2088 snprintf(&fsid[i*2],
2089 sizeof(fsid) - (i*2), "%02x",
2090 ((u_char *)&buf.f_fsid)[i]);
2093 "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
2094 "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
2095 buf.f_mntfromname, fsid);
2097 fprintf(fp, "0x%lx", args[sc->offset]);
2104 if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
2107 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
2108 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
2109 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
2110 ru.ru_inblock, ru.ru_oublock);
2112 fprintf(fp, "0x%lx", args[sc->offset]);
2118 if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
2120 fprintf(fp, "{ cur=%ju,max=%ju }",
2121 rl.rlim_cur, rl.rlim_max);
2123 fprintf(fp, "0x%lx", args[sc->offset]);
2129 if (get_struct(pid, (void *)args[sc->offset], &status,
2130 sizeof(status)) != -1) {
2132 if (WIFCONTINUED(status))
2133 fputs("CONTINUED", fp);
2134 else if (WIFEXITED(status))
2135 fprintf(fp, "EXITED,val=%d",
2136 WEXITSTATUS(status));
2137 else if (WIFSIGNALED(status))
2138 fprintf(fp, "SIGNALED,sig=%s%s",
2139 strsig2(WTERMSIG(status)),
2140 WCOREDUMP(status) ? ",cored" : "");
2142 fprintf(fp, "STOPPED,sig=%s",
2143 strsig2(WTERMSIG(status)));
2146 fprintf(fp, "0x%lx", args[sc->offset]);
2150 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]);
2153 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]);
2156 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]);
2159 print_integer_arg(sysdecode_umtx_op, fp, args[sc->offset]);
2162 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]);
2165 print_mask_arg(sysdecode_atflags, fp, args[sc->offset]);
2168 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]);
2171 print_integer_arg(sysdecode_sysarch_number, fp,
2176 * The pipe() system call in the kernel returns its
2177 * two file descriptors via return values. However,
2178 * the interface exposed by libc is that pipe()
2179 * accepts a pointer to an array of descriptors.
2180 * Format the output to match the libc API by printing
2181 * the returned file descriptors as a fake argument.
2183 * Overwrite the first retval to signal a successful
2186 fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
2193 len = args[sc->offset + 1];
2194 utrace_addr = calloc(1, len);
2195 if (get_struct(pid, (void *)args[sc->offset],
2196 (void *)utrace_addr, len) != -1)
2197 print_utrace(fp, utrace_addr, len);
2199 fprintf(fp, "0x%lx", args[sc->offset]);
2204 int descriptors[16];
2205 unsigned long i, ndescriptors;
2208 ndescriptors = args[sc->offset + 1];
2210 if (ndescriptors > nitems(descriptors)) {
2211 ndescriptors = nitems(descriptors);
2214 if (get_struct(pid, (void *)args[sc->offset],
2215 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
2217 for (i = 0; i < ndescriptors; i++)
2218 fprintf(fp, i == 0 ? " %d" : ", %d",
2220 fprintf(fp, truncated ? ", ... }" : " }");
2222 fprintf(fp, "0x%lx", args[sc->offset]);
2226 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]);
2228 case CapFcntlRights: {
2231 if (sc->type & OUT) {
2232 if (get_struct(pid, (void *)args[sc->offset], &rights,
2233 sizeof(rights)) == -1) {
2234 fprintf(fp, "0x%lx", args[sc->offset]);
2238 rights = args[sc->offset];
2239 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights);
2243 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]);
2248 if (!sysdecode_fileflags(fp, args[sc->offset], &rem))
2249 fprintf(fp, "0x%x", rem);
2251 fprintf(fp, "|0x%x", rem);
2255 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]);
2258 print_integer_arg(sysdecode_getfsstat_mode, fp,
2262 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]);
2264 case Kldunloadflags:
2265 print_integer_arg(sysdecode_kldunload_flags, fp,
2269 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]);
2272 fprintf(fp, "%u", (socklen_t)args[sc->offset]);
2274 case Sockprotocol: {
2276 int domain, protocol;
2278 domain = args[sc->offset - 2];
2279 protocol = args[sc->offset];
2280 if (protocol == 0) {
2283 temp = sysdecode_socket_protocol(domain, protocol);
2287 fprintf(fp, "%d", protocol);
2293 print_integer_arg(sysdecode_sockopt_level, fp,
2300 level = args[sc->offset - 1];
2301 name = args[sc->offset];
2302 temp = sysdecode_sockopt_name(level, name);
2306 fprintf(fp, "%d", name);
2311 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]);
2314 cap_rights_t rights;
2316 if (get_struct(pid, (void *)args[sc->offset], &rights,
2317 sizeof(rights)) != -1) {
2319 sysdecode_cap_rights(fp, &rights);
2322 fprintf(fp, "0x%lx", args[sc->offset]);
2326 print_integer_arg(sysdecode_acltype, fp, args[sc->offset]);
2328 case Extattrnamespace:
2329 print_integer_arg(sysdecode_extattrnamespace, fp,
2333 print_integer_arg(sysdecode_minherit_inherit, fp,
2337 print_mask_arg(sysdecode_mlockall_flags, fp, args[sc->offset]);
2340 print_mask_arg(sysdecode_mount_flags, fp, args[sc->offset]);
2343 print_mask_arg(sysdecode_msync_flags, fp, args[sc->offset]);
2346 print_integer_arg(sysdecode_prio_which, fp, args[sc->offset]);
2349 print_integer_arg(sysdecode_ptrace_request, fp,
2353 if (!sysdecode_quotactl_cmd(fp, args[sc->offset]))
2354 fprintf(fp, "%#x", (int)args[sc->offset]);
2357 print_mask_arg(sysdecode_reboot_howto, fp, args[sc->offset]);
2360 print_integer_arg(sysdecode_rtprio_function, fp,
2364 print_integer_arg(sysdecode_scheduler_policy, fp,
2368 struct sched_param sp;
2370 if (get_struct(pid, (void *)args[sc->offset], &sp,
2372 fprintf(fp, "{ %d }", sp.sched_priority);
2374 fprintf(fp, "0x%lx", args[sc->offset]);
2380 if (get_struct(pid, (void *)args[sc->offset], &sig,
2382 fprintf(fp, "{ %s }", strsig2(sig));
2384 fprintf(fp, "0x%lx", args[sc->offset]);
2390 if (get_struct(pid, (void *)args[sc->offset], &si,
2391 sizeof(si)) != -1) {
2392 fprintf(fp, "{ signo=%s", strsig2(si.si_signo));
2393 decode_siginfo(fp, &si);
2396 fprintf(fp, "0x%lx", args[sc->offset]);
2401 * Print argument as an array of struct iovec, where the next
2402 * syscall argument is the number of elements of the array.
2405 print_iovec(fp, trussinfo, (void *)args[sc->offset],
2406 (int)args[sc->offset + 1]);
2408 case Sctpsndrcvinfo: {
2409 struct sctp_sndrcvinfo info;
2411 if (get_struct(pid, (void *)args[sc->offset],
2412 &info, sizeof(struct sctp_sndrcvinfo)) == -1) {
2413 fprintf(fp, "0x%lx", args[sc->offset]);
2416 print_sctp_sndrcvinfo(fp, sc->type & OUT, &info);
2420 struct msghdr msghdr;
2422 if (get_struct(pid, (void *)args[sc->offset],
2423 &msghdr, sizeof(struct msghdr)) == -1) {
2424 fprintf(fp, "0x%lx", args[sc->offset]);
2428 print_sockaddr(fp, trussinfo, msghdr.msg_name, msghdr.msg_namelen);
2429 fprintf(fp, ",%d,", msghdr.msg_namelen);
2430 print_iovec(fp, trussinfo, msghdr.msg_iov, msghdr.msg_iovlen);
2431 fprintf(fp, ",%d,", msghdr.msg_iovlen);
2432 print_cmsgs(fp, pid, sc->type & OUT, &msghdr);
2433 fprintf(fp, ",%u,", msghdr.msg_controllen);
2434 print_mask_arg(sysdecode_msg_flags, fp, msghdr.msg_flags);
2439 case CloudABIAdvice:
2440 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
2442 case CloudABIClockID:
2443 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2445 case ClouduABIFDSFlags:
2446 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2448 case CloudABIFDStat: {
2449 cloudabi_fdstat_t fds;
2450 if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds))
2452 fprintf(fp, "{ %s, ",
2453 xlookup(cloudabi_filetype, fds.fs_filetype));
2454 fprintf(fp, "%s, ... }",
2455 xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2457 fprintf(fp, "0x%lx", args[sc->offset]);
2460 case CloudABIFileStat: {
2461 cloudabi_filestat_t fsb;
2462 if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb))
2464 fprintf(fp, "{ %s, %ju }",
2465 xlookup(cloudabi_filetype, fsb.st_filetype),
2466 (uintmax_t)fsb.st_size);
2468 fprintf(fp, "0x%lx", args[sc->offset]);
2471 case CloudABIFileType:
2472 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2474 case CloudABIFSFlags:
2475 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2477 case CloudABILookup:
2478 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2479 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2480 (int)args[sc->offset]);
2482 fprintf(fp, "%d", (int)args[sc->offset]);
2484 case CloudABIMFlags:
2485 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2488 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2490 case CloudABIMSFlags:
2491 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2493 case CloudABIOFlags:
2494 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2496 case CloudABISDFlags:
2497 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2499 case CloudABISignal:
2500 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2502 case CloudABITimestamp:
2503 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2504 args[sc->offset] % 1000000000);
2506 case CloudABIULFlags:
2507 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2509 case CloudABIWhence:
2510 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2514 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2521 * Print (to outfile) the system call and its arguments.
2524 print_syscall(struct trussinfo *trussinfo)
2526 struct threadinfo *t;
2531 t = trussinfo->curthread;
2533 name = t->cs.sc->name;
2534 nargs = t->cs.nargs;
2535 s_args = t->cs.s_args;
2537 len = print_line_prefix(trussinfo);
2538 len += fprintf(trussinfo->outfile, "%s(", name);
2540 for (i = 0; i < nargs; i++) {
2541 if (s_args[i] != NULL)
2542 len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2544 len += fprintf(trussinfo->outfile,
2545 "<missing argument>");
2546 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2549 len += fprintf(trussinfo->outfile, ")");
2550 for (i = 0; i < 6 - (len / 8); i++)
2551 fprintf(trussinfo->outfile, "\t");
2555 print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
2557 struct timespec timediff;
2558 struct threadinfo *t;
2562 t = trussinfo->curthread;
2564 if (trussinfo->flags & COUNTONLY) {
2565 timespecsubt(&t->after, &t->before, &timediff);
2566 timespecadd(&sc->time, &timediff, &sc->time);
2573 print_syscall(trussinfo);
2574 fflush(trussinfo->outfile);
2576 if (retval == NULL) {
2578 * This system call resulted in the current thread's exit,
2579 * so there is no return value or error to display.
2581 fprintf(trussinfo->outfile, "\n");
2586 error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi,
2588 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
2589 error == INT_MAX ? "Unknown error" : strerror(error));
2592 else if (sc->ret_type == 2) {
2595 #if _BYTE_ORDER == _LITTLE_ENDIAN
2596 off = (off_t)retval[1] << 32 | retval[0];
2598 off = (off_t)retval[0] << 32 | retval[1];
2600 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2605 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
2610 print_summary(struct trussinfo *trussinfo)
2612 struct timespec total = {0, 0};
2616 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2617 "syscall", "seconds", "calls", "errors");
2619 STAILQ_FOREACH(sc, &syscalls, entries)
2621 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2622 sc->name, (intmax_t)sc->time.tv_sec,
2623 sc->time.tv_nsec, sc->ncalls, sc->nerror);
2624 timespecadd(&total, &sc->time, &total);
2625 ncall += sc->ncalls;
2626 nerror += sc->nerror;
2628 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2629 "", "-------------", "-------", "-------");
2630 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2631 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);