2 * SPDX-License-Identifier: BSD-4-Clause
4 * Copyright 1997 Sean Eric Fagan
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Sean Eric Fagan
17 * 4. Neither the name of the author may be used to endorse or promote
18 * products derived from this software without specific prior written
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
36 * This file has routines used to print out system calls and their
41 #include <sys/capsicum.h>
42 #include <sys/types.h>
43 #define _WANT_FREEBSD11_KEVENT
44 #include <sys/event.h>
45 #include <sys/ioccom.h>
47 #include <sys/mount.h>
49 #include <sys/procfs.h>
50 #include <sys/ptrace.h>
51 #include <sys/resource.h>
52 #include <sys/sched.h>
53 #include <sys/socket.h>
54 #define _WANT_FREEBSD11_STAT
56 #include <sys/sysctl.h>
60 #include <netinet/in.h>
61 #include <netinet/sctp.h>
62 #include <arpa/inet.h>
67 #define _WANT_KERNEL_ERRNO
75 #include <sysdecode.h>
79 #include <contrib/cloudabi/cloudabi_types_common.h>
86 * This should probably be in its own file, sorted alphabetically.
88 * Note: We only scan this table on the initial syscall number to calling
89 * convention lookup, i.e. once each time a new syscall is encountered. This
90 * is unlikely to be a performance issue, but if it is we could sort this array
91 * and use a binary search instead.
93 static const struct syscall_decode decoded_syscalls[] = {
95 { .name = "__acl_aclcheck_fd", .ret_type = 1, .nargs = 3,
96 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
97 { .name = "__acl_aclcheck_file", .ret_type = 1, .nargs = 3,
98 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
99 { .name = "__acl_aclcheck_link", .ret_type = 1, .nargs = 3,
100 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
101 { .name = "__acl_delete_fd", .ret_type = 1, .nargs = 2,
102 .args = { { Int, 0 }, { Acltype, 1 } } },
103 { .name = "__acl_delete_file", .ret_type = 1, .nargs = 2,
104 .args = { { Name, 0 }, { Acltype, 1 } } },
105 { .name = "__acl_delete_link", .ret_type = 1, .nargs = 2,
106 .args = { { Name, 0 }, { Acltype, 1 } } },
107 { .name = "__acl_get_fd", .ret_type = 1, .nargs = 3,
108 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
109 { .name = "__acl_get_file", .ret_type = 1, .nargs = 3,
110 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
111 { .name = "__acl_get_link", .ret_type = 1, .nargs = 3,
112 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
113 { .name = "__acl_set_fd", .ret_type = 1, .nargs = 3,
114 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
115 { .name = "__acl_set_file", .ret_type = 1, .nargs = 3,
116 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
117 { .name = "__acl_set_link", .ret_type = 1, .nargs = 3,
118 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
119 { .name = "__cap_rights_get", .ret_type = 1, .nargs = 3,
120 .args = { { Int, 0 }, { Int, 1 }, { CapRights | OUT, 2 } } },
121 { .name = "__getcwd", .ret_type = 1, .nargs = 2,
122 .args = { { Name | OUT, 0 }, { Int, 1 } } },
123 { .name = "__realpathat", .ret_type = 1, .nargs = 5,
124 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Name | OUT, 2 },
125 { Sizet, 3 }, { Int, 4} } },
126 { .name = "_umtx_op", .ret_type = 1, .nargs = 5,
127 .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
129 { .name = "accept", .ret_type = 1, .nargs = 3,
130 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
131 { .name = "access", .ret_type = 1, .nargs = 2,
132 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
133 { .name = "aio_cancel", .ret_type = 1, .nargs = 2,
134 .args = { { Int, 0 }, { Aiocb, 1 } } },
135 { .name = "aio_error", .ret_type = 1, .nargs = 1,
136 .args = { { Aiocb, 0 } } },
137 { .name = "aio_fsync", .ret_type = 1, .nargs = 2,
138 .args = { { AiofsyncOp, 0 }, { Aiocb, 1 } } },
139 { .name = "aio_mlock", .ret_type = 1, .nargs = 1,
140 .args = { { Aiocb, 0 } } },
141 { .name = "aio_read", .ret_type = 1, .nargs = 1,
142 .args = { { Aiocb, 0 } } },
143 { .name = "aio_return", .ret_type = 1, .nargs = 1,
144 .args = { { Aiocb, 0 } } },
145 { .name = "aio_suspend", .ret_type = 1, .nargs = 3,
146 .args = { { AiocbArray, 0 }, { Int, 1 }, { Timespec, 2 } } },
147 { .name = "aio_waitcomplete", .ret_type = 1, .nargs = 2,
148 .args = { { AiocbPointer | OUT, 0 }, { Timespec, 1 } } },
149 { .name = "aio_write", .ret_type = 1, .nargs = 1,
150 .args = { { Aiocb, 0 } } },
151 { .name = "bind", .ret_type = 1, .nargs = 3,
152 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
153 { .name = "bindat", .ret_type = 1, .nargs = 4,
154 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
156 { .name = "break", .ret_type = 1, .nargs = 1,
157 .args = { { Ptr, 0 } } },
158 { .name = "cap_fcntls_get", .ret_type = 1, .nargs = 2,
159 .args = { { Int, 0 }, { CapFcntlRights | OUT, 1 } } },
160 { .name = "cap_fcntls_limit", .ret_type = 1, .nargs = 2,
161 .args = { { Int, 0 }, { CapFcntlRights, 1 } } },
162 { .name = "cap_getmode", .ret_type = 1, .nargs = 1,
163 .args = { { PUInt | OUT, 0 } } },
164 { .name = "cap_rights_limit", .ret_type = 1, .nargs = 2,
165 .args = { { Int, 0 }, { CapRights, 1 } } },
166 { .name = "chdir", .ret_type = 1, .nargs = 1,
167 .args = { { Name, 0 } } },
168 { .name = "chflags", .ret_type = 1, .nargs = 2,
169 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
170 { .name = "chflagsat", .ret_type = 1, .nargs = 4,
171 .args = { { Atfd, 0 }, { Name | IN, 1 }, { FileFlags, 2 },
173 { .name = "chmod", .ret_type = 1, .nargs = 2,
174 .args = { { Name, 0 }, { Octal, 1 } } },
175 { .name = "chown", .ret_type = 1, .nargs = 3,
176 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
177 { .name = "chroot", .ret_type = 1, .nargs = 1,
178 .args = { { Name, 0 } } },
179 { .name = "clock_gettime", .ret_type = 1, .nargs = 2,
180 .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
181 { .name = "close", .ret_type = 1, .nargs = 1,
182 .args = { { Int, 0 } } },
183 { .name = "closefrom", .ret_type = 1, .nargs = 1,
184 .args = { { Int, 0 } } },
185 { .name = "close_range", .ret_type = 1, .nargs = 3,
186 .args = { { Int, 0 }, { Int, 1 }, { Closerangeflags, 2 } } },
187 { .name = "compat11.fstat", .ret_type = 1, .nargs = 2,
188 .args = { { Int, 0 }, { Stat11 | OUT, 1 } } },
189 { .name = "compat11.fstatat", .ret_type = 1, .nargs = 4,
190 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat11 | OUT, 2 },
192 { .name = "compat11.kevent", .ret_type = 1, .nargs = 6,
193 .args = { { Int, 0 }, { Kevent11, 1 }, { Int, 2 },
194 { Kevent11 | OUT, 3 }, { Int, 4 }, { Timespec, 5 } } },
195 { .name = "compat11.lstat", .ret_type = 1, .nargs = 2,
196 .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } },
197 { .name = "compat11.mknod", .ret_type = 1, .nargs = 3,
198 .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
199 { .name = "compat11.mknodat", .ret_type = 1, .nargs = 4,
200 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
201 { .name = "compat11.stat", .ret_type = 1, .nargs = 2,
202 .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } },
203 { .name = "connect", .ret_type = 1, .nargs = 3,
204 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
205 { .name = "connectat", .ret_type = 1, .nargs = 4,
206 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
208 { .name = "dup", .ret_type = 1, .nargs = 1,
209 .args = { { Int, 0 } } },
210 { .name = "dup2", .ret_type = 1, .nargs = 2,
211 .args = { { Int, 0 }, { Int, 1 } } },
212 { .name = "eaccess", .ret_type = 1, .nargs = 2,
213 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
214 { .name = "execve", .ret_type = 1, .nargs = 3,
215 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
216 { ExecEnv | IN, 2 } } },
217 { .name = "exit", .ret_type = 0, .nargs = 1,
218 .args = { { Hex, 0 } } },
219 { .name = "extattr_delete_fd", .ret_type = 1, .nargs = 3,
220 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
221 { .name = "extattr_delete_file", .ret_type = 1, .nargs = 3,
222 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
223 { .name = "extattr_delete_link", .ret_type = 1, .nargs = 3,
224 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
225 { .name = "extattr_get_fd", .ret_type = 1, .nargs = 5,
226 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
227 { BinString | OUT, 3 }, { Sizet, 4 } } },
228 { .name = "extattr_get_file", .ret_type = 1, .nargs = 5,
229 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
230 { BinString | OUT, 3 }, { Sizet, 4 } } },
231 { .name = "extattr_get_link", .ret_type = 1, .nargs = 5,
232 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
233 { BinString | OUT, 3 }, { Sizet, 4 } } },
234 { .name = "extattr_list_fd", .ret_type = 1, .nargs = 4,
235 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
237 { .name = "extattr_list_file", .ret_type = 1, .nargs = 4,
238 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
240 { .name = "extattr_list_link", .ret_type = 1, .nargs = 4,
241 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
243 { .name = "extattr_set_fd", .ret_type = 1, .nargs = 5,
244 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
245 { BinString | IN, 3 }, { Sizet, 4 } } },
246 { .name = "extattr_set_file", .ret_type = 1, .nargs = 5,
247 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
248 { BinString | IN, 3 }, { Sizet, 4 } } },
249 { .name = "extattr_set_link", .ret_type = 1, .nargs = 5,
250 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
251 { BinString | IN, 3 }, { Sizet, 4 } } },
252 { .name = "extattrctl", .ret_type = 1, .nargs = 5,
253 .args = { { Name, 0 }, { Hex, 1 }, { Name, 2 },
254 { Extattrnamespace, 3 }, { Name, 4 } } },
255 { .name = "faccessat", .ret_type = 1, .nargs = 4,
256 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
258 { .name = "fchflags", .ret_type = 1, .nargs = 2,
259 .args = { { Int, 0 }, { FileFlags, 1 } } },
260 { .name = "fchmod", .ret_type = 1, .nargs = 2,
261 .args = { { Int, 0 }, { Octal, 1 } } },
262 { .name = "fchmodat", .ret_type = 1, .nargs = 4,
263 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
264 { .name = "fchown", .ret_type = 1, .nargs = 3,
265 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
266 { .name = "fchownat", .ret_type = 1, .nargs = 5,
267 .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
269 { .name = "fcntl", .ret_type = 1, .nargs = 3,
270 .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
271 { .name = "fdatasync", .ret_type = 1, .nargs = 1,
272 .args = { { Int, 0 } } },
273 { .name = "flock", .ret_type = 1, .nargs = 2,
274 .args = { { Int, 0 }, { Flockop, 1 } } },
275 { .name = "fstat", .ret_type = 1, .nargs = 2,
276 .args = { { Int, 0 }, { Stat | OUT, 1 } } },
277 { .name = "fstatat", .ret_type = 1, .nargs = 4,
278 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
280 { .name = "fstatfs", .ret_type = 1, .nargs = 2,
281 .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
282 { .name = "fsync", .ret_type = 1, .nargs = 1,
283 .args = { { Int, 0 } } },
284 { .name = "ftruncate", .ret_type = 1, .nargs = 2,
285 .args = { { Int | IN, 0 }, { QuadHex | IN, 1 } } },
286 { .name = "futimens", .ret_type = 1, .nargs = 2,
287 .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
288 { .name = "futimes", .ret_type = 1, .nargs = 2,
289 .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
290 { .name = "futimesat", .ret_type = 1, .nargs = 3,
291 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
292 { .name = "getdirentries", .ret_type = 1, .nargs = 4,
293 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
294 { PQuadHex | OUT, 3 } } },
295 { .name = "getfsstat", .ret_type = 1, .nargs = 3,
296 .args = { { Ptr, 0 }, { Long, 1 }, { Getfsstatmode, 2 } } },
297 { .name = "getitimer", .ret_type = 1, .nargs = 2,
298 .args = { { Itimerwhich, 0 }, { Itimerval | OUT, 2 } } },
299 { .name = "getpeername", .ret_type = 1, .nargs = 3,
300 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
301 { .name = "getpgid", .ret_type = 1, .nargs = 1,
302 .args = { { Int, 0 } } },
303 { .name = "getpriority", .ret_type = 1, .nargs = 2,
304 .args = { { Priowhich, 0 }, { Int, 1 } } },
305 { .name = "getrandom", .ret_type = 1, .nargs = 3,
306 .args = { { BinString | OUT, 0 }, { Sizet, 1 }, { UInt, 2 } } },
307 { .name = "getrlimit", .ret_type = 1, .nargs = 2,
308 .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
309 { .name = "getrusage", .ret_type = 1, .nargs = 2,
310 .args = { { RusageWho, 0 }, { Rusage | OUT, 1 } } },
311 { .name = "getsid", .ret_type = 1, .nargs = 1,
312 .args = { { Int, 0 } } },
313 { .name = "getsockname", .ret_type = 1, .nargs = 3,
314 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
315 { .name = "getsockopt", .ret_type = 1, .nargs = 5,
316 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
317 { Ptr | OUT, 3 }, { Ptr | OUT, 4 } } },
318 { .name = "gettimeofday", .ret_type = 1, .nargs = 2,
319 .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
320 { .name = "ioctl", .ret_type = 1, .nargs = 3,
321 .args = { { Int, 0 }, { Ioctl, 1 }, { Ptr, 2 } } },
322 { .name = "kevent", .ret_type = 1, .nargs = 6,
323 .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
324 { Int, 4 }, { Timespec, 5 } } },
325 { .name = "kill", .ret_type = 1, .nargs = 2,
326 .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
327 { .name = "kldfind", .ret_type = 1, .nargs = 1,
328 .args = { { Name | IN, 0 } } },
329 { .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
330 .args = { { Int, 0 } } },
331 { .name = "kldload", .ret_type = 1, .nargs = 1,
332 .args = { { Name | IN, 0 } } },
333 { .name = "kldnext", .ret_type = 1, .nargs = 1,
334 .args = { { Int, 0 } } },
335 { .name = "kldstat", .ret_type = 1, .nargs = 2,
336 .args = { { Int, 0 }, { Ptr, 1 } } },
337 { .name = "kldsym", .ret_type = 1, .nargs = 3,
338 .args = { { Int, 0 }, { Kldsymcmd, 1 }, { Ptr, 2 } } },
339 { .name = "kldunload", .ret_type = 1, .nargs = 1,
340 .args = { { Int, 0 } } },
341 { .name = "kldunloadf", .ret_type = 1, .nargs = 2,
342 .args = { { Int, 0 }, { Kldunloadflags, 1 } } },
343 { .name = "kse_release", .ret_type = 0, .nargs = 1,
344 .args = { { Timespec, 0 } } },
345 { .name = "lchflags", .ret_type = 1, .nargs = 2,
346 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
347 { .name = "lchmod", .ret_type = 1, .nargs = 2,
348 .args = { { Name, 0 }, { Octal, 1 } } },
349 { .name = "lchown", .ret_type = 1, .nargs = 3,
350 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
351 { .name = "link", .ret_type = 1, .nargs = 2,
352 .args = { { Name, 0 }, { Name, 1 } } },
353 { .name = "linkat", .ret_type = 1, .nargs = 5,
354 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
356 { .name = "lio_listio", .ret_type = 1, .nargs = 4,
357 .args = { { LioMode, 0 }, { AiocbArray, 1 }, { Int, 2 },
359 { .name = "listen", .ret_type = 1, .nargs = 2,
360 .args = { { Int, 0 }, { Int, 1 } } },
361 { .name = "lseek", .ret_type = 2, .nargs = 3,
362 .args = { { Int, 0 }, { QuadHex, 1 }, { Whence, 2 } } },
363 { .name = "lstat", .ret_type = 1, .nargs = 2,
364 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
365 { .name = "lutimes", .ret_type = 1, .nargs = 2,
366 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
367 { .name = "madvise", .ret_type = 1, .nargs = 3,
368 .args = { { Ptr, 0 }, { Sizet, 1 }, { Madvice, 2 } } },
369 { .name = "minherit", .ret_type = 1, .nargs = 3,
370 .args = { { Ptr, 0 }, { Sizet, 1 }, { Minherit, 2 } } },
371 { .name = "mkdir", .ret_type = 1, .nargs = 2,
372 .args = { { Name, 0 }, { Octal, 1 } } },
373 { .name = "mkdirat", .ret_type = 1, .nargs = 3,
374 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
375 { .name = "mkfifo", .ret_type = 1, .nargs = 2,
376 .args = { { Name, 0 }, { Octal, 1 } } },
377 { .name = "mkfifoat", .ret_type = 1, .nargs = 3,
378 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
379 { .name = "mknod", .ret_type = 1, .nargs = 3,
380 .args = { { Name, 0 }, { Octal, 1 }, { Quad, 2 } } },
381 { .name = "mknodat", .ret_type = 1, .nargs = 4,
382 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Quad, 3 } } },
383 { .name = "mlock", .ret_type = 1, .nargs = 2,
384 .args = { { Ptr, 0 }, { Sizet, 1 } } },
385 { .name = "mlockall", .ret_type = 1, .nargs = 1,
386 .args = { { Mlockall, 0 } } },
387 { .name = "mmap", .ret_type = 1, .nargs = 6,
388 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
389 { Int, 4 }, { QuadHex, 5 } } },
390 { .name = "modfind", .ret_type = 1, .nargs = 1,
391 .args = { { Name | IN, 0 } } },
392 { .name = "mount", .ret_type = 1, .nargs = 4,
393 .args = { { Name, 0 }, { Name, 1 }, { Mountflags, 2 }, { Ptr, 3 } } },
394 { .name = "mprotect", .ret_type = 1, .nargs = 3,
395 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 } } },
396 { .name = "msync", .ret_type = 1, .nargs = 3,
397 .args = { { Ptr, 0 }, { Sizet, 1 }, { Msync, 2 } } },
398 { .name = "munlock", .ret_type = 1, .nargs = 2,
399 .args = { { Ptr, 0 }, { Sizet, 1 } } },
400 { .name = "munmap", .ret_type = 1, .nargs = 2,
401 .args = { { Ptr, 0 }, { Sizet, 1 } } },
402 { .name = "nanosleep", .ret_type = 1, .nargs = 1,
403 .args = { { Timespec, 0 } } },
404 { .name = "nmount", .ret_type = 1, .nargs = 3,
405 .args = { { Ptr, 0 }, { UInt, 1 }, { Mountflags, 2 } } },
406 { .name = "open", .ret_type = 1, .nargs = 3,
407 .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
408 { .name = "openat", .ret_type = 1, .nargs = 4,
409 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
411 { .name = "pathconf", .ret_type = 1, .nargs = 2,
412 .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
413 { .name = "pipe", .ret_type = 1, .nargs = 1,
414 .args = { { PipeFds | OUT, 0 } } },
415 { .name = "pipe2", .ret_type = 1, .nargs = 2,
416 .args = { { Ptr, 0 }, { Pipe2, 1 } } },
417 { .name = "poll", .ret_type = 1, .nargs = 3,
418 .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
419 { .name = "posix_fadvise", .ret_type = 1, .nargs = 4,
420 .args = { { Int, 0 }, { QuadHex, 1 }, { QuadHex, 2 },
422 { .name = "posix_openpt", .ret_type = 1, .nargs = 1,
423 .args = { { Open, 0 } } },
424 { .name = "ppoll", .ret_type = 1, .nargs = 4,
425 .args = { { Pollfd, 0 }, { Int, 1 }, { Timespec | IN, 2 },
426 { Sigset | IN, 3 } } },
427 { .name = "pread", .ret_type = 1, .nargs = 4,
428 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
430 { .name = "procctl", .ret_type = 1, .nargs = 4,
431 .args = { { Idtype, 0 }, { Quad, 1 }, { Procctl, 2 }, { Ptr, 3 } } },
432 { .name = "ptrace", .ret_type = 1, .nargs = 4,
433 .args = { { Ptraceop, 0 }, { Int, 1 }, { Ptr, 2 }, { Int, 3 } } },
434 { .name = "pwrite", .ret_type = 1, .nargs = 4,
435 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
437 { .name = "quotactl", .ret_type = 1, .nargs = 4,
438 .args = { { Name, 0 }, { Quotactlcmd, 1 }, { Int, 2 }, { Ptr, 3 } } },
439 { .name = "read", .ret_type = 1, .nargs = 3,
440 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 } } },
441 { .name = "readlink", .ret_type = 1, .nargs = 3,
442 .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Sizet, 2 } } },
443 { .name = "readlinkat", .ret_type = 1, .nargs = 4,
444 .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
446 { .name = "readv", .ret_type = 1, .nargs = 3,
447 .args = { { Int, 0 }, { Iovec | OUT, 1 }, { Int, 2 } } },
448 { .name = "reboot", .ret_type = 1, .nargs = 1,
449 .args = { { Reboothowto, 0 } } },
450 { .name = "recvfrom", .ret_type = 1, .nargs = 6,
451 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
452 { Msgflags, 3 }, { Sockaddr | OUT, 4 },
453 { Ptr | OUT, 5 } } },
454 { .name = "recvmsg", .ret_type = 1, .nargs = 3,
455 .args = { { Int, 0 }, { Msghdr | OUT, 1 }, { Msgflags, 2 } } },
456 { .name = "rename", .ret_type = 1, .nargs = 2,
457 .args = { { Name, 0 }, { Name, 1 } } },
458 { .name = "renameat", .ret_type = 1, .nargs = 4,
459 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
460 { .name = "rfork", .ret_type = 1, .nargs = 1,
461 .args = { { Rforkflags, 0 } } },
462 { .name = "rmdir", .ret_type = 1, .nargs = 1,
463 .args = { { Name, 0 } } },
464 { .name = "rtprio", .ret_type = 1, .nargs = 3,
465 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
466 { .name = "rtprio_thread", .ret_type = 1, .nargs = 3,
467 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
468 { .name = "sched_get_priority_max", .ret_type = 1, .nargs = 1,
469 .args = { { Schedpolicy, 0 } } },
470 { .name = "sched_get_priority_min", .ret_type = 1, .nargs = 1,
471 .args = { { Schedpolicy, 0 } } },
472 { .name = "sched_getparam", .ret_type = 1, .nargs = 2,
473 .args = { { Int, 0 }, { Schedparam | OUT, 1 } } },
474 { .name = "sched_getscheduler", .ret_type = 1, .nargs = 1,
475 .args = { { Int, 0 } } },
476 { .name = "sched_rr_get_interval", .ret_type = 1, .nargs = 2,
477 .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
478 { .name = "sched_setparam", .ret_type = 1, .nargs = 2,
479 .args = { { Int, 0 }, { Schedparam, 1 } } },
480 { .name = "sched_setscheduler", .ret_type = 1, .nargs = 3,
481 .args = { { Int, 0 }, { Schedpolicy, 1 }, { Schedparam, 2 } } },
482 { .name = "sctp_generic_recvmsg", .ret_type = 1, .nargs = 7,
483 .args = { { Int, 0 }, { Iovec | OUT, 1 }, { Int, 2 },
484 { Sockaddr | OUT, 3 }, { Ptr | OUT, 4 },
485 { Sctpsndrcvinfo | OUT, 5 }, { Ptr | OUT, 6 } } },
486 { .name = "sctp_generic_sendmsg", .ret_type = 1, .nargs = 7,
487 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
488 { Sockaddr | IN, 3 }, { Socklent, 4 },
489 { Sctpsndrcvinfo | IN, 5 }, { Msgflags, 6 } } },
490 { .name = "sctp_generic_sendmsg_iov", .ret_type = 1, .nargs = 7,
491 .args = { { Int, 0 }, { Iovec | IN, 1 }, { Int, 2 },
492 { Sockaddr | IN, 3 }, { Socklent, 4 },
493 { Sctpsndrcvinfo | IN, 5 }, { Msgflags, 6 } } },
494 { .name = "sendfile", .ret_type = 1, .nargs = 7,
495 .args = { { Int, 0 }, { Int, 1 }, { QuadHex, 2 }, { Sizet, 3 },
496 { Sendfilehdtr, 4 }, { QuadHex | OUT, 5 },
497 { Sendfileflags, 6 } } },
498 { .name = "select", .ret_type = 1, .nargs = 5,
499 .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
501 { .name = "sendmsg", .ret_type = 1, .nargs = 3,
502 .args = { { Int, 0 }, { Msghdr | IN, 1 }, { Msgflags, 2 } } },
503 { .name = "sendto", .ret_type = 1, .nargs = 6,
504 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
505 { Msgflags, 3 }, { Sockaddr | IN, 4 },
506 { Socklent | IN, 5 } } },
507 { .name = "setitimer", .ret_type = 1, .nargs = 3,
508 .args = { { Itimerwhich, 0 }, { Itimerval, 1 },
509 { Itimerval | OUT, 2 } } },
510 { .name = "setpriority", .ret_type = 1, .nargs = 3,
511 .args = { { Priowhich, 0 }, { Int, 1 }, { Int, 2 } } },
512 { .name = "setrlimit", .ret_type = 1, .nargs = 2,
513 .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
514 { .name = "setsockopt", .ret_type = 1, .nargs = 5,
515 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
516 { Ptr | IN, 3 }, { Socklent, 4 } } },
517 { .name = "shm_open", .ret_type = 1, .nargs = 3,
518 .args = { { ShmName | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
519 { .name = "shm_open2", .ret_type = 1, .nargs = 5,
520 .args = { { ShmName | IN, 0 }, { Open, 1 }, { Octal, 2 },
521 { ShmFlags, 3 }, { Name | IN, 4 } } },
522 { .name = "shm_rename", .ret_type = 1, .nargs = 3,
523 .args = { { Name | IN, 0 }, { Name | IN, 1 }, { Hex, 2 } } },
524 { .name = "shm_unlink", .ret_type = 1, .nargs = 1,
525 .args = { { Name | IN, 0 } } },
526 { .name = "shutdown", .ret_type = 1, .nargs = 2,
527 .args = { { Int, 0 }, { Shutdown, 1 } } },
528 { .name = "sigaction", .ret_type = 1, .nargs = 3,
529 .args = { { Signal, 0 }, { Sigaction | IN, 1 },
530 { Sigaction | OUT, 2 } } },
531 { .name = "sigpending", .ret_type = 1, .nargs = 1,
532 .args = { { Sigset | OUT, 0 } } },
533 { .name = "sigprocmask", .ret_type = 1, .nargs = 3,
534 .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
535 { .name = "sigqueue", .ret_type = 1, .nargs = 3,
536 .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
537 { .name = "sigreturn", .ret_type = 1, .nargs = 1,
538 .args = { { Ptr, 0 } } },
539 { .name = "sigsuspend", .ret_type = 1, .nargs = 1,
540 .args = { { Sigset | IN, 0 } } },
541 { .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
542 .args = { { Sigset | IN, 0 }, { Siginfo | OUT, 1 },
543 { Timespec | IN, 2 } } },
544 { .name = "sigwait", .ret_type = 1, .nargs = 2,
545 .args = { { Sigset | IN, 0 }, { PSig | OUT, 1 } } },
546 { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
547 .args = { { Sigset | IN, 0 }, { Siginfo | OUT, 1 } } },
548 { .name = "socket", .ret_type = 1, .nargs = 3,
549 .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Sockprotocol, 2 } } },
550 { .name = "stat", .ret_type = 1, .nargs = 2,
551 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
552 { .name = "statfs", .ret_type = 1, .nargs = 2,
553 .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } },
554 { .name = "symlink", .ret_type = 1, .nargs = 2,
555 .args = { { Name, 0 }, { Name, 1 } } },
556 { .name = "symlinkat", .ret_type = 1, .nargs = 3,
557 .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } },
558 { .name = "sysarch", .ret_type = 1, .nargs = 2,
559 .args = { { Sysarch, 0 }, { Ptr, 1 } } },
560 { .name = "__sysctl", .ret_type = 1, .nargs = 6,
561 .args = { { Sysctl, 0 }, { Sizet, 1 }, { Ptr, 2 }, { Ptr, 3 },
562 { Ptr, 4 }, { Sizet, 5 } } },
563 { .name = "__sysctlbyname", .ret_type = 1, .nargs = 6,
564 .args = { { Name, 0 }, { Sizet, 1 }, { Ptr, 2 }, { Ptr, 3 },
565 { Ptr, 4}, { Sizet, 5 } } },
566 { .name = "thr_kill", .ret_type = 1, .nargs = 2,
567 .args = { { Long, 0 }, { Signal, 1 } } },
568 { .name = "thr_self", .ret_type = 1, .nargs = 1,
569 .args = { { Ptr, 0 } } },
570 { .name = "thr_set_name", .ret_type = 1, .nargs = 2,
571 .args = { { Long, 0 }, { Name, 1 } } },
572 { .name = "truncate", .ret_type = 1, .nargs = 2,
573 .args = { { Name | IN, 0 }, { QuadHex | IN, 1 } } },
576 { .name = "umount", .ret_type = 1, .nargs = 2,
577 .args = { { Name, 0 }, { Int, 2 } } },
579 { .name = "unlink", .ret_type = 1, .nargs = 1,
580 .args = { { Name, 0 } } },
581 { .name = "unlinkat", .ret_type = 1, .nargs = 3,
582 .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
583 { .name = "unmount", .ret_type = 1, .nargs = 2,
584 .args = { { Name, 0 }, { Mountflags, 1 } } },
585 { .name = "utimensat", .ret_type = 1, .nargs = 4,
586 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
588 { .name = "utimes", .ret_type = 1, .nargs = 2,
589 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
590 { .name = "utrace", .ret_type = 1, .nargs = 1,
591 .args = { { Utrace, 0 } } },
592 { .name = "wait4", .ret_type = 1, .nargs = 4,
593 .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
594 { Rusage | OUT, 3 } } },
595 { .name = "wait6", .ret_type = 1, .nargs = 6,
596 .args = { { Idtype, 0 }, { Quad, 1 }, { ExitStatus | OUT, 2 },
597 { Waitoptions, 3 }, { Rusage | OUT, 4 },
598 { Siginfo | OUT, 5 } } },
599 { .name = "write", .ret_type = 1, .nargs = 3,
600 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 } } },
601 { .name = "writev", .ret_type = 1, .nargs = 3,
602 .args = { { Int, 0 }, { Iovec | IN, 1 }, { Int, 2 } } },
605 { .name = "linux_access", .ret_type = 1, .nargs = 2,
606 .args = { { Name, 0 }, { Accessmode, 1 } } },
607 { .name = "linux_execve", .ret_type = 1, .nargs = 3,
608 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
609 { ExecEnv | IN, 2 } } },
610 { .name = "linux_getitimer", .ret_type = 1, .nargs = 2,
611 .args = { { Itimerwhich, 0 }, { Itimerval | OUT, 2 } } },
612 { .name = "linux_lseek", .ret_type = 2, .nargs = 3,
613 .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
614 { .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
615 .args = { { Name | IN, 0 }, { Int, 1 } } },
616 { .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
617 .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
618 { .name = "linux_newstat", .ret_type = 1, .nargs = 2,
619 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
620 { .name = "linux_open", .ret_type = 1, .nargs = 3,
621 .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
622 { .name = "linux_readlink", .ret_type = 1, .nargs = 3,
623 .args = { { Name, 0 }, { Name | OUT, 1 }, { Sizet, 2 } } },
624 { .name = "linux_setitimer", .ret_type = 1, .nargs = 3,
625 .args = { { Itimerwhich, 0 }, { Itimerval, 1 },
626 { Itimerval | OUT, 2 } } },
627 { .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
628 .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
629 { .name = "linux_stat64", .ret_type = 1, .nargs = 2,
630 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
632 /* CloudABI system calls. */
633 { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
634 .args = { { CloudABIClockID, 0 } } },
635 { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
636 .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
637 { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
638 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
639 { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
640 .args = { { Int, 0 } } },
641 { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
642 .args = { { CloudABIFileType, 0 } } },
643 { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
644 .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
645 { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
646 .args = { { Int, 0 } } },
647 { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
648 .args = { { Int, 0 } } },
649 { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
650 .args = { { Int, 0 }, { Int, 1 } } },
651 { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
652 .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
653 { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
654 .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
655 { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
656 .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
657 { CloudABIFDSFlags, 2 } } },
658 { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
659 .args = { { Int, 0 } } },
660 { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
661 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
662 { CloudABIAdvice, 3 } } },
663 { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
664 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
665 { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
666 .args = { { Int, 0 }, { BinString | IN, 1 },
667 { CloudABIFileType, 3 } } },
668 { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
669 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
670 { Int, 3 }, { BinString | IN, 4 } } },
671 { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
672 .args = { { Int, 0 }, { BinString | IN, 1 },
673 { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
674 { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
675 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
677 { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
678 .args = { { Int, 0 }, { BinString | IN, 1 },
679 { BinString | OUT, 3 }, { Int, 4 } } },
680 { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
681 .args = { { Int, 0 }, { BinString | IN, 1 },
682 { Int, 3 }, { BinString | IN, 4 } } },
683 { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
684 .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
685 { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
686 .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
687 { CloudABIFSFlags, 2 } } },
688 { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
689 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
690 { CloudABIFileStat | OUT, 3 } } },
691 { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
692 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
693 { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
694 { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
695 .args = { { BinString | IN, 0 },
696 { Int, 2 }, { BinString | IN, 3 } } },
697 { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
698 .args = { { Int, 0 }, { BinString | IN, 1 },
699 { CloudABIULFlags, 3 } } },
700 { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
701 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
702 { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
703 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
704 { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
705 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
706 { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
707 { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
708 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
709 { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
710 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
711 { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
712 .args = { { Ptr, 0 }, { Int, 1 } } },
713 { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
714 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
715 { IntArray, 3 }, { Int, 4 } } },
716 { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
717 .args = { { Int, 0 } } },
718 { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
719 { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
720 .args = { { CloudABISignal, 0 } } },
721 { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
722 .args = { { BinString | OUT, 0 }, { Int, 1 } } },
723 { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
724 .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
725 { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
726 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
727 { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
729 static STAILQ_HEAD(, syscall) seen_syscalls;
731 /* Xlat idea taken from strace */
737 #define X(a) { a, #a },
738 #define XEND { 0, NULL }
740 static struct xlat poll_flags[] = {
741 X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
742 X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
743 X(POLLWRBAND) X(POLLINIGNEOF) X(POLLRDHUP) XEND
746 static struct xlat sigaction_flags[] = {
747 X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
748 X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
751 static struct xlat linux_socketcall_ops[] = {
752 X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
753 X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
754 X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
755 X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
756 X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
760 static struct xlat lio_modes[] = {
761 X(LIO_WAIT) X(LIO_NOWAIT)
765 static struct xlat lio_opcodes[] = {
766 X(LIO_WRITE) X(LIO_READ) X(LIO_READV) X(LIO_WRITEV) X(LIO_NOP)
770 static struct xlat aio_fsync_ops[] = {
776 #define X(a) { CLOUDABI_##a, #a },
778 static struct xlat cloudabi_advice[] = {
779 X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
780 X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
784 static struct xlat cloudabi_clockid[] = {
785 X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
786 X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
790 static struct xlat cloudabi_fdflags[] = {
791 X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
792 X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
796 static struct xlat cloudabi_fdsflags[] = {
797 X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
801 static struct xlat cloudabi_filetype[] = {
802 X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
803 X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
804 X(FILETYPE_PROCESS) X(FILETYPE_REGULAR_FILE)
805 X(FILETYPE_SHARED_MEMORY) X(FILETYPE_SOCKET_DGRAM)
806 X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK)
810 static struct xlat cloudabi_fsflags[] = {
811 X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
812 X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
816 static struct xlat cloudabi_mflags[] = {
817 X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
821 static struct xlat cloudabi_mprot[] = {
822 X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
826 static struct xlat cloudabi_msflags[] = {
827 X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
831 static struct xlat cloudabi_oflags[] = {
832 X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
836 static struct xlat cloudabi_sdflags[] = {
837 X(SHUT_RD) X(SHUT_WR)
841 static struct xlat cloudabi_signal[] = {
842 X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
843 X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
844 X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
845 X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
846 X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
850 static struct xlat cloudabi_ulflags[] = {
855 static struct xlat cloudabi_whence[] = {
856 X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
864 * Searches an xlat array for a value, and returns it if found. Otherwise
865 * return a string representation.
868 lookup(struct xlat *xlat, int val, int base)
872 for (; xlat->str != NULL; xlat++)
873 if (xlat->val == val)
877 sprintf(tmp, "0%o", val);
880 sprintf(tmp, "0x%x", val);
883 sprintf(tmp, "%u", val);
886 errx(1, "Unknown lookup base");
892 xlookup(struct xlat *xlat, int val)
895 return (lookup(xlat, val, 16));
899 * Searches an xlat array containing bitfield values. Remaining bits
900 * set after removing the known ones are printed at the end:
904 xlookup_bits(struct xlat *xlat, int val)
907 static char str[512];
911 for (; xlat->str != NULL; xlat++) {
912 if ((xlat->val & rem) == xlat->val) {
914 * Don't print the "all-bits-zero" string unless all
915 * bits are really zero.
917 if (xlat->val == 0 && val != 0)
919 len += sprintf(str + len, "%s|", xlat->str);
925 * If we have leftover bits or didn't match anything, print
929 len += sprintf(str + len, "0x%x", rem);
930 if (len && str[len - 1] == '|')
937 print_integer_arg(const char *(*decoder)(int), FILE *fp, int value)
941 str = decoder(value);
945 fprintf(fp, "%d", value);
949 print_mask_arg_part(bool (*decoder)(FILE *, int, int *), FILE *fp, int value,
953 return (decoder(fp, value, rem));
957 print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value)
961 if (!print_mask_arg_part(decoder, fp, value, &rem))
962 fprintf(fp, "0x%x", rem);
964 fprintf(fp, "|0x%x", rem);
968 print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), FILE *fp,
973 if (!decoder(fp, value, &rem))
974 fprintf(fp, "0x%x", rem);
976 fprintf(fp, "|0x%x", rem);
980 * Add argument padding to subsequent system calls after Quad
981 * syscall arguments as needed. This used to be done by hand in the
982 * decoded_syscalls table which was ugly and error prone. It is
983 * simpler to do the fixup of offsets at initialization time than when
984 * decoding arguments.
987 quad_fixup(struct syscall_decode *sc)
994 for (i = 0; i < sc->nargs; i++) {
995 /* This arg type is a dummy that doesn't use offset. */
996 if ((sc->args[i].type & ARG_MASK) == PipeFds)
999 assert(prev < sc->args[i].offset);
1000 prev = sc->args[i].offset;
1001 sc->args[i].offset += offset;
1002 switch (sc->args[i].type & ARG_MASK) {
1007 * 64-bit arguments on 32-bit powerpc must be
1008 * 64-bit aligned. If the current offset is
1009 * not aligned, the calling convention inserts
1010 * a 32-bit pad argument that should be skipped.
1012 if (sc->args[i].offset % 2 == 1) {
1013 sc->args[i].offset++;
1024 static struct syscall *
1025 find_syscall(struct procabi *abi, u_int number)
1027 struct extra_syscall *es;
1029 if (number < nitems(abi->syscalls))
1030 return (abi->syscalls[number]);
1031 STAILQ_FOREACH(es, &abi->extra_syscalls, entries) {
1032 if (es->number == number)
1039 add_syscall(struct procabi *abi, u_int number, struct syscall *sc)
1041 struct extra_syscall *es;
1044 * quad_fixup() is currently needed for all 32-bit ABIs.
1045 * TODO: This should probably be a function pointer inside struct
1048 if (abi->pointer_size == 4)
1049 quad_fixup(&sc->decode);
1051 if (number < nitems(abi->syscalls)) {
1052 assert(abi->syscalls[number] == NULL);
1053 abi->syscalls[number] = sc;
1055 es = malloc(sizeof(*es));
1057 es->number = number;
1058 STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries);
1061 STAILQ_INSERT_HEAD(&seen_syscalls, sc, entries);
1065 * If/when the list gets big, it might be desirable to do it
1066 * as a hash table or binary search.
1069 get_syscall(struct threadinfo *t, u_int number, u_int nargs)
1072 struct procabi *procabi;
1073 const char *sysdecode_name;
1074 const char *lookup_name;
1078 procabi = t->proc->abi;
1079 sc = find_syscall(procabi, number);
1083 /* Memory is not explicitly deallocated, it's released on exit(). */
1084 sysdecode_name = sysdecode_syscallname(procabi->abi, number);
1085 if (sysdecode_name == NULL)
1086 asprintf(__DECONST(char **, &name), "#%d", number);
1088 name = sysdecode_name;
1090 sc = calloc(1, sizeof(*sc));
1093 /* Also decode compat syscalls arguments by stripping the prefix. */
1095 if (procabi->compat_prefix != NULL && strncmp(procabi->compat_prefix,
1096 name, strlen(procabi->compat_prefix)) == 0)
1097 lookup_name += strlen(procabi->compat_prefix);
1099 for (i = 0; i < nitems(decoded_syscalls); i++) {
1100 if (strcmp(lookup_name, decoded_syscalls[i].name) == 0) {
1101 sc->decode = decoded_syscalls[i];
1102 add_syscall(t->proc->abi, number, sc);
1107 /* It is unknown. Add it into the list. */
1109 fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
1112 sc->unknown = sysdecode_name == NULL;
1113 sc->decode.ret_type = 1; /* Assume 1 return value. */
1114 sc->decode.nargs = nargs;
1115 for (i = 0; i < nargs; i++) {
1116 sc->decode.args[i].offset = i;
1117 /* Treat all unknown arguments as LongHex. */
1118 sc->decode.args[i].type = LongHex;
1120 add_syscall(t->proc->abi, number, sc);
1125 * Copy a fixed amount of bytes from the process.
1128 get_struct(pid_t pid, psaddr_t offset, void *buf, size_t len)
1130 struct ptrace_io_desc iorequest;
1132 iorequest.piod_op = PIOD_READ_D;
1133 iorequest.piod_offs = (void *)(uintptr_t)offset;
1134 iorequest.piod_addr = buf;
1135 iorequest.piod_len = len;
1136 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
1141 #define MAXSIZE 4096
1144 * Copy a string from the process. Note that it is
1145 * expected to be a C string, but if max is set, it will
1146 * only get that much.
1149 get_string(pid_t pid, psaddr_t addr, int max)
1151 struct ptrace_io_desc iorequest;
1153 size_t offset, size, totalsize;
1159 /* Read up to the end of the current page. */
1160 size = PAGE_SIZE - (addr % PAGE_SIZE);
1165 buf = malloc(totalsize);
1169 iorequest.piod_op = PIOD_READ_D;
1170 iorequest.piod_offs = (void *)((uintptr_t)addr + offset);
1171 iorequest.piod_addr = buf + offset;
1172 iorequest.piod_len = size;
1173 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
1177 if (memchr(buf + offset, '\0', size) != NULL)
1180 if (totalsize < MAXSIZE && max == 0) {
1181 size = MAXSIZE - totalsize;
1182 if (size > PAGE_SIZE)
1184 nbuf = realloc(buf, totalsize + size);
1186 buf[totalsize - 1] = '\0';
1192 buf[totalsize - 1] = '\0';
1201 static char tmp[32];
1202 const char *signame;
1204 signame = sysdecode_signal(sig);
1205 if (signame == NULL) {
1206 snprintf(tmp, sizeof(tmp), "%d", sig);
1213 print_kevent(FILE *fp, struct kevent *ke)
1216 switch (ke->filter) {
1222 case EVFILT_PROCDESC:
1224 fprintf(fp, "%ju", (uintmax_t)ke->ident);
1227 fputs(strsig2(ke->ident), fp);
1230 fprintf(fp, "%p", (void *)ke->ident);
1233 print_integer_arg(sysdecode_kevent_filter, fp, ke->filter);
1235 print_mask_arg(sysdecode_kevent_flags, fp, ke->flags);
1237 sysdecode_kevent_fflags(fp, ke->filter, ke->fflags, 16);
1238 fprintf(fp, ",%#jx,%p", (uintmax_t)ke->data, ke->udata);
1242 print_utrace(FILE *fp, void *utrace_addr, size_t len)
1244 unsigned char *utrace_buffer;
1247 if (sysdecode_utrace(fp, utrace_addr, len)) {
1252 utrace_buffer = utrace_addr;
1253 fprintf(fp, "%zu:", len);
1255 fprintf(fp, " %02x", *utrace_buffer++);
1260 print_pointer(FILE *fp, uintptr_t arg)
1263 fprintf(fp, "%p", (void *)arg);
1267 print_sockaddr(FILE *fp, struct trussinfo *trussinfo, uintptr_t arg,
1271 struct sockaddr_in *lsin;
1272 struct sockaddr_in6 *lsin6;
1273 struct sockaddr_un *sun;
1274 struct sockaddr *sa;
1276 pid_t pid = trussinfo->curthread->proc->pid;
1282 /* If the length is too small, just bail. */
1283 if (len < sizeof(*sa)) {
1284 print_pointer(fp, arg);
1288 sa = calloc(1, len);
1289 if (get_struct(pid, arg, sa, len) == -1) {
1291 print_pointer(fp, arg);
1295 switch (sa->sa_family) {
1297 if (len < sizeof(*lsin))
1298 goto sockaddr_short;
1299 lsin = (struct sockaddr_in *)(void *)sa;
1300 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1301 fprintf(fp, "{ AF_INET %s:%d }", addr,
1302 htons(lsin->sin_port));
1305 if (len < sizeof(*lsin6))
1306 goto sockaddr_short;
1307 lsin6 = (struct sockaddr_in6 *)(void *)sa;
1308 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1310 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1311 htons(lsin6->sin6_port));
1314 sun = (struct sockaddr_un *)sa;
1315 fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1316 (int)(len - offsetof(struct sockaddr_un, sun_path)),
1322 "{ sa_len = %d, sa_family = %d, sa_data = {",
1323 (int)sa->sa_len, (int)sa->sa_family);
1324 for (q = (u_char *)sa->sa_data;
1325 q < (u_char *)sa + len; q++)
1326 fprintf(fp, "%s 0x%02x",
1327 q == (u_char *)sa->sa_data ? "" : ",",
1334 #define IOV_LIMIT 16
1337 print_iovec(FILE *fp, struct trussinfo *trussinfo, uintptr_t arg, int iovcnt)
1339 struct iovec iov[IOV_LIMIT];
1340 size_t max_string = trussinfo->strsize;
1341 char tmp2[max_string + 1], *tmp3;
1343 pid_t pid = trussinfo->curthread->proc->pid;
1345 bool buf_truncated, iov_truncated;
1348 print_pointer(fp, arg);
1351 if (iovcnt > IOV_LIMIT) {
1353 iov_truncated = true;
1355 iov_truncated = false;
1357 if (get_struct(pid, arg, &iov, iovcnt * sizeof(struct iovec)) == -1) {
1358 print_pointer(fp, arg);
1363 for (i = 0; i < iovcnt; i++) {
1364 len = iov[i].iov_len;
1365 if (len > max_string) {
1367 buf_truncated = true;
1369 buf_truncated = false;
1371 fprintf(fp, "%s{", (i > 0) ? "," : "");
1372 if (len && get_struct(pid, (uintptr_t)iov[i].iov_base, &tmp2, len) != -1) {
1373 tmp3 = malloc(len * 4 + 1);
1375 if (strvisx(tmp3, tmp2, len,
1376 VIS_CSTYLE|VIS_TAB|VIS_NL) <=
1380 buf_truncated = true;
1382 fprintf(fp, "\"%s\"%s", tmp3,
1383 buf_truncated ? "..." : "");
1386 print_pointer(fp, (uintptr_t)iov[i].iov_base);
1388 fprintf(fp, ",%zu}", iov[i].iov_len);
1390 fprintf(fp, "%s%s", iov_truncated ? ",..." : "", "]");
1394 print_sigval(FILE *fp, union sigval *sv)
1396 fprintf(fp, "{ %d, %p }", sv->sival_int, sv->sival_ptr);
1400 print_sigevent(FILE *fp, struct sigevent *se)
1402 fputs("{ sigev_notify=", fp);
1403 switch (se->sigev_notify) {
1405 fputs("SIGEV_NONE", fp);
1408 fprintf(fp, "SIGEV_SIGNAL, sigev_signo=%s, sigev_value=",
1409 strsig2(se->sigev_signo));
1410 print_sigval(fp, &se->sigev_value);
1413 fputs("SIGEV_THREAD, sigev_value=", fp);
1414 print_sigval(fp, &se->sigev_value);
1417 fprintf(fp, "SIGEV_KEVENT, sigev_notify_kqueue=%d, sigev_notify_kevent_flags=",
1418 se->sigev_notify_kqueue);
1419 print_mask_arg(sysdecode_kevent_flags, fp, se->sigev_notify_kevent_flags);
1421 case SIGEV_THREAD_ID:
1422 fprintf(fp, "SIGEV_THREAD_ID, sigev_notify_thread_id=%d, sigev_signo=%s, sigev_value=",
1423 se->sigev_notify_thread_id, strsig2(se->sigev_signo));
1424 print_sigval(fp, &se->sigev_value);
1427 fprintf(fp, "%d", se->sigev_notify);
1434 print_aiocb(FILE *fp, struct aiocb *cb)
1436 fprintf(fp, "{ %d,%jd,%p,%zu,%s,",
1441 xlookup(lio_opcodes, cb->aio_lio_opcode));
1442 print_sigevent(fp, &cb->aio_sigevent);
1447 print_gen_cmsg(FILE *fp, struct cmsghdr *cmsghdr)
1452 for (q = CMSG_DATA(cmsghdr);
1453 q < (u_char *)cmsghdr + cmsghdr->cmsg_len; q++) {
1454 fprintf(fp, "%s0x%02x", q == CMSG_DATA(cmsghdr) ? "" : ",", *q);
1460 print_sctp_initmsg(FILE *fp, struct sctp_initmsg *init)
1462 fprintf(fp, "{out=%u,", init->sinit_num_ostreams);
1463 fprintf(fp, "in=%u,", init->sinit_max_instreams);
1464 fprintf(fp, "max_rtx=%u,", init->sinit_max_attempts);
1465 fprintf(fp, "max_rto=%u}", init->sinit_max_init_timeo);
1469 print_sctp_sndrcvinfo(FILE *fp, bool receive, struct sctp_sndrcvinfo *info)
1471 fprintf(fp, "{sid=%u,", info->sinfo_stream);
1473 fprintf(fp, "ssn=%u,", info->sinfo_ssn);
1476 sysdecode_sctp_sinfo_flags(fp, info->sinfo_flags);
1477 fprintf(fp, ",ppid=%u,", ntohl(info->sinfo_ppid));
1479 fprintf(fp, "ctx=%u,", info->sinfo_context);
1480 fprintf(fp, "ttl=%u,", info->sinfo_timetolive);
1483 fprintf(fp, "tsn=%u,", info->sinfo_tsn);
1484 fprintf(fp, "cumtsn=%u,", info->sinfo_cumtsn);
1486 fprintf(fp, "id=%u}", info->sinfo_assoc_id);
1490 print_sctp_sndinfo(FILE *fp, struct sctp_sndinfo *info)
1492 fprintf(fp, "{sid=%u,", info->snd_sid);
1494 print_mask_arg(sysdecode_sctp_snd_flags, fp, info->snd_flags);
1495 fprintf(fp, ",ppid=%u,", ntohl(info->snd_ppid));
1496 fprintf(fp, "ctx=%u,", info->snd_context);
1497 fprintf(fp, "id=%u}", info->snd_assoc_id);
1501 print_sctp_rcvinfo(FILE *fp, struct sctp_rcvinfo *info)
1503 fprintf(fp, "{sid=%u,", info->rcv_sid);
1504 fprintf(fp, "ssn=%u,", info->rcv_ssn);
1506 print_mask_arg(sysdecode_sctp_rcv_flags, fp, info->rcv_flags);
1507 fprintf(fp, ",ppid=%u,", ntohl(info->rcv_ppid));
1508 fprintf(fp, "tsn=%u,", info->rcv_tsn);
1509 fprintf(fp, "cumtsn=%u,", info->rcv_cumtsn);
1510 fprintf(fp, "ctx=%u,", info->rcv_context);
1511 fprintf(fp, "id=%u}", info->rcv_assoc_id);
1515 print_sctp_nxtinfo(FILE *fp, struct sctp_nxtinfo *info)
1517 fprintf(fp, "{sid=%u,", info->nxt_sid);
1519 print_mask_arg(sysdecode_sctp_nxt_flags, fp, info->nxt_flags);
1520 fprintf(fp, ",ppid=%u,", ntohl(info->nxt_ppid));
1521 fprintf(fp, "len=%u,", info->nxt_length);
1522 fprintf(fp, "id=%u}", info->nxt_assoc_id);
1526 print_sctp_prinfo(FILE *fp, struct sctp_prinfo *info)
1529 print_integer_arg(sysdecode_sctp_pr_policy, fp, info->pr_policy);
1530 fprintf(fp, ",val=%u}", info->pr_value);
1534 print_sctp_authinfo(FILE *fp, struct sctp_authinfo *info)
1536 fprintf(fp, "{num=%u}", info->auth_keynumber);
1540 print_sctp_ipv4_addr(FILE *fp, struct in_addr *addr)
1542 char buf[INET_ADDRSTRLEN];
1545 s = inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN);
1547 fprintf(fp, "{addr=%s}", s);
1549 fputs("{addr=???}", fp);
1553 print_sctp_ipv6_addr(FILE *fp, struct in6_addr *addr)
1555 char buf[INET6_ADDRSTRLEN];
1558 s = inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN);
1560 fprintf(fp, "{addr=%s}", s);
1562 fputs("{addr=???}", fp);
1566 print_sctp_cmsg(FILE *fp, bool receive, struct cmsghdr *cmsghdr)
1571 len = cmsghdr->cmsg_len;
1572 data = CMSG_DATA(cmsghdr);
1573 switch (cmsghdr->cmsg_type) {
1575 if (len == CMSG_LEN(sizeof(struct sctp_initmsg)))
1576 print_sctp_initmsg(fp, (struct sctp_initmsg *)data);
1578 print_gen_cmsg(fp, cmsghdr);
1581 if (len == CMSG_LEN(sizeof(struct sctp_sndrcvinfo)))
1582 print_sctp_sndrcvinfo(fp, receive,
1583 (struct sctp_sndrcvinfo *)data);
1585 print_gen_cmsg(fp, cmsghdr);
1589 if (len == CMSG_LEN(sizeof(struct sctp_extrcvinfo)))
1590 print_sctp_extrcvinfo(fp,
1591 (struct sctp_extrcvinfo *)data);
1593 print_gen_cmsg(fp, cmsghdr);
1597 if (len == CMSG_LEN(sizeof(struct sctp_sndinfo)))
1598 print_sctp_sndinfo(fp, (struct sctp_sndinfo *)data);
1600 print_gen_cmsg(fp, cmsghdr);
1603 if (len == CMSG_LEN(sizeof(struct sctp_rcvinfo)))
1604 print_sctp_rcvinfo(fp, (struct sctp_rcvinfo *)data);
1606 print_gen_cmsg(fp, cmsghdr);
1609 if (len == CMSG_LEN(sizeof(struct sctp_nxtinfo)))
1610 print_sctp_nxtinfo(fp, (struct sctp_nxtinfo *)data);
1612 print_gen_cmsg(fp, cmsghdr);
1615 if (len == CMSG_LEN(sizeof(struct sctp_prinfo)))
1616 print_sctp_prinfo(fp, (struct sctp_prinfo *)data);
1618 print_gen_cmsg(fp, cmsghdr);
1621 if (len == CMSG_LEN(sizeof(struct sctp_authinfo)))
1622 print_sctp_authinfo(fp, (struct sctp_authinfo *)data);
1624 print_gen_cmsg(fp, cmsghdr);
1626 case SCTP_DSTADDRV4:
1627 if (len == CMSG_LEN(sizeof(struct in_addr)))
1628 print_sctp_ipv4_addr(fp, (struct in_addr *)data);
1630 print_gen_cmsg(fp, cmsghdr);
1632 case SCTP_DSTADDRV6:
1633 if (len == CMSG_LEN(sizeof(struct in6_addr)))
1634 print_sctp_ipv6_addr(fp, (struct in6_addr *)data);
1636 print_gen_cmsg(fp, cmsghdr);
1639 print_gen_cmsg(fp, cmsghdr);
1644 print_cmsgs(FILE *fp, pid_t pid, bool receive, struct msghdr *msghdr)
1646 struct cmsghdr *cmsghdr;
1653 len = msghdr->msg_controllen;
1658 cmsgbuf = calloc(1, len);
1659 if (get_struct(pid, (uintptr_t)msghdr->msg_control, cmsgbuf, len) == -1) {
1660 print_pointer(fp, (uintptr_t)msghdr->msg_control);
1664 msghdr->msg_control = cmsgbuf;
1667 for (cmsghdr = CMSG_FIRSTHDR(msghdr);
1669 cmsghdr = CMSG_NXTHDR(msghdr, cmsghdr)) {
1670 if (cmsghdr->cmsg_len < sizeof(*cmsghdr)) {
1671 fprintf(fp, "{<invalid cmsg, len=%u>}",
1673 if (cmsghdr->cmsg_len == 0) {
1674 /* Avoid looping forever. */
1680 level = cmsghdr->cmsg_level;
1681 type = cmsghdr->cmsg_type;
1682 len = cmsghdr->cmsg_len;
1683 fprintf(fp, "%s{level=", first ? "" : ",");
1684 print_integer_arg(sysdecode_sockopt_level, fp, level);
1685 fputs(",type=", fp);
1686 temp = sysdecode_cmsg_type(level, type);
1690 fprintf(fp, "%d", type);
1692 fputs(",data=", fp);
1695 print_sctp_cmsg(fp, receive, cmsghdr);
1698 print_gen_cmsg(fp, cmsghdr);
1709 print_sysctl_oid(FILE *fp, int *oid, size_t len)
1716 for (i = 0; i < len; i++) {
1717 fprintf(fp, "%s%d", first ? "" : ".", oid[i]);
1724 print_sysctl(FILE *fp, int *oid, size_t len)
1727 int qoid[CTL_MAXNAME + 2];
1730 qoid[0] = CTL_SYSCTL;
1731 qoid[1] = CTL_SYSCTL_NAME;
1732 memcpy(qoid + 2, oid, len * sizeof(int));
1734 if (sysctl(qoid, len + 2, name, &i, 0, 0) == -1)
1735 print_sysctl_oid(fp, oid, len);
1737 fprintf(fp, "%s", name);
1741 * Convert a 32-bit user-space pointer to psaddr_t. Currently, this
1742 * sign-extends on MIPS and zero-extends on all other architectures.
1745 user_ptr32_to_psaddr(int32_t user_pointer)
1747 #if defined(__mips__)
1748 return ((psaddr_t)(intptr_t)user_pointer);
1750 return ((psaddr_t)(uintptr_t)user_pointer);
1755 * Converts a syscall argument into a string. Said string is
1756 * allocated via malloc(), so needs to be free()'d. sc is
1757 * a pointer to the syscall description (see above); args is
1758 * an array of all of the system call arguments.
1761 print_arg(struct syscall_arg *sc, unsigned long *args, register_t *retval,
1762 struct trussinfo *trussinfo)
1769 fp = open_memstream(&tmp, &tmplen);
1770 pid = trussinfo->curthread->proc->pid;
1771 switch (sc->type & ARG_MASK) {
1773 fprintf(fp, "0x%x", (int)args[sc->offset]);
1776 fprintf(fp, "0%o", (int)args[sc->offset]);
1779 fprintf(fp, "%d", (int)args[sc->offset]);
1782 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1787 if (get_struct(pid, args[sc->offset], &val,
1789 fprintf(fp, "{ %u }", val);
1791 print_pointer(fp, args[sc->offset]);
1795 fprintf(fp, "0x%lx", args[sc->offset]);
1798 fprintf(fp, "%ld", args[sc->offset]);
1801 fprintf(fp, "%zu", (size_t)args[sc->offset]);
1804 /* Handle special SHM_ANON value. */
1805 if ((char *)(uintptr_t)args[sc->offset] == SHM_ANON) {
1806 fprintf(fp, "SHM_ANON");
1811 /* NULL-terminated string. */
1814 tmp2 = get_string(pid, args[sc->offset], 0);
1815 fprintf(fp, "\"%s\"", tmp2);
1821 * Binary block of data that might have printable characters.
1822 * XXX If type|OUT, assume that the length is the syscall's
1823 * return value. Otherwise, assume that the length of the block
1824 * is in the next syscall argument.
1826 int max_string = trussinfo->strsize;
1827 char tmp2[max_string + 1], *tmp3;
1834 len = args[sc->offset + 1];
1837 * Don't print more than max_string characters, to avoid word
1838 * wrap. If we have to truncate put some ... after the string.
1840 if (len > max_string) {
1844 if (len && get_struct(pid, args[sc->offset], &tmp2, len)
1846 tmp3 = malloc(len * 4 + 1);
1848 if (strvisx(tmp3, tmp2, len,
1849 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1854 fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1858 print_pointer(fp, args[sc->offset]);
1867 int32_t strarray32[PAGE_SIZE / sizeof(int32_t)];
1868 int64_t strarray64[PAGE_SIZE / sizeof(int64_t)];
1869 char buf[PAGE_SIZE];
1874 size_t pointer_size =
1875 trussinfo->curthread->proc->abi->pointer_size;
1878 * Only parse argv[] and environment arrays from exec calls
1881 if (((sc->type & ARG_MASK) == ExecArgs &&
1882 (trussinfo->flags & EXECVEARGS) == 0) ||
1883 ((sc->type & ARG_MASK) == ExecEnv &&
1884 (trussinfo->flags & EXECVEENVS) == 0)) {
1885 print_pointer(fp, args[sc->offset]);
1890 * Read a page of pointers at a time. Punt if the top-level
1891 * pointer is not aligned. Note that the first read is of
1894 addr = args[sc->offset];
1895 if (!__is_aligned(addr, pointer_size)) {
1896 print_pointer(fp, args[sc->offset]);
1900 len = PAGE_SIZE - (addr & PAGE_MASK);
1901 if (get_struct(pid, addr, u.buf, len) == -1) {
1902 print_pointer(fp, args[sc->offset]);
1912 if (pointer_size == 4) {
1913 straddr = user_ptr32_to_psaddr(u.strarray32[i]);
1914 } else if (pointer_size == 8) {
1915 straddr = (psaddr_t)u.strarray64[i];
1917 errx(1, "Unsupported pointer size: %zu",
1921 /* Stop once we read the first NULL pointer. */
1924 string = get_string(pid, straddr, 0);
1925 fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1930 if (i == len / pointer_size) {
1933 if (get_struct(pid, addr, u.buf, len) == -1) {
1934 fprintf(fp, ", <inval>");
1946 size_t pointer_size =
1947 trussinfo->curthread->proc->abi->pointer_size;
1949 if (pointer_size == 4) {
1950 #if _BYTE_ORDER == _LITTLE_ENDIAN
1951 value = (uint64_t)args[sc->offset + 1] << 32 |
1954 value = (uint64_t)args[sc->offset] << 32 |
1955 args[sc->offset + 1];
1958 value = (uint64_t)args[sc->offset];
1960 if ((sc->type & ARG_MASK) == Quad)
1961 fprintf(fp, "%jd", (intmax_t)value);
1963 fprintf(fp, "0x%jx", (intmax_t)value);
1969 if (get_struct(pid, args[sc->offset], &val,
1971 fprintf(fp, "{ 0x%jx }", (uintmax_t)val);
1973 print_pointer(fp, args[sc->offset]);
1977 print_pointer(fp, args[sc->offset]);
1982 if (retval[0] == -1)
1984 tmp2 = get_string(pid, args[sc->offset], retval[0]);
1985 fprintf(fp, "\"%s\"", tmp2);
1993 cmd = args[sc->offset];
1994 temp = sysdecode_ioctlname(cmd);
1998 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1999 cmd, cmd & IOC_OUT ? "R" : "",
2000 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
2001 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
2002 cmd & 0xFF, IOCPARM_LEN(cmd));
2009 if (get_struct(pid, args[sc->offset], &ts, sizeof(ts)) != -1)
2010 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
2013 print_pointer(fp, args[sc->offset]);
2017 struct timespec ts[2];
2021 if (get_struct(pid, args[sc->offset], &ts, sizeof(ts)) != -1) {
2024 for (i = 0; i < nitems(ts); i++) {
2027 switch (ts[i].tv_nsec) {
2029 fprintf(fp, "UTIME_NOW");
2032 fprintf(fp, "UTIME_OMIT");
2035 fprintf(fp, "%jd.%09ld",
2036 (intmax_t)ts[i].tv_sec,
2043 print_pointer(fp, args[sc->offset]);
2049 if (get_struct(pid, args[sc->offset], &tv, sizeof(tv)) != -1)
2050 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
2053 print_pointer(fp, args[sc->offset]);
2057 struct timeval tv[2];
2059 if (get_struct(pid, args[sc->offset], &tv, sizeof(tv)) != -1)
2060 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
2061 (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
2062 (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
2064 print_pointer(fp, args[sc->offset]);
2068 struct itimerval itv;
2070 if (get_struct(pid, args[sc->offset], &itv, sizeof(itv)) != -1)
2071 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
2072 (intmax_t)itv.it_interval.tv_sec,
2073 itv.it_interval.tv_usec,
2074 (intmax_t)itv.it_value.tv_sec,
2075 itv.it_value.tv_usec);
2077 print_pointer(fp, args[sc->offset]);
2082 struct linux_socketcall_args largs;
2084 if (get_struct(pid, args[sc->offset], (void *)&largs,
2085 sizeof(largs)) != -1)
2086 fprintf(fp, "{ %s, 0x%lx }",
2087 lookup(linux_socketcall_ops, largs.what, 10),
2088 (long unsigned int)largs.args);
2090 print_pointer(fp, args[sc->offset]);
2095 * XXX: A Pollfd argument expects the /next/ syscall argument
2096 * to be the number of fds in the array. This matches the poll
2100 int numfds = args[sc->offset + 1];
2101 size_t bytes = sizeof(struct pollfd) * numfds;
2104 if ((pfd = malloc(bytes)) == NULL)
2105 err(1, "Cannot malloc %zu bytes for pollfd array",
2107 if (get_struct(pid, args[sc->offset], pfd, bytes) != -1) {
2109 for (i = 0; i < numfds; i++) {
2110 fprintf(fp, " %d/%s", pfd[i].fd,
2111 xlookup_bits(poll_flags, pfd[i].events));
2115 print_pointer(fp, args[sc->offset]);
2122 * XXX: A Fd_set argument expects the /first/ syscall argument
2123 * to be the number of fds in the array. This matches the
2127 int numfds = args[0];
2128 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
2131 if ((fds = malloc(bytes)) == NULL)
2132 err(1, "Cannot malloc %zu bytes for fd_set array",
2134 if (get_struct(pid, args[sc->offset], fds, bytes) != -1) {
2136 for (i = 0; i < numfds; i++) {
2137 if (FD_ISSET(i, fds))
2138 fprintf(fp, " %d", i);
2142 print_pointer(fp, args[sc->offset]);
2147 fputs(strsig2(args[sc->offset]), fp);
2153 if (get_struct(pid, args[sc->offset], (void *)&ss,
2154 sizeof(ss)) == -1) {
2155 print_pointer(fp, args[sc->offset]);
2160 for (i = 1; i < sys_nsig; i++) {
2161 if (sigismember(&ss, i)) {
2162 fprintf(fp, "%s%s", !first ? "|" : "",
2173 print_integer_arg(sysdecode_sigprocmask_how, fp,
2177 /* XXX: Output depends on the value of the previous argument. */
2178 if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
2179 sysdecode_fcntl_arg(fp, args[sc->offset - 1],
2180 args[sc->offset], 16);
2183 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
2186 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
2188 case Closerangeflags:
2189 print_mask_arg(sysdecode_close_range_flags, fp, args[sc->offset]);
2192 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
2195 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
2198 print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
2201 print_mask_arg(sysdecode_shmflags, fp, args[sc->offset]);
2204 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
2207 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
2210 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
2213 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
2216 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]);
2219 print_integer_arg(sysdecode_pathconf_name, fp, args[sc->offset]);
2222 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
2227 if (args[sc->offset] == 0) {
2233 * Extract the address length from the next argument. If
2234 * this is an output sockaddr (OUT is set), then the
2235 * next argument is a pointer to a socklen_t. Otherwise
2236 * the next argument contains a socklen_t by value.
2238 if (sc->type & OUT) {
2239 if (get_struct(pid, args[sc->offset + 1], &len,
2240 sizeof(len)) == -1) {
2241 print_pointer(fp, args[sc->offset]);
2245 len = args[sc->offset + 1];
2247 print_sockaddr(fp, trussinfo, args[sc->offset], len);
2251 struct sigaction sa;
2253 if (get_struct(pid, args[sc->offset], &sa, sizeof(sa)) != -1) {
2255 if (sa.sa_handler == SIG_DFL)
2256 fputs("SIG_DFL", fp);
2257 else if (sa.sa_handler == SIG_IGN)
2258 fputs("SIG_IGN", fp);
2260 fprintf(fp, "%p", sa.sa_handler);
2261 fprintf(fp, " %s ss_t }",
2262 xlookup_bits(sigaction_flags, sa.sa_flags));
2264 print_pointer(fp, args[sc->offset]);
2270 if (get_struct(pid, args[sc->offset], &se, sizeof(se)) != -1)
2271 print_sigevent(fp, &se);
2273 print_pointer(fp, args[sc->offset]);
2278 * XXX XXX: The size of the array is determined by either the
2279 * next syscall argument, or by the syscall return value,
2280 * depending on which argument number we are. This matches the
2281 * kevent syscall, but luckily that's the only syscall that uses
2289 if (sc->offset == 1)
2290 numevents = args[sc->offset+1];
2291 else if (sc->offset == 3 && retval[0] != -1)
2292 numevents = retval[0];
2294 if (numevents >= 0) {
2295 bytes = sizeof(struct kevent) * numevents;
2296 if ((ke = malloc(bytes)) == NULL)
2298 "Cannot malloc %zu bytes for kevent array",
2302 if (numevents >= 0 && get_struct(pid, args[sc->offset],
2305 for (i = 0; i < numevents; i++) {
2307 print_kevent(fp, &ke[i]);
2311 print_pointer(fp, args[sc->offset]);
2317 struct kevent_freebsd11 *ke11;
2323 if (sc->offset == 1)
2324 numevents = args[sc->offset+1];
2325 else if (sc->offset == 3 && retval[0] != -1)
2326 numevents = retval[0];
2328 if (numevents >= 0) {
2329 bytes = sizeof(struct kevent_freebsd11) * numevents;
2330 if ((ke11 = malloc(bytes)) == NULL)
2332 "Cannot malloc %zu bytes for kevent array",
2336 memset(&ke, 0, sizeof(ke));
2337 if (numevents >= 0 && get_struct(pid, args[sc->offset],
2338 ke11, bytes) != -1) {
2340 for (i = 0; i < numevents; i++) {
2342 ke.ident = ke11[i].ident;
2343 ke.filter = ke11[i].filter;
2344 ke.flags = ke11[i].flags;
2345 ke.fflags = ke11[i].fflags;
2346 ke.data = ke11[i].data;
2347 ke.udata = ke11[i].udata;
2348 print_kevent(fp, &ke);
2352 print_pointer(fp, args[sc->offset]);
2360 if (get_struct(pid, args[sc->offset], &st, sizeof(st))
2364 strmode(st.st_mode, mode);
2366 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
2367 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
2368 (long)st.st_blksize);
2370 print_pointer(fp, args[sc->offset]);
2375 struct freebsd11_stat st;
2377 if (get_struct(pid, args[sc->offset], &st, sizeof(st))
2381 strmode(st.st_mode, mode);
2383 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
2384 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
2385 (long)st.st_blksize);
2387 print_pointer(fp, args[sc->offset]);
2395 if (get_struct(pid, args[sc->offset], &buf,
2396 sizeof(buf)) != -1) {
2399 bzero(fsid, sizeof(fsid));
2400 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
2401 for (i = 0; i < sizeof(buf.f_fsid); i++)
2402 snprintf(&fsid[i*2],
2403 sizeof(fsid) - (i*2), "%02x",
2404 ((u_char *)&buf.f_fsid)[i]);
2407 "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
2408 "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
2409 buf.f_mntfromname, fsid);
2411 print_pointer(fp, args[sc->offset]);
2418 if (get_struct(pid, args[sc->offset], &ru, sizeof(ru))
2421 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
2422 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
2423 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
2424 ru.ru_inblock, ru.ru_oublock);
2426 print_pointer(fp, args[sc->offset]);
2432 if (get_struct(pid, args[sc->offset], &rl, sizeof(rl))
2434 fprintf(fp, "{ cur=%ju,max=%ju }",
2435 rl.rlim_cur, rl.rlim_max);
2437 print_pointer(fp, args[sc->offset]);
2443 if (get_struct(pid, args[sc->offset], &status,
2444 sizeof(status)) != -1) {
2446 if (WIFCONTINUED(status))
2447 fputs("CONTINUED", fp);
2448 else if (WIFEXITED(status))
2449 fprintf(fp, "EXITED,val=%d",
2450 WEXITSTATUS(status));
2451 else if (WIFSIGNALED(status))
2452 fprintf(fp, "SIGNALED,sig=%s%s",
2453 strsig2(WTERMSIG(status)),
2454 WCOREDUMP(status) ? ",cored" : "");
2456 fprintf(fp, "STOPPED,sig=%s",
2457 strsig2(WTERMSIG(status)));
2460 print_pointer(fp, args[sc->offset]);
2464 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]);
2467 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]);
2470 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]);
2475 if (print_mask_arg_part(sysdecode_umtx_op_flags, fp,
2476 args[sc->offset], &rem))
2478 print_integer_arg(sysdecode_umtx_op, fp, rem);
2482 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]);
2485 print_mask_arg(sysdecode_atflags, fp, args[sc->offset]);
2488 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]);
2491 print_integer_arg(sysdecode_sysarch_number, fp,
2496 int oid[CTL_MAXNAME + 2];
2499 memset(name, 0, sizeof(name));
2500 len = args[sc->offset + 1];
2501 if (get_struct(pid, args[sc->offset], oid,
2502 len * sizeof(oid[0])) != -1) {
2504 if (oid[0] == CTL_SYSCTL) {
2505 fprintf(fp, "sysctl.");
2507 case CTL_SYSCTL_DEBUG:
2508 fprintf(fp, "debug");
2510 case CTL_SYSCTL_NAME:
2511 fprintf(fp, "name ");
2512 print_sysctl_oid(fp, oid + 2, len - 2);
2514 case CTL_SYSCTL_NEXT:
2515 fprintf(fp, "next");
2517 case CTL_SYSCTL_NAME2OID:
2518 fprintf(fp, "name2oid %s",
2520 args[sc->offset + 4],
2521 args[sc->offset + 5]));
2523 case CTL_SYSCTL_OIDFMT:
2524 fprintf(fp, "oidfmt ");
2525 print_sysctl(fp, oid + 2, len - 2);
2527 case CTL_SYSCTL_OIDDESCR:
2528 fprintf(fp, "oiddescr ");
2529 print_sysctl(fp, oid + 2, len - 2);
2531 case CTL_SYSCTL_OIDLABEL:
2532 fprintf(fp, "oidlabel ");
2533 print_sysctl(fp, oid + 2, len - 2);
2535 case CTL_SYSCTL_NEXTNOSKIP:
2536 fprintf(fp, "nextnoskip");
2539 print_sysctl(fp, oid + 1, len - 1);
2542 print_sysctl(fp, oid, len);
2550 * The pipe() system call in the kernel returns its
2551 * two file descriptors via return values. However,
2552 * the interface exposed by libc is that pipe()
2553 * accepts a pointer to an array of descriptors.
2554 * Format the output to match the libc API by printing
2555 * the returned file descriptors as a fake argument.
2557 * Overwrite the first retval to signal a successful
2560 fprintf(fp, "{ %d, %d }", (int)retval[0], (int)retval[1]);
2567 len = args[sc->offset + 1];
2568 utrace_addr = calloc(1, len);
2569 if (get_struct(pid, args[sc->offset],
2570 (void *)utrace_addr, len) != -1)
2571 print_utrace(fp, utrace_addr, len);
2573 print_pointer(fp, args[sc->offset]);
2578 int descriptors[16];
2579 unsigned long i, ndescriptors;
2582 ndescriptors = args[sc->offset + 1];
2584 if (ndescriptors > nitems(descriptors)) {
2585 ndescriptors = nitems(descriptors);
2588 if (get_struct(pid, args[sc->offset],
2589 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
2591 for (i = 0; i < ndescriptors; i++)
2592 fprintf(fp, i == 0 ? " %d" : ", %d",
2594 fprintf(fp, truncated ? ", ... }" : " }");
2596 print_pointer(fp, args[sc->offset]);
2600 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]);
2602 case CapFcntlRights: {
2605 if (sc->type & OUT) {
2606 if (get_struct(pid, args[sc->offset], &rights,
2607 sizeof(rights)) == -1) {
2608 print_pointer(fp, args[sc->offset]);
2612 rights = args[sc->offset];
2613 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights);
2617 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]);
2622 if (!sysdecode_fileflags(fp, args[sc->offset], &rem))
2623 fprintf(fp, "0x%x", rem);
2625 fprintf(fp, "|0x%x", rem);
2629 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]);
2632 print_integer_arg(sysdecode_getfsstat_mode, fp,
2636 print_integer_arg(sysdecode_itimer, fp, args[sc->offset]);
2639 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]);
2641 case Kldunloadflags:
2642 print_integer_arg(sysdecode_kldunload_flags, fp,
2646 fputs(xlookup(aio_fsync_ops, args[sc->offset]), fp);
2649 fputs(xlookup(lio_modes, args[sc->offset]), fp);
2652 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]);
2655 fprintf(fp, "%u", (socklen_t)args[sc->offset]);
2657 case Sockprotocol: {
2659 int domain, protocol;
2661 domain = args[sc->offset - 2];
2662 protocol = args[sc->offset];
2663 if (protocol == 0) {
2666 temp = sysdecode_socket_protocol(domain, protocol);
2670 fprintf(fp, "%d", protocol);
2676 print_integer_arg(sysdecode_sockopt_level, fp,
2683 level = args[sc->offset - 1];
2684 name = args[sc->offset];
2685 temp = sysdecode_sockopt_name(level, name);
2689 fprintf(fp, "%d", name);
2694 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]);
2697 cap_rights_t rights;
2699 if (get_struct(pid, args[sc->offset], &rights,
2700 sizeof(rights)) != -1) {
2702 sysdecode_cap_rights(fp, &rights);
2705 print_pointer(fp, args[sc->offset]);
2709 print_integer_arg(sysdecode_acltype, fp, args[sc->offset]);
2711 case Extattrnamespace:
2712 print_integer_arg(sysdecode_extattrnamespace, fp,
2716 print_integer_arg(sysdecode_minherit_inherit, fp,
2720 print_mask_arg(sysdecode_mlockall_flags, fp, args[sc->offset]);
2723 print_mask_arg(sysdecode_mount_flags, fp, args[sc->offset]);
2726 print_mask_arg(sysdecode_msync_flags, fp, args[sc->offset]);
2729 print_integer_arg(sysdecode_prio_which, fp, args[sc->offset]);
2732 print_integer_arg(sysdecode_ptrace_request, fp,
2736 print_mask_arg(sysdecode_sendfile_flags, fp, args[sc->offset]);
2738 case Sendfilehdtr: {
2739 struct sf_hdtr hdtr;
2741 if (get_struct(pid, args[sc->offset], &hdtr, sizeof(hdtr)) !=
2744 print_iovec(fp, trussinfo, (uintptr_t)hdtr.headers,
2746 print_iovec(fp, trussinfo, (uintptr_t)hdtr.trailers,
2750 print_pointer(fp, args[sc->offset]);
2754 if (!sysdecode_quotactl_cmd(fp, args[sc->offset]))
2755 fprintf(fp, "%#x", (int)args[sc->offset]);
2758 print_mask_arg(sysdecode_reboot_howto, fp, args[sc->offset]);
2761 print_integer_arg(sysdecode_rtprio_function, fp,
2765 print_integer_arg(sysdecode_scheduler_policy, fp,
2769 struct sched_param sp;
2771 if (get_struct(pid, args[sc->offset], &sp, sizeof(sp)) != -1)
2772 fprintf(fp, "{ %d }", sp.sched_priority);
2774 print_pointer(fp, args[sc->offset]);
2780 if (get_struct(pid, args[sc->offset], &sig, sizeof(sig)) == 0)
2781 fprintf(fp, "{ %s }", strsig2(sig));
2783 print_pointer(fp, args[sc->offset]);
2789 if (get_struct(pid, args[sc->offset], &si, sizeof(si)) != -1) {
2790 fprintf(fp, "{ signo=%s", strsig2(si.si_signo));
2791 decode_siginfo(fp, &si);
2794 print_pointer(fp, args[sc->offset]);
2799 * Print argument as an array of struct iovec, where the next
2800 * syscall argument is the number of elements of the array.
2803 print_iovec(fp, trussinfo, args[sc->offset],
2804 (int)args[sc->offset + 1]);
2809 if (get_struct(pid, args[sc->offset], &cb, sizeof(cb)) != -1)
2810 print_aiocb(fp, &cb);
2812 print_pointer(fp, args[sc->offset]);
2817 * Print argment as an array of pointers to struct aiocb, where
2818 * the next syscall argument is the number of elements.
2824 nent = args[sc->offset + 1];
2826 if (nent > nitems(cbs)) {
2831 if (get_struct(pid, args[sc->offset], cbs, sizeof(uintptr_t) * nent) != -1) {
2834 for (i = 0; i < nent; ++i) {
2838 if (get_struct(pid, cbs[i], &cb, sizeof(cb)) != -1)
2839 print_aiocb(fp, &cb);
2841 print_pointer(fp, cbs[i]);
2847 print_pointer(fp, args[sc->offset]);
2850 case AiocbPointer: {
2852 * aio_waitcomplete(2) assigns a pointer to a pointer to struct
2853 * aiocb, so we need to handle the extra layer of indirection.
2858 if (get_struct(pid, args[sc->offset], &cbp, sizeof(cbp)) != -1) {
2859 if (get_struct(pid, cbp, &cb, sizeof(cb)) != -1)
2860 print_aiocb(fp, &cb);
2862 print_pointer(fp, cbp);
2864 print_pointer(fp, args[sc->offset]);
2867 case Sctpsndrcvinfo: {
2868 struct sctp_sndrcvinfo info;
2870 if (get_struct(pid, args[sc->offset],
2871 &info, sizeof(struct sctp_sndrcvinfo)) == -1) {
2872 print_pointer(fp, args[sc->offset]);
2875 print_sctp_sndrcvinfo(fp, sc->type & OUT, &info);
2879 struct msghdr msghdr;
2881 if (get_struct(pid, args[sc->offset],
2882 &msghdr, sizeof(struct msghdr)) == -1) {
2883 print_pointer(fp, args[sc->offset]);
2887 print_sockaddr(fp, trussinfo, (uintptr_t)msghdr.msg_name, msghdr.msg_namelen);
2888 fprintf(fp, ",%d,", msghdr.msg_namelen);
2889 print_iovec(fp, trussinfo, (uintptr_t)msghdr.msg_iov, msghdr.msg_iovlen);
2890 fprintf(fp, ",%d,", msghdr.msg_iovlen);
2891 print_cmsgs(fp, pid, sc->type & OUT, &msghdr);
2892 fprintf(fp, ",%u,", msghdr.msg_controllen);
2893 print_mask_arg(sysdecode_msg_flags, fp, msghdr.msg_flags);
2898 case CloudABIAdvice:
2899 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
2901 case CloudABIClockID:
2902 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2904 case CloudABIFDSFlags:
2905 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2907 case CloudABIFDStat: {
2908 cloudabi_fdstat_t fds;
2909 if (get_struct(pid, args[sc->offset], &fds, sizeof(fds))
2911 fprintf(fp, "{ %s, ",
2912 xlookup(cloudabi_filetype, fds.fs_filetype));
2913 fprintf(fp, "%s, ... }",
2914 xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2916 print_pointer(fp, args[sc->offset]);
2919 case CloudABIFileStat: {
2920 cloudabi_filestat_t fsb;
2921 if (get_struct(pid, args[sc->offset], &fsb, sizeof(fsb))
2923 fprintf(fp, "{ %s, %ju }",
2924 xlookup(cloudabi_filetype, fsb.st_filetype),
2925 (uintmax_t)fsb.st_size);
2927 print_pointer(fp, args[sc->offset]);
2930 case CloudABIFileType:
2931 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2933 case CloudABIFSFlags:
2934 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2936 case CloudABILookup:
2937 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2938 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2939 (int)args[sc->offset]);
2941 fprintf(fp, "%d", (int)args[sc->offset]);
2943 case CloudABIMFlags:
2944 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2947 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2949 case CloudABIMSFlags:
2950 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2952 case CloudABIOFlags:
2953 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2955 case CloudABISDFlags:
2956 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2958 case CloudABISignal:
2959 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2961 case CloudABITimestamp:
2962 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2963 args[sc->offset] % 1000000000);
2965 case CloudABIULFlags:
2966 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2968 case CloudABIWhence:
2969 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2973 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2980 * Print (to outfile) the system call and its arguments.
2983 print_syscall(struct trussinfo *trussinfo)
2985 struct threadinfo *t;
2990 t = trussinfo->curthread;
2992 name = t->cs.sc->name;
2993 nargs = t->cs.nargs;
2994 s_args = t->cs.s_args;
2996 len = print_line_prefix(trussinfo);
2997 len += fprintf(trussinfo->outfile, "%s(", name);
2999 for (i = 0; i < nargs; i++) {
3000 if (s_args[i] != NULL)
3001 len += fprintf(trussinfo->outfile, "%s", s_args[i]);
3003 len += fprintf(trussinfo->outfile,
3004 "<missing argument>");
3005 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
3008 len += fprintf(trussinfo->outfile, ")");
3009 for (i = 0; i < 6 - (len / 8); i++)
3010 fprintf(trussinfo->outfile, "\t");
3014 print_syscall_ret(struct trussinfo *trussinfo, int error, register_t *retval)
3016 struct timespec timediff;
3017 struct threadinfo *t;
3020 t = trussinfo->curthread;
3022 if (trussinfo->flags & COUNTONLY) {
3023 timespecsub(&t->after, &t->before, &timediff);
3024 timespecadd(&sc->time, &timediff, &sc->time);
3031 print_syscall(trussinfo);
3032 fflush(trussinfo->outfile);
3034 if (retval == NULL) {
3036 * This system call resulted in the current thread's exit,
3037 * so there is no return value or error to display.
3039 fprintf(trussinfo->outfile, "\n");
3043 if (error == ERESTART)
3044 fprintf(trussinfo->outfile, " ERESTART\n");
3045 else if (error == EJUSTRETURN)
3046 fprintf(trussinfo->outfile, " EJUSTRETURN\n");
3047 else if (error != 0) {
3048 fprintf(trussinfo->outfile, " ERR#%d '%s'\n",
3049 sysdecode_freebsd_to_abi_errno(t->proc->abi->abi, error),
3051 } else if (sc->decode.ret_type == 2 &&
3052 t->proc->abi->pointer_size == 4) {
3054 #if _BYTE_ORDER == _LITTLE_ENDIAN
3055 off = (off_t)retval[1] << 32 | retval[0];
3057 off = (off_t)retval[0] << 32 | retval[1];
3059 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
3062 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n",
3063 (intmax_t)retval[0], (intmax_t)retval[0]);
3068 print_summary(struct trussinfo *trussinfo)
3070 struct timespec total = {0, 0};
3074 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
3075 "syscall", "seconds", "calls", "errors");
3077 STAILQ_FOREACH(sc, &seen_syscalls, entries) {
3079 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
3080 sc->name, (intmax_t)sc->time.tv_sec,
3081 sc->time.tv_nsec, sc->ncalls, sc->nerror);
3082 timespecadd(&total, &sc->time, &total);
3083 ncall += sc->ncalls;
3084 nerror += sc->nerror;
3087 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
3088 "", "-------------", "-------", "-------");
3089 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
3090 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);