1 /*-
2 * SPDX-License-Identifier: BSD-4-Clause
3 *
4 * Copyright 1997 Sean Eric Fagan
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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
19 * permission.
20 *
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
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 /*
38 * This file has routines used to print out system calls and their
39 * arguments.
40 */
41
42 #include <sys/aio.h>
43 #include <sys/capsicum.h>
44 #include <sys/types.h>
45 #define _WANT_FREEBSD11_KEVENT
46 #include <sys/event.h>
47 #include <sys/ioccom.h>
48 #include <sys/mman.h>
49 #include <sys/mount.h>
50 #include <sys/poll.h>
51 #include <sys/procfs.h>
52 #include <sys/ptrace.h>
53 #include <sys/resource.h>
54 #include <sys/sched.h>
55 #include <sys/socket.h>
56 #define _WANT_FREEBSD11_STAT
57 #include <sys/stat.h>
58 #include <sys/sysctl.h>
59 #include <sys/time.h>
60 #include <sys/un.h>
61 #include <sys/wait.h>
62 #include <netinet/in.h>
63 #include <netinet/sctp.h>
64 #include <arpa/inet.h>
65
66 #include <assert.h>
67 #include <ctype.h>
68 #include <err.h>
69 #define _WANT_KERNEL_ERRNO
70 #include <errno.h>
71 #include <fcntl.h>
72 #include <signal.h>
73 #include <stdbool.h>
74 #include <stdio.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include <sysdecode.h>
78 #include <unistd.h>
79 #include <vis.h>
80
81 #include <contrib/cloudabi/cloudabi_types_common.h>
82
83 #include "truss.h"
84 #include "extern.h"
85 #include "syscall.h"
86
87 /*
88 * This should probably be in its own file, sorted alphabetically.
89 *
90 * Note: We only scan this table on the initial syscall number to calling
91 * convention lookup, i.e. once each time a new syscall is encountered. This
92 * is unlikely to be a performance issue, but if it is we could sort this array
93 * and use a binary search instead.
94 */
95 static const struct syscall_decode decoded_syscalls[] = {
96 /* Native ABI */
97 { .name = "__acl_aclcheck_fd", .ret_type = 1, .nargs = 3,
98 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
99 { .name = "__acl_aclcheck_file", .ret_type = 1, .nargs = 3,
100 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
101 { .name = "__acl_aclcheck_link", .ret_type = 1, .nargs = 3,
102 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
103 { .name = "__acl_delete_fd", .ret_type = 1, .nargs = 2,
104 .args = { { Int, 0 }, { Acltype, 1 } } },
105 { .name = "__acl_delete_file", .ret_type = 1, .nargs = 2,
106 .args = { { Name, 0 }, { Acltype, 1 } } },
107 { .name = "__acl_delete_link", .ret_type = 1, .nargs = 2,
108 .args = { { Name, 0 }, { Acltype, 1 } } },
109 { .name = "__acl_get_fd", .ret_type = 1, .nargs = 3,
110 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
111 { .name = "__acl_get_file", .ret_type = 1, .nargs = 3,
112 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
113 { .name = "__acl_get_link", .ret_type = 1, .nargs = 3,
114 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
115 { .name = "__acl_set_fd", .ret_type = 1, .nargs = 3,
116 .args = { { Int, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
117 { .name = "__acl_set_file", .ret_type = 1, .nargs = 3,
118 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
119 { .name = "__acl_set_link", .ret_type = 1, .nargs = 3,
120 .args = { { Name, 0 }, { Acltype, 1 }, { Ptr, 2 } } },
121 { .name = "__cap_rights_get", .ret_type = 1, .nargs = 3,
122 .args = { { Int, 0 }, { Int, 1 }, { CapRights | OUT, 2 } } },
123 { .name = "__getcwd", .ret_type = 1, .nargs = 2,
124 .args = { { Name | OUT, 0 }, { Int, 1 } } },
125 { .name = "__realpathat", .ret_type = 1, .nargs = 5,
126 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Name | OUT, 2 },
127 { Sizet, 3 }, { Int, 4} } },
128 { .name = "_umtx_op", .ret_type = 1, .nargs = 5,
129 .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
130 { Ptr, 4 } } },
131 { .name = "accept", .ret_type = 1, .nargs = 3,
132 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
133 { .name = "access", .ret_type = 1, .nargs = 2,
134 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
135 { .name = "aio_cancel", .ret_type = 1, .nargs = 2,
136 .args = { { Int, 0 }, { Aiocb, 1 } } },
137 { .name = "aio_error", .ret_type = 1, .nargs = 1,
138 .args = { { Aiocb, 0 } } },
139 { .name = "aio_fsync", .ret_type = 1, .nargs = 2,
140 .args = { { AiofsyncOp, 0 }, { Aiocb, 1 } } },
141 { .name = "aio_mlock", .ret_type = 1, .nargs = 1,
142 .args = { { Aiocb, 0 } } },
143 { .name = "aio_read", .ret_type = 1, .nargs = 1,
144 .args = { { Aiocb, 0 } } },
145 { .name = "aio_return", .ret_type = 1, .nargs = 1,
146 .args = { { Aiocb, 0 } } },
147 { .name = "aio_suspend", .ret_type = 1, .nargs = 3,
148 .args = { { AiocbArray, 0 }, { Int, 1 }, { Timespec, 2 } } },
149 { .name = "aio_waitcomplete", .ret_type = 1, .nargs = 2,
150 .args = { { AiocbPointer | OUT, 0 }, { Timespec, 1 } } },
151 { .name = "aio_write", .ret_type = 1, .nargs = 1,
152 .args = { { Aiocb, 0 } } },
153 { .name = "bind", .ret_type = 1, .nargs = 3,
154 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
155 { .name = "bindat", .ret_type = 1, .nargs = 4,
156 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
157 { Int, 3 } } },
158 { .name = "break", .ret_type = 1, .nargs = 1,
159 .args = { { Ptr, 0 } } },
160 { .name = "cap_fcntls_get", .ret_type = 1, .nargs = 2,
161 .args = { { Int, 0 }, { CapFcntlRights | OUT, 1 } } },
162 { .name = "cap_fcntls_limit", .ret_type = 1, .nargs = 2,
163 .args = { { Int, 0 }, { CapFcntlRights, 1 } } },
164 { .name = "cap_getmode", .ret_type = 1, .nargs = 1,
165 .args = { { PUInt | OUT, 0 } } },
166 { .name = "cap_rights_limit", .ret_type = 1, .nargs = 2,
167 .args = { { Int, 0 }, { CapRights, 1 } } },
168 { .name = "chdir", .ret_type = 1, .nargs = 1,
169 .args = { { Name, 0 } } },
170 { .name = "chflags", .ret_type = 1, .nargs = 2,
171 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
172 { .name = "chflagsat", .ret_type = 1, .nargs = 4,
173 .args = { { Atfd, 0 }, { Name | IN, 1 }, { FileFlags, 2 },
174 { Atflags, 3 } } },
175 { .name = "chmod", .ret_type = 1, .nargs = 2,
176 .args = { { Name, 0 }, { Octal, 1 } } },
177 { .name = "chown", .ret_type = 1, .nargs = 3,
178 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
179 { .name = "chroot", .ret_type = 1, .nargs = 1,
180 .args = { { Name, 0 } } },
181 { .name = "clock_gettime", .ret_type = 1, .nargs = 2,
182 .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
183 { .name = "close", .ret_type = 1, .nargs = 1,
184 .args = { { Int, 0 } } },
185 { .name = "closefrom", .ret_type = 1, .nargs = 1,
186 .args = { { Int, 0 } } },
187 { .name = "close_range", .ret_type = 1, .nargs = 3,
188 .args = { { Int, 0 }, { Int, 1 }, { Closerangeflags, 2 } } },
189 { .name = "compat11.fstat", .ret_type = 1, .nargs = 2,
190 .args = { { Int, 0 }, { Stat11 | OUT, 1 } } },
191 { .name = "compat11.fstatat", .ret_type = 1, .nargs = 4,
192 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat11 | OUT, 2 },
193 { Atflags, 3 } } },
194 { .name = "compat11.kevent", .ret_type = 1, .nargs = 6,
195 .args = { { Int, 0 }, { Kevent11, 1 }, { Int, 2 },
196 { Kevent11 | OUT, 3 }, { Int, 4 }, { Timespec, 5 } } },
197 { .name = "compat11.lstat", .ret_type = 1, .nargs = 2,
198 .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } },
199 { .name = "compat11.mknod", .ret_type = 1, .nargs = 3,
200 .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
201 { .name = "compat11.mknodat", .ret_type = 1, .nargs = 4,
202 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
203 { .name = "compat11.stat", .ret_type = 1, .nargs = 2,
204 .args = { { Name | IN, 0 }, { Stat11 | OUT, 1 } } },
205 { .name = "connect", .ret_type = 1, .nargs = 3,
206 .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Socklent, 2 } } },
207 { .name = "connectat", .ret_type = 1, .nargs = 4,
208 .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
209 { Int, 3 } } },
210 { .name = "dup", .ret_type = 1, .nargs = 1,
211 .args = { { Int, 0 } } },
212 { .name = "dup2", .ret_type = 1, .nargs = 2,
213 .args = { { Int, 0 }, { Int, 1 } } },
214 { .name = "eaccess", .ret_type = 1, .nargs = 2,
215 .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
216 { .name = "execve", .ret_type = 1, .nargs = 3,
217 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
218 { ExecEnv | IN, 2 } } },
219 { .name = "exit", .ret_type = 0, .nargs = 1,
220 .args = { { Hex, 0 } } },
221 { .name = "extattr_delete_fd", .ret_type = 1, .nargs = 3,
222 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
223 { .name = "extattr_delete_file", .ret_type = 1, .nargs = 3,
224 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
225 { .name = "extattr_delete_link", .ret_type = 1, .nargs = 3,
226 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 } } },
227 { .name = "extattr_get_fd", .ret_type = 1, .nargs = 5,
228 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
229 { BinString | OUT, 3 }, { Sizet, 4 } } },
230 { .name = "extattr_get_file", .ret_type = 1, .nargs = 5,
231 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
232 { BinString | OUT, 3 }, { Sizet, 4 } } },
233 { .name = "extattr_get_link", .ret_type = 1, .nargs = 5,
234 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
235 { BinString | OUT, 3 }, { Sizet, 4 } } },
236 { .name = "extattr_list_fd", .ret_type = 1, .nargs = 4,
237 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
238 { Sizet, 3 } } },
239 { .name = "extattr_list_file", .ret_type = 1, .nargs = 4,
240 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
241 { Sizet, 3 } } },
242 { .name = "extattr_list_link", .ret_type = 1, .nargs = 4,
243 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { BinString | OUT, 2 },
244 { Sizet, 3 } } },
245 { .name = "extattr_set_fd", .ret_type = 1, .nargs = 5,
246 .args = { { Int, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
247 { BinString | IN, 3 }, { Sizet, 4 } } },
248 { .name = "extattr_set_file", .ret_type = 1, .nargs = 5,
249 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
250 { BinString | IN, 3 }, { Sizet, 4 } } },
251 { .name = "extattr_set_link", .ret_type = 1, .nargs = 5,
252 .args = { { Name, 0 }, { Extattrnamespace, 1 }, { Name, 2 },
253 { BinString | IN, 3 }, { Sizet, 4 } } },
254 { .name = "extattrctl", .ret_type = 1, .nargs = 5,
255 .args = { { Name, 0 }, { Hex, 1 }, { Name, 2 },
256 { Extattrnamespace, 3 }, { Name, 4 } } },
257 { .name = "faccessat", .ret_type = 1, .nargs = 4,
258 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
259 { Atflags, 3 } } },
260 { .name = "fchflags", .ret_type = 1, .nargs = 2,
261 .args = { { Int, 0 }, { FileFlags, 1 } } },
262 { .name = "fchmod", .ret_type = 1, .nargs = 2,
263 .args = { { Int, 0 }, { Octal, 1 } } },
264 { .name = "fchmodat", .ret_type = 1, .nargs = 4,
265 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
266 { .name = "fchown", .ret_type = 1, .nargs = 3,
267 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
268 { .name = "fchownat", .ret_type = 1, .nargs = 5,
269 .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
270 { Atflags, 4 } } },
271 { .name = "fcntl", .ret_type = 1, .nargs = 3,
272 .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
273 { .name = "fdatasync", .ret_type = 1, .nargs = 1,
274 .args = { { Int, 0 } } },
275 { .name = "flock", .ret_type = 1, .nargs = 2,
276 .args = { { Int, 0 }, { Flockop, 1 } } },
277 { .name = "fstat", .ret_type = 1, .nargs = 2,
278 .args = { { Int, 0 }, { Stat | OUT, 1 } } },
279 { .name = "fstatat", .ret_type = 1, .nargs = 4,
280 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
281 { Atflags, 3 } } },
282 { .name = "fstatfs", .ret_type = 1, .nargs = 2,
283 .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
284 { .name = "fsync", .ret_type = 1, .nargs = 1,
285 .args = { { Int, 0 } } },
286 { .name = "ftruncate", .ret_type = 1, .nargs = 2,
287 .args = { { Int | IN, 0 }, { QuadHex | IN, 1 } } },
288 { .name = "futimens", .ret_type = 1, .nargs = 2,
289 .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
290 { .name = "futimes", .ret_type = 1, .nargs = 2,
291 .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
292 { .name = "futimesat", .ret_type = 1, .nargs = 3,
293 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
294 { .name = "getdirentries", .ret_type = 1, .nargs = 4,
295 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
296 { PQuadHex | OUT, 3 } } },
297 { .name = "getfsstat", .ret_type = 1, .nargs = 3,
298 .args = { { Ptr, 0 }, { Long, 1 }, { Getfsstatmode, 2 } } },
299 { .name = "getitimer", .ret_type = 1, .nargs = 2,
300 .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
301 { .name = "getpeername", .ret_type = 1, .nargs = 3,
302 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
303 { .name = "getpgid", .ret_type = 1, .nargs = 1,
304 .args = { { Int, 0 } } },
305 { .name = "getpriority", .ret_type = 1, .nargs = 2,
306 .args = { { Priowhich, 0 }, { Int, 1 } } },
307 { .name = "getrandom", .ret_type = 1, .nargs = 3,
308 .args = { { BinString | OUT, 0 }, { Sizet, 1 }, { UInt, 2 } } },
309 { .name = "getrlimit", .ret_type = 1, .nargs = 2,
310 .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
311 { .name = "getrusage", .ret_type = 1, .nargs = 2,
312 .args = { { RusageWho, 0 }, { Rusage | OUT, 1 } } },
313 { .name = "getsid", .ret_type = 1, .nargs = 1,
314 .args = { { Int, 0 } } },
315 { .name = "getsockname", .ret_type = 1, .nargs = 3,
316 .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
317 { .name = "getsockopt", .ret_type = 1, .nargs = 5,
318 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
319 { Ptr | OUT, 3 }, { Ptr | OUT, 4 } } },
320 { .name = "gettimeofday", .ret_type = 1, .nargs = 2,
321 .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
322 { .name = "ioctl", .ret_type = 1, .nargs = 3,
323 .args = { { Int, 0 }, { Ioctl, 1 }, { Ptr, 2 } } },
324 { .name = "kevent", .ret_type = 1, .nargs = 6,
325 .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
326 { Int, 4 }, { Timespec, 5 } } },
327 { .name = "kill", .ret_type = 1, .nargs = 2,
328 .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
329 { .name = "kldfind", .ret_type = 1, .nargs = 1,
330 .args = { { Name | IN, 0 } } },
331 { .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
332 .args = { { Int, 0 } } },
333 { .name = "kldload", .ret_type = 1, .nargs = 1,
334 .args = { { Name | IN, 0 } } },
335 { .name = "kldnext", .ret_type = 1, .nargs = 1,
336 .args = { { Int, 0 } } },
337 { .name = "kldstat", .ret_type = 1, .nargs = 2,
338 .args = { { Int, 0 }, { Ptr, 1 } } },
339 { .name = "kldsym", .ret_type = 1, .nargs = 3,
340 .args = { { Int, 0 }, { Kldsymcmd, 1 }, { Ptr, 2 } } },
341 { .name = "kldunload", .ret_type = 1, .nargs = 1,
342 .args = { { Int, 0 } } },
343 { .name = "kldunloadf", .ret_type = 1, .nargs = 2,
344 .args = { { Int, 0 }, { Kldunloadflags, 1 } } },
345 { .name = "kse_release", .ret_type = 0, .nargs = 1,
346 .args = { { Timespec, 0 } } },
347 { .name = "lchflags", .ret_type = 1, .nargs = 2,
348 .args = { { Name | IN, 0 }, { FileFlags, 1 } } },
349 { .name = "lchmod", .ret_type = 1, .nargs = 2,
350 .args = { { Name, 0 }, { Octal, 1 } } },
351 { .name = "lchown", .ret_type = 1, .nargs = 3,
352 .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
353 { .name = "link", .ret_type = 1, .nargs = 2,
354 .args = { { Name, 0 }, { Name, 1 } } },
355 { .name = "linkat", .ret_type = 1, .nargs = 5,
356 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
357 { Atflags, 4 } } },
358 { .name = "lio_listio", .ret_type = 1, .nargs = 4,
359 .args = { { LioMode, 0 }, { AiocbArray, 1 }, { Int, 2 },
360 { Sigevent, 3 } } },
361 { .name = "listen", .ret_type = 1, .nargs = 2,
362 .args = { { Int, 0 }, { Int, 1 } } },
363 { .name = "lseek", .ret_type = 2, .nargs = 3,
364 .args = { { Int, 0 }, { QuadHex, 1 }, { Whence, 2 } } },
365 { .name = "lstat", .ret_type = 1, .nargs = 2,
366 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
367 { .name = "lutimes", .ret_type = 1, .nargs = 2,
368 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
369 { .name = "madvise", .ret_type = 1, .nargs = 3,
370 .args = { { Ptr, 0 }, { Sizet, 1 }, { Madvice, 2 } } },
371 { .name = "minherit", .ret_type = 1, .nargs = 3,
372 .args = { { Ptr, 0 }, { Sizet, 1 }, { Minherit, 2 } } },
373 { .name = "mkdir", .ret_type = 1, .nargs = 2,
374 .args = { { Name, 0 }, { Octal, 1 } } },
375 { .name = "mkdirat", .ret_type = 1, .nargs = 3,
376 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
377 { .name = "mkfifo", .ret_type = 1, .nargs = 2,
378 .args = { { Name, 0 }, { Octal, 1 } } },
379 { .name = "mkfifoat", .ret_type = 1, .nargs = 3,
380 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
381 { .name = "mknod", .ret_type = 1, .nargs = 3,
382 .args = { { Name, 0 }, { Octal, 1 }, { Quad, 2 } } },
383 { .name = "mknodat", .ret_type = 1, .nargs = 4,
384 .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Quad, 3 } } },
385 { .name = "mlock", .ret_type = 1, .nargs = 2,
386 .args = { { Ptr, 0 }, { Sizet, 1 } } },
387 { .name = "mlockall", .ret_type = 1, .nargs = 1,
388 .args = { { Mlockall, 0 } } },
389 { .name = "mmap", .ret_type = 1, .nargs = 6,
390 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
391 { Int, 4 }, { QuadHex, 5 } } },
392 { .name = "modfind", .ret_type = 1, .nargs = 1,
393 .args = { { Name | IN, 0 } } },
394 { .name = "mount", .ret_type = 1, .nargs = 4,
395 .args = { { Name, 0 }, { Name, 1 }, { Mountflags, 2 }, { Ptr, 3 } } },
396 { .name = "mprotect", .ret_type = 1, .nargs = 3,
397 .args = { { Ptr, 0 }, { Sizet, 1 }, { Mprot, 2 } } },
398 { .name = "msync", .ret_type = 1, .nargs = 3,
399 .args = { { Ptr, 0 }, { Sizet, 1 }, { Msync, 2 } } },
400 { .name = "munlock", .ret_type = 1, .nargs = 2,
401 .args = { { Ptr, 0 }, { Sizet, 1 } } },
402 { .name = "munmap", .ret_type = 1, .nargs = 2,
403 .args = { { Ptr, 0 }, { Sizet, 1 } } },
404 { .name = "nanosleep", .ret_type = 1, .nargs = 1,
405 .args = { { Timespec, 0 } } },
406 { .name = "nmount", .ret_type = 1, .nargs = 3,
407 .args = { { Ptr, 0 }, { UInt, 1 }, { Mountflags, 2 } } },
408 { .name = "open", .ret_type = 1, .nargs = 3,
409 .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
410 { .name = "openat", .ret_type = 1, .nargs = 4,
411 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
412 { Octal, 3 } } },
413 { .name = "pathconf", .ret_type = 1, .nargs = 2,
414 .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
415 { .name = "pipe", .ret_type = 1, .nargs = 1,
416 .args = { { PipeFds | OUT, 0 } } },
417 { .name = "pipe2", .ret_type = 1, .nargs = 2,
418 .args = { { Ptr, 0 }, { Pipe2, 1 } } },
419 { .name = "poll", .ret_type = 1, .nargs = 3,
420 .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
421 { .name = "posix_fadvise", .ret_type = 1, .nargs = 4,
422 .args = { { Int, 0 }, { QuadHex, 1 }, { QuadHex, 2 },
423 { Fadvice, 3 } } },
424 { .name = "posix_openpt", .ret_type = 1, .nargs = 1,
425 .args = { { Open, 0 } } },
426 { .name = "pread", .ret_type = 1, .nargs = 4,
427 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
428 { QuadHex, 3 } } },
429 { .name = "procctl", .ret_type = 1, .nargs = 4,
430 .args = { { Idtype, 0 }, { Quad, 1 }, { Procctl, 2 }, { Ptr, 3 } } },
431 { .name = "ptrace", .ret_type = 1, .nargs = 4,
432 .args = { { Ptraceop, 0 }, { Int, 1 }, { Ptr, 2 }, { Int, 3 } } },
433 { .name = "pwrite", .ret_type = 1, .nargs = 4,
434 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
435 { QuadHex, 3 } } },
436 { .name = "quotactl", .ret_type = 1, .nargs = 4,
437 .args = { { Name, 0 }, { Quotactlcmd, 1 }, { Int, 2 }, { Ptr, 3 } } },
438 { .name = "read", .ret_type = 1, .nargs = 3,
439 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 } } },
440 { .name = "readlink", .ret_type = 1, .nargs = 3,
441 .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Sizet, 2 } } },
442 { .name = "readlinkat", .ret_type = 1, .nargs = 4,
443 .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
444 { Sizet, 3 } } },
445 { .name = "readv", .ret_type = 1, .nargs = 3,
446 .args = { { Int, 0 }, { Iovec | OUT, 1 }, { Int, 2 } } },
447 { .name = "reboot", .ret_type = 1, .nargs = 1,
448 .args = { { Reboothowto, 0 } } },
449 { .name = "recvfrom", .ret_type = 1, .nargs = 6,
450 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Sizet, 2 },
451 { Msgflags, 3 }, { Sockaddr | OUT, 4 },
452 { Ptr | OUT, 5 } } },
453 { .name = "recvmsg", .ret_type = 1, .nargs = 3,
454 .args = { { Int, 0 }, { Msghdr | OUT, 1 }, { Msgflags, 2 } } },
455 { .name = "rename", .ret_type = 1, .nargs = 2,
456 .args = { { Name, 0 }, { Name, 1 } } },
457 { .name = "renameat", .ret_type = 1, .nargs = 4,
458 .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
459 { .name = "rfork", .ret_type = 1, .nargs = 1,
460 .args = { { Rforkflags, 0 } } },
461 { .name = "rmdir", .ret_type = 1, .nargs = 1,
462 .args = { { Name, 0 } } },
463 { .name = "rtprio", .ret_type = 1, .nargs = 3,
464 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
465 { .name = "rtprio_thread", .ret_type = 1, .nargs = 3,
466 .args = { { Rtpriofunc, 0 }, { Int, 1 }, { Ptr, 2 } } },
467 { .name = "sched_get_priority_max", .ret_type = 1, .nargs = 1,
468 .args = { { Schedpolicy, 0 } } },
469 { .name = "sched_get_priority_min", .ret_type = 1, .nargs = 1,
470 .args = { { Schedpolicy, 0 } } },
471 { .name = "sched_getparam", .ret_type = 1, .nargs = 2,
472 .args = { { Int, 0 }, { Schedparam | OUT, 1 } } },
473 { .name = "sched_getscheduler", .ret_type = 1, .nargs = 1,
474 .args = { { Int, 0 } } },
475 { .name = "sched_rr_get_interval", .ret_type = 1, .nargs = 2,
476 .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
477 { .name = "sched_setparam", .ret_type = 1, .nargs = 2,
478 .args = { { Int, 0 }, { Schedparam, 1 } } },
479 { .name = "sched_setscheduler", .ret_type = 1, .nargs = 3,
480 .args = { { Int, 0 }, { Schedpolicy, 1 }, { Schedparam, 2 } } },
481 { .name = "sctp_generic_recvmsg", .ret_type = 1, .nargs = 7,
482 .args = { { Int, 0 }, { Iovec | OUT, 1 }, { Int, 2 },
483 { Sockaddr | OUT, 3 }, { Ptr | OUT, 4 },
484 { Sctpsndrcvinfo | OUT, 5 }, { Ptr | OUT, 6 } } },
485 { .name = "sctp_generic_sendmsg", .ret_type = 1, .nargs = 7,
486 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
487 { Sockaddr | IN, 3 }, { Socklent, 4 },
488 { Sctpsndrcvinfo | IN, 5 }, { Msgflags, 6 } } },
489 { .name = "sctp_generic_sendmsg_iov", .ret_type = 1, .nargs = 7,
490 .args = { { Int, 0 }, { Iovec | IN, 1 }, { Int, 2 },
491 { Sockaddr | IN, 3 }, { Socklent, 4 },
492 { Sctpsndrcvinfo | IN, 5 }, { Msgflags, 6 } } },
493 { .name = "sendfile", .ret_type = 1, .nargs = 7,
494 .args = { { Int, 0 }, { Int, 1 }, { QuadHex, 2 }, { Sizet, 3 },
495 { Sendfilehdtr, 4 }, { QuadHex | OUT, 5 },
496 { Sendfileflags, 6 } } },
497 { .name = "select", .ret_type = 1, .nargs = 5,
498 .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
499 { Timeval, 4 } } },
500 { .name = "sendmsg", .ret_type = 1, .nargs = 3,
501 .args = { { Int, 0 }, { Msghdr | IN, 1 }, { Msgflags, 2 } } },
502 { .name = "sendto", .ret_type = 1, .nargs = 6,
503 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 },
504 { Msgflags, 3 }, { Sockaddr | IN, 4 },
505 { Socklent | IN, 5 } } },
506 { .name = "setitimer", .ret_type = 1, .nargs = 3,
507 .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
508 { .name = "setpriority", .ret_type = 1, .nargs = 3,
509 .args = { { Priowhich, 0 }, { Int, 1 }, { Int, 2 } } },
510 { .name = "setrlimit", .ret_type = 1, .nargs = 2,
511 .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
512 { .name = "setsockopt", .ret_type = 1, .nargs = 5,
513 .args = { { Int, 0 }, { Sockoptlevel, 1 }, { Sockoptname, 2 },
514 { Ptr | IN, 3 }, { Socklent, 4 } } },
515 { .name = "shm_open", .ret_type = 1, .nargs = 3,
516 .args = { { ShmName | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
517 { .name = "shm_open2", .ret_type = 1, .nargs = 5,
518 .args = { { ShmName | IN, 0 }, { Open, 1 }, { Octal, 2 },
519 { ShmFlags, 3 }, { Name | IN, 4 } } },
520 { .name = "shm_rename", .ret_type = 1, .nargs = 3,
521 .args = { { Name | IN, 0 }, { Name | IN, 1 }, { Hex, 2 } } },
522 { .name = "shm_unlink", .ret_type = 1, .nargs = 1,
523 .args = { { Name | IN, 0 } } },
524 { .name = "shutdown", .ret_type = 1, .nargs = 2,
525 .args = { { Int, 0 }, { Shutdown, 1 } } },
526 { .name = "sigaction", .ret_type = 1, .nargs = 3,
527 .args = { { Signal, 0 }, { Sigaction | IN, 1 },
528 { Sigaction | OUT, 2 } } },
529 { .name = "sigpending", .ret_type = 1, .nargs = 1,
530 .args = { { Sigset | OUT, 0 } } },
531 { .name = "sigprocmask", .ret_type = 1, .nargs = 3,
532 .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
533 { .name = "sigqueue", .ret_type = 1, .nargs = 3,
534 .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
535 { .name = "sigreturn", .ret_type = 1, .nargs = 1,
536 .args = { { Ptr, 0 } } },
537 { .name = "sigsuspend", .ret_type = 1, .nargs = 1,
538 .args = { { Sigset | IN, 0 } } },
539 { .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
540 .args = { { Sigset | IN, 0 }, { Siginfo | OUT, 1 },
541 { Timespec | IN, 2 } } },
542 { .name = "sigwait", .ret_type = 1, .nargs = 2,
543 .args = { { Sigset | IN, 0 }, { PSig | OUT, 1 } } },
544 { .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
545 .args = { { Sigset | IN, 0 }, { Siginfo | OUT, 1 } } },
546 { .name = "socket", .ret_type = 1, .nargs = 3,
547 .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Sockprotocol, 2 } } },
548 { .name = "stat", .ret_type = 1, .nargs = 2,
549 .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
550 { .name = "statfs", .ret_type = 1, .nargs = 2,
551 .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } },
552 { .name = "symlink", .ret_type = 1, .nargs = 2,
553 .args = { { Name, 0 }, { Name, 1 } } },
554 { .name = "symlinkat", .ret_type = 1, .nargs = 3,
555 .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } },
556 { .name = "sysarch", .ret_type = 1, .nargs = 2,
557 .args = { { Sysarch, 0 }, { Ptr, 1 } } },
558 { .name = "__sysctl", .ret_type = 1, .nargs = 6,
559 .args = { { Sysctl, 0 }, { Sizet, 1 }, { Ptr, 2 }, { Ptr, 3 },
560 { Ptr, 4 }, { Sizet, 5 } } },
561 { .name = "__sysctlbyname", .ret_type = 1, .nargs = 6,
562 .args = { { Name, 0 }, { Sizet, 1 }, { Ptr, 2 }, { Ptr, 3 },
563 { Ptr, 4}, { Sizet, 5 } } },
564 { .name = "thr_kill", .ret_type = 1, .nargs = 2,
565 .args = { { Long, 0 }, { Signal, 1 } } },
566 { .name = "thr_self", .ret_type = 1, .nargs = 1,
567 .args = { { Ptr, 0 } } },
568 { .name = "thr_set_name", .ret_type = 1, .nargs = 2,
569 .args = { { Long, 0 }, { Name, 1 } } },
570 { .name = "truncate", .ret_type = 1, .nargs = 2,
571 .args = { { Name | IN, 0 }, { QuadHex | IN, 1 } } },
572 #if 0
573 /* Does not exist */
574 { .name = "umount", .ret_type = 1, .nargs = 2,
575 .args = { { Name, 0 }, { Int, 2 } } },
576 #endif
577 { .name = "unlink", .ret_type = 1, .nargs = 1,
578 .args = { { Name, 0 } } },
579 { .name = "unlinkat", .ret_type = 1, .nargs = 3,
580 .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
581 { .name = "unmount", .ret_type = 1, .nargs = 2,
582 .args = { { Name, 0 }, { Mountflags, 1 } } },
583 { .name = "utimensat", .ret_type = 1, .nargs = 4,
584 .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
585 { Atflags, 3 } } },
586 { .name = "utimes", .ret_type = 1, .nargs = 2,
587 .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
588 { .name = "utrace", .ret_type = 1, .nargs = 1,
589 .args = { { Utrace, 0 } } },
590 { .name = "wait4", .ret_type = 1, .nargs = 4,
591 .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
592 { Rusage | OUT, 3 } } },
593 { .name = "wait6", .ret_type = 1, .nargs = 6,
594 .args = { { Idtype, 0 }, { Quad, 1 }, { ExitStatus | OUT, 2 },
595 { Waitoptions, 3 }, { Rusage | OUT, 4 },
596 { Siginfo | OUT, 5 } } },
597 { .name = "write", .ret_type = 1, .nargs = 3,
598 .args = { { Int, 0 }, { BinString | IN, 1 }, { Sizet, 2 } } },
599 { .name = "writev", .ret_type = 1, .nargs = 3,
600 .args = { { Int, 0 }, { Iovec | IN, 1 }, { Int, 2 } } },
601
602 /* Linux ABI */
603 { .name = "linux_access", .ret_type = 1, .nargs = 2,
604 .args = { { Name, 0 }, { Accessmode, 1 } } },
605 { .name = "linux_execve", .ret_type = 1, .nargs = 3,
606 .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
607 { ExecEnv | IN, 2 } } },
608 { .name = "linux_lseek", .ret_type = 2, .nargs = 3,
609 .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
610 { .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
611 .args = { { Name | IN, 0 }, { Int, 1 } } },
612 { .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
613 .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
614 { .name = "linux_newstat", .ret_type = 1, .nargs = 2,
615 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
616 { .name = "linux_open", .ret_type = 1, .nargs = 3,
617 .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
618 { .name = "linux_readlink", .ret_type = 1, .nargs = 3,
619 .args = { { Name, 0 }, { Name | OUT, 1 }, { Sizet, 2 } } },
620 { .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
621 .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
622 { .name = "linux_stat64", .ret_type = 1, .nargs = 2,
623 .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
624
625 /* CloudABI system calls. */
626 { .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
627 .args = { { CloudABIClockID, 0 } } },
628 { .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
629 .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
630 { .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
631 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
632 { .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
633 .args = { { Int, 0 } } },
634 { .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
635 .args = { { CloudABIFileType, 0 } } },
636 { .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
637 .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
638 { .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
639 .args = { { Int, 0 } } },
640 { .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
641 .args = { { Int, 0 } } },
642 { .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
643 .args = { { Int, 0 }, { Int, 1 } } },
644 { .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
645 .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
646 { .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
647 .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
648 { .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
649 .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
650 { CloudABIFDSFlags, 2 } } },
651 { .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
652 .args = { { Int, 0 } } },
653 { .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
654 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
655 { CloudABIAdvice, 3 } } },
656 { .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
657 .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
658 { .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
659 .args = { { Int, 0 }, { BinString | IN, 1 },
660 { CloudABIFileType, 3 } } },
661 { .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
662 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
663 { Int, 3 }, { BinString | IN, 4 } } },
664 { .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
665 .args = { { Int, 0 }, { BinString | IN, 1 },
666 { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
667 { .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
668 .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
669 { Int, 3 } } },
670 { .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
671 .args = { { Int, 0 }, { BinString | IN, 1 },
672 { BinString | OUT, 3 }, { Int, 4 } } },
673 { .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
674 .args = { { Int, 0 }, { BinString | IN, 1 },
675 { Int, 3 }, { BinString | IN, 4 } } },
676 { .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
677 .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
678 { .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
679 .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
680 { CloudABIFSFlags, 2 } } },
681 { .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
682 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
683 { CloudABIFileStat | OUT, 3 } } },
684 { .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
685 .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
686 { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
687 { .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
688 .args = { { BinString | IN, 0 },
689 { Int, 2 }, { BinString | IN, 3 } } },
690 { .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
691 .args = { { Int, 0 }, { BinString | IN, 1 },
692 { CloudABIULFlags, 3 } } },
693 { .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
694 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
695 { .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
696 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
697 { .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
698 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
699 { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
700 { .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
701 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
702 { .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
703 .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
704 { .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
705 .args = { { Ptr, 0 }, { Int, 1 } } },
706 { .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
707 .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
708 { IntArray, 3 }, { Int, 4 } } },
709 { .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
710 .args = { { Int, 0 } } },
711 { .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
712 { .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
713 .args = { { CloudABISignal, 0 } } },
714 { .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
715 .args = { { BinString | OUT, 0 }, { Int, 1 } } },
716 { .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
717 .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
718 { .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
719 .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
720 { .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
721 };
722 static STAILQ_HEAD(, syscall) seen_syscalls;
723
724 /* Xlat idea taken from strace */
725 struct xlat {
726 int val;
727 const char *str;
728 };
729
730 #define X(a) { a, #a },
731 #define XEND { 0, NULL }
732
733 static struct xlat poll_flags[] = {
734 X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
735 X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
736 X(POLLWRBAND) X(POLLINIGNEOF) XEND
737 };
738
739 static struct xlat sigaction_flags[] = {
740 X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
741 X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
742 };
743
744 static struct xlat linux_socketcall_ops[] = {
745 X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
746 X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
747 X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
748 X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
749 X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
750 XEND
751 };
752
753 static struct xlat lio_modes[] = {
754 X(LIO_WAIT) X(LIO_NOWAIT)
755 XEND
756 };
757
758 static struct xlat lio_opcodes[] = {
759 X(LIO_WRITE) X(LIO_READ) X(LIO_NOP)
760 XEND
761 };
762
763 static struct xlat aio_fsync_ops[] = {
764 X(O_SYNC)
765 XEND
766 };
767
768 #undef X
769 #define X(a) { CLOUDABI_##a, #a },
770
771 static struct xlat cloudabi_advice[] = {
772 X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
773 X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
774 XEND
775 };
776
777 static struct xlat cloudabi_clockid[] = {
778 X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
779 X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
780 XEND
781 };
782
783 static struct xlat cloudabi_fdflags[] = {
784 X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
785 X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
786 XEND
787 };
788
789 static struct xlat cloudabi_fdsflags[] = {
790 X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
791 XEND
792 };
793
794 static struct xlat cloudabi_filetype[] = {
795 X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
796 X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
797 X(FILETYPE_PROCESS) X(FILETYPE_REGULAR_FILE)
798 X(FILETYPE_SHARED_MEMORY) X(FILETYPE_SOCKET_DGRAM)
799 X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK)
800 XEND
801 };
802
803 static struct xlat cloudabi_fsflags[] = {
804 X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
805 X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
806 XEND
807 };
808
809 static struct xlat cloudabi_mflags[] = {
810 X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
811 XEND
812 };
813
814 static struct xlat cloudabi_mprot[] = {
815 X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
816 XEND
817 };
818
819 static struct xlat cloudabi_msflags[] = {
820 X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
821 XEND
822 };
823
824 static struct xlat cloudabi_oflags[] = {
825 X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
826 XEND
827 };
828
829 static struct xlat cloudabi_sdflags[] = {
830 X(SHUT_RD) X(SHUT_WR)
831 XEND
832 };
833
834 static struct xlat cloudabi_signal[] = {
835 X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
836 X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
837 X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
838 X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
839 X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
840 XEND
841 };
842
843 static struct xlat cloudabi_ulflags[] = {
844 X(UNLINK_REMOVEDIR)
845 XEND
846 };
847
848 static struct xlat cloudabi_whence[] = {
849 X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
850 XEND
851 };
852
853 #undef X
854 #undef XEND
855
856 /*
857 * Searches an xlat array for a value, and returns it if found. Otherwise
858 * return a string representation.
859 */
860 static const char *
lookup(struct xlat * xlat,int val,int base)861 lookup(struct xlat *xlat, int val, int base)
862 {
863 static char tmp[16];
864
865 for (; xlat->str != NULL; xlat++)
866 if (xlat->val == val)
867 return (xlat->str);
868 switch (base) {
869 case 8:
870 sprintf(tmp, "0%o", val);
871 break;
872 case 16:
873 sprintf(tmp, "0x%x", val);
874 break;
875 case 10:
876 sprintf(tmp, "%u", val);
877 break;
878 default:
879 errx(1, "Unknown lookup base");
880 }
881 return (tmp);
882 }
883
884 static const char *
xlookup(struct xlat * xlat,int val)885 xlookup(struct xlat *xlat, int val)
886 {
887
888 return (lookup(xlat, val, 16));
889 }
890
891 /*
892 * Searches an xlat array containing bitfield values. Remaining bits
893 * set after removing the known ones are printed at the end:
894 * IN|0x400.
895 */
896 static char *
xlookup_bits(struct xlat * xlat,int val)897 xlookup_bits(struct xlat *xlat, int val)
898 {
899 int len, rem;
900 static char str[512];
901
902 len = 0;
903 rem = val;
904 for (; xlat->str != NULL; xlat++) {
905 if ((xlat->val & rem) == xlat->val) {
906 /*
907 * Don't print the "all-bits-zero" string unless all
908 * bits are really zero.
909 */
910 if (xlat->val == 0 && val != 0)
911 continue;
912 len += sprintf(str + len, "%s|", xlat->str);
913 rem &= ~(xlat->val);
914 }
915 }
916
917 /*
918 * If we have leftover bits or didn't match anything, print
919 * the remainder.
920 */
921 if (rem || len == 0)
922 len += sprintf(str + len, "0x%x", rem);
923 if (len && str[len - 1] == '|')
924 len--;
925 str[len] = 0;
926 return (str);
927 }
928
929 static void
print_integer_arg(const char * (* decoder)(int),FILE * fp,int value)930 print_integer_arg(const char *(*decoder)(int), FILE *fp, int value)
931 {
932 const char *str;
933
934 str = decoder(value);
935 if (str != NULL)
936 fputs(str, fp);
937 else
938 fprintf(fp, "%d", value);
939 }
940
941 static bool
print_mask_arg_part(bool (* decoder)(FILE *,int,int *),FILE * fp,int value,int * rem)942 print_mask_arg_part(bool (*decoder)(FILE *, int, int *), FILE *fp, int value,
943 int *rem)
944 {
945
946 return (decoder(fp, value, rem));
947 }
948
949 static void
print_mask_arg(bool (* decoder)(FILE *,int,int *),FILE * fp,int value)950 print_mask_arg(bool (*decoder)(FILE *, int, int *), FILE *fp, int value)
951 {
952 int rem;
953
954 if (!print_mask_arg_part(decoder, fp, value, &rem))
955 fprintf(fp, "0x%x", rem);
956 else if (rem != 0)
957 fprintf(fp, "|0x%x", rem);
958 }
959
960 static void
print_mask_arg32(bool (* decoder)(FILE *,uint32_t,uint32_t *),FILE * fp,uint32_t value)961 print_mask_arg32(bool (*decoder)(FILE *, uint32_t, uint32_t *), FILE *fp,
962 uint32_t value)
963 {
964 uint32_t rem;
965
966 if (!decoder(fp, value, &rem))
967 fprintf(fp, "0x%x", rem);
968 else if (rem != 0)
969 fprintf(fp, "|0x%x", rem);
970 }
971
972 /*
973 * Add argument padding to subsequent system calls after Quad
974 * syscall arguments as needed. This used to be done by hand in the
975 * decoded_syscalls table which was ugly and error prone. It is
976 * simpler to do the fixup of offsets at initialization time than when
977 * decoding arguments.
978 */
979 static void
quad_fixup(struct syscall_decode * sc)980 quad_fixup(struct syscall_decode *sc)
981 {
982 int offset, prev;
983 u_int i;
984
985 offset = 0;
986 prev = -1;
987 for (i = 0; i < sc->nargs; i++) {
988 /* This arg type is a dummy that doesn't use offset. */
989 if ((sc->args[i].type & ARG_MASK) == PipeFds)
990 continue;
991
992 assert(prev < sc->args[i].offset);
993 prev = sc->args[i].offset;
994 sc->args[i].offset += offset;
995 switch (sc->args[i].type & ARG_MASK) {
996 case Quad:
997 case QuadHex:
998 #ifdef __powerpc__
999 /*
1000 * 64-bit arguments on 32-bit powerpc must be
1001 * 64-bit aligned. If the current offset is
1002 * not aligned, the calling convention inserts
1003 * a 32-bit pad argument that should be skipped.
1004 */
1005 if (sc->args[i].offset % 2 == 1) {
1006 sc->args[i].offset++;
1007 offset++;
1008 }
1009 #endif
1010 offset++;
1011 default:
1012 break;
1013 }
1014 }
1015 }
1016
1017 static struct syscall *
find_syscall(struct procabi * abi,u_int number)1018 find_syscall(struct procabi *abi, u_int number)
1019 {
1020 struct extra_syscall *es;
1021
1022 if (number < nitems(abi->syscalls))
1023 return (abi->syscalls[number]);
1024 STAILQ_FOREACH(es, &abi->extra_syscalls, entries) {
1025 if (es->number == number)
1026 return (es->sc);
1027 }
1028 return (NULL);
1029 }
1030
1031 static void
add_syscall(struct procabi * abi,u_int number,struct syscall * sc)1032 add_syscall(struct procabi *abi, u_int number, struct syscall *sc)
1033 {
1034 struct extra_syscall *es;
1035
1036 /*
1037 * quad_fixup() is currently needed for all 32-bit ABIs.
1038 * TODO: This should probably be a function pointer inside struct
1039 * procabi instead.
1040 */
1041 if (abi->pointer_size == 4)
1042 quad_fixup(&sc->decode);
1043
1044 if (number < nitems(abi->syscalls)) {
1045 assert(abi->syscalls[number] == NULL);
1046 abi->syscalls[number] = sc;
1047 } else {
1048 es = malloc(sizeof(*es));
1049 es->sc = sc;
1050 es->number = number;
1051 STAILQ_INSERT_TAIL(&abi->extra_syscalls, es, entries);
1052 }
1053
1054 STAILQ_INSERT_HEAD(&seen_syscalls, sc, entries);
1055 }
1056
1057 /*
1058 * If/when the list gets big, it might be desirable to do it
1059 * as a hash table or binary search.
1060 */
1061 struct syscall *
get_syscall(struct threadinfo * t,u_int number,u_int nargs)1062 get_syscall(struct threadinfo *t, u_int number, u_int nargs)
1063 {
1064 struct syscall *sc;
1065 struct procabi *procabi;
1066 const char *sysdecode_name;
1067 const char *lookup_name;
1068 const char *name;
1069 u_int i;
1070
1071 procabi = t->proc->abi;
1072 sc = find_syscall(procabi, number);
1073 if (sc != NULL)
1074 return (sc);
1075
1076 /* Memory is not explicitly deallocated, it's released on exit(). */
1077 sysdecode_name = sysdecode_syscallname(procabi->abi, number);
1078 if (sysdecode_name == NULL)
1079 asprintf(__DECONST(char **, &name), "#%d", number);
1080 else
1081 name = sysdecode_name;
1082
1083 sc = calloc(1, sizeof(*sc));
1084 sc->name = name;
1085
1086 /* Also decode compat syscalls arguments by stripping the prefix. */
1087 lookup_name = name;
1088 if (procabi->compat_prefix != NULL && strncmp(procabi->compat_prefix,
1089 name, strlen(procabi->compat_prefix)) == 0)
1090 lookup_name += strlen(procabi->compat_prefix);
1091
1092 for (i = 0; i < nitems(decoded_syscalls); i++) {
1093 if (strcmp(lookup_name, decoded_syscalls[i].name) == 0) {
1094 sc->decode = decoded_syscalls[i];
1095 add_syscall(t->proc->abi, number, sc);
1096 return (sc);
1097 }
1098 }
1099
1100 /* It is unknown. Add it into the list. */
1101 #if DEBUG
1102 fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
1103 nargs);
1104 #endif
1105 sc->unknown = sysdecode_name == NULL;
1106 sc->decode.ret_type = 1; /* Assume 1 return value. */
1107 sc->decode.nargs = nargs;
1108 for (i = 0; i < nargs; i++) {
1109 sc->decode.args[i].offset = i;
1110 /* Treat all unknown arguments as LongHex. */
1111 sc->decode.args[i].type = LongHex;
1112 }
1113 add_syscall(t->proc->abi, number, sc);
1114 return (sc);
1115 }
1116
1117 /*
1118 * Copy a fixed amount of bytes from the process.
1119 */
1120 static int
get_struct(pid_t pid,psaddr_t offset,void * buf,size_t len)1121 get_struct(pid_t pid, psaddr_t offset, void *buf, size_t len)
1122 {
1123 struct ptrace_io_desc iorequest;
1124
1125 iorequest.piod_op = PIOD_READ_D;
1126 iorequest.piod_offs = (void *)(uintptr_t)offset;
1127 iorequest.piod_addr = buf;
1128 iorequest.piod_len = len;
1129 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
1130 return (-1);
1131 return (0);
1132 }
1133
1134 #define MAXSIZE 4096
1135
1136 /*
1137 * Copy a string from the process. Note that it is
1138 * expected to be a C string, but if max is set, it will
1139 * only get that much.
1140 */
1141 static char *
get_string(pid_t pid,psaddr_t addr,int max)1142 get_string(pid_t pid, psaddr_t addr, int max)
1143 {
1144 struct ptrace_io_desc iorequest;
1145 char *buf, *nbuf;
1146 size_t offset, size, totalsize;
1147
1148 offset = 0;
1149 if (max)
1150 size = max + 1;
1151 else {
1152 /* Read up to the end of the current page. */
1153 size = PAGE_SIZE - (addr % PAGE_SIZE);
1154 if (size > MAXSIZE)
1155 size = MAXSIZE;
1156 }
1157 totalsize = size;
1158 buf = malloc(totalsize);
1159 if (buf == NULL)
1160 return (NULL);
1161 for (;;) {
1162 iorequest.piod_op = PIOD_READ_D;
1163 iorequest.piod_offs = (void *)((uintptr_t)addr + offset);
1164 iorequest.piod_addr = buf + offset;
1165 iorequest.piod_len = size;
1166 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
1167 free(buf);
1168 return (NULL);
1169 }
1170 if (memchr(buf + offset, '\0', size) != NULL)
1171 return (buf);
1172 offset += size;
1173 if (totalsize < MAXSIZE && max == 0) {
1174 size = MAXSIZE - totalsize;
1175 if (size > PAGE_SIZE)
1176 size = PAGE_SIZE;
1177 nbuf = realloc(buf, totalsize + size);
1178 if (nbuf == NULL) {
1179 buf[totalsize - 1] = '\0';
1180 return (buf);
1181 }
1182 buf = nbuf;
1183 totalsize += size;
1184 } else {
1185 buf[totalsize - 1] = '\0';
1186 return (buf);
1187 }
1188 }
1189 }
1190
1191 static const char *
strsig2(int sig)1192 strsig2(int sig)
1193 {
1194 static char tmp[32];
1195 const char *signame;
1196
1197 signame = sysdecode_signal(sig);
1198 if (signame == NULL) {
1199 snprintf(tmp, sizeof(tmp), "%d", sig);
1200 signame = tmp;
1201 }
1202 return (signame);
1203 }
1204
1205 static void
print_kevent(FILE * fp,struct kevent * ke)1206 print_kevent(FILE *fp, struct kevent *ke)
1207 {
1208
1209 switch (ke->filter) {
1210 case EVFILT_READ:
1211 case EVFILT_WRITE:
1212 case EVFILT_VNODE:
1213 case EVFILT_PROC:
1214 case EVFILT_TIMER:
1215 case EVFILT_PROCDESC:
1216 case EVFILT_EMPTY:
1217 fprintf(fp, "%ju", (uintmax_t)ke->ident);
1218 break;
1219 case EVFILT_SIGNAL:
1220 fputs(strsig2(ke->ident), fp);
1221 break;
1222 default:
1223 fprintf(fp, "%p", (void *)ke->ident);
1224 }
1225 fprintf(fp, ",");
1226 print_integer_arg(sysdecode_kevent_filter, fp, ke->filter);
1227 fprintf(fp, ",");
1228 print_mask_arg(sysdecode_kevent_flags, fp, ke->flags);
1229 fprintf(fp, ",");
1230 sysdecode_kevent_fflags(fp, ke->filter, ke->fflags, 16);
1231 fprintf(fp, ",%#jx,%p", (uintmax_t)ke->data, ke->udata);
1232 }
1233
1234 static void
print_utrace(FILE * fp,void * utrace_addr,size_t len)1235 print_utrace(FILE *fp, void *utrace_addr, size_t len)
1236 {
1237 unsigned char *utrace_buffer;
1238
1239 fprintf(fp, "{ ");
1240 if (sysdecode_utrace(fp, utrace_addr, len)) {
1241 fprintf(fp, " }");
1242 return;
1243 }
1244
1245 utrace_buffer = utrace_addr;
1246 fprintf(fp, "%zu:", len);
1247 while (len--)
1248 fprintf(fp, " %02x", *utrace_buffer++);
1249 fprintf(fp, " }");
1250 }
1251
1252 static void
print_pointer(FILE * fp,uintptr_t arg)1253 print_pointer(FILE *fp, uintptr_t arg)
1254 {
1255
1256 fprintf(fp, "%p", (void *)arg);
1257 }
1258
1259 static void
print_sockaddr(FILE * fp,struct trussinfo * trussinfo,uintptr_t arg,socklen_t len)1260 print_sockaddr(FILE *fp, struct trussinfo *trussinfo, uintptr_t arg,
1261 socklen_t len)
1262 {
1263 char addr[64];
1264 struct sockaddr_in *lsin;
1265 struct sockaddr_in6 *lsin6;
1266 struct sockaddr_un *sun;
1267 struct sockaddr *sa;
1268 u_char *q;
1269 pid_t pid = trussinfo->curthread->proc->pid;
1270
1271 if (arg == 0) {
1272 fputs("NULL", fp);
1273 return;
1274 }
1275 /* If the length is too small, just bail. */
1276 if (len < sizeof(*sa)) {
1277 print_pointer(fp, arg);
1278 return;
1279 }
1280
1281 sa = calloc(1, len);
1282 if (get_struct(pid, arg, sa, len) == -1) {
1283 free(sa);
1284 print_pointer(fp, arg);
1285 return;
1286 }
1287
1288 switch (sa->sa_family) {
1289 case AF_INET:
1290 if (len < sizeof(*lsin))
1291 goto sockaddr_short;
1292 lsin = (struct sockaddr_in *)(void *)sa;
1293 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1294 fprintf(fp, "{ AF_INET %s:%d }", addr,
1295 htons(lsin->sin_port));
1296 break;
1297 case AF_INET6:
1298 if (len < sizeof(*lsin6))
1299 goto sockaddr_short;
1300 lsin6 = (struct sockaddr_in6 *)(void *)sa;
1301 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1302 sizeof(addr));
1303 fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1304 htons(lsin6->sin6_port));
1305 break;
1306 case AF_UNIX:
1307 sun = (struct sockaddr_un *)sa;
1308 fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1309 (int)(len - offsetof(struct sockaddr_un, sun_path)),
1310 sun->sun_path);
1311 break;
1312 default:
1313 sockaddr_short:
1314 fprintf(fp,
1315 "{ sa_len = %d, sa_family = %d, sa_data = {",
1316 (int)sa->sa_len, (int)sa->sa_family);
1317 for (q = (u_char *)sa->sa_data;
1318 q < (u_char *)sa + len; q++)
1319 fprintf(fp, "%s 0x%02x",
1320 q == (u_char *)sa->sa_data ? "" : ",",
1321 *q);
1322 fputs(" } }", fp);
1323 }
1324 free(sa);
1325 }
1326
1327 #define IOV_LIMIT 16
1328
1329 static void
print_iovec(FILE * fp,struct trussinfo * trussinfo,uintptr_t arg,int iovcnt)1330 print_iovec(FILE *fp, struct trussinfo *trussinfo, uintptr_t arg, int iovcnt)
1331 {
1332 struct iovec iov[IOV_LIMIT];
1333 size_t max_string = trussinfo->strsize;
1334 char tmp2[max_string + 1], *tmp3;
1335 size_t len;
1336 pid_t pid = trussinfo->curthread->proc->pid;
1337 int i;
1338 bool buf_truncated, iov_truncated;
1339
1340 if (iovcnt <= 0) {
1341 print_pointer(fp, arg);
1342 return;
1343 }
1344 if (iovcnt > IOV_LIMIT) {
1345 iovcnt = IOV_LIMIT;
1346 iov_truncated = true;
1347 } else {
1348 iov_truncated = false;
1349 }
1350 if (get_struct(pid, arg, &iov, iovcnt * sizeof(struct iovec)) == -1) {
1351 print_pointer(fp, arg);
1352 return;
1353 }
1354
1355 fputs("[", fp);
1356 for (i = 0; i < iovcnt; i++) {
1357 len = iov[i].iov_len;
1358 if (len > max_string) {
1359 len = max_string;
1360 buf_truncated = true;
1361 } else {
1362 buf_truncated = false;
1363 }
1364 fprintf(fp, "%s{", (i > 0) ? "," : "");
1365 if (len && get_struct(pid, (uintptr_t)iov[i].iov_base, &tmp2, len) != -1) {
1366 tmp3 = malloc(len * 4 + 1);
1367 while (len) {
1368 if (strvisx(tmp3, tmp2, len,
1369 VIS_CSTYLE|VIS_TAB|VIS_NL) <=
1370 (int)max_string)
1371 break;
1372 len--;
1373 buf_truncated = true;
1374 }
1375 fprintf(fp, "\"%s\"%s", tmp3,
1376 buf_truncated ? "..." : "");
1377 free(tmp3);
1378 } else {
1379 print_pointer(fp, (uintptr_t)iov[i].iov_base);
1380 }
1381 fprintf(fp, ",%zu}", iov[i].iov_len);
1382 }
1383 fprintf(fp, "%s%s", iov_truncated ? ",..." : "", "]");
1384 }
1385
1386 static void
print_sigval(FILE * fp,union sigval * sv)1387 print_sigval(FILE *fp, union sigval *sv)
1388 {
1389 fprintf(fp, "{ %d, %p }", sv->sival_int, sv->sival_ptr);
1390 }
1391
1392 static void
print_sigevent(FILE * fp,struct sigevent * se)1393 print_sigevent(FILE *fp, struct sigevent *se)
1394 {
1395 fputs("{ sigev_notify=", fp);
1396 switch (se->sigev_notify) {
1397 case SIGEV_NONE:
1398 fputs("SIGEV_NONE", fp);
1399 break;
1400 case SIGEV_SIGNAL:
1401 fprintf(fp, "SIGEV_SIGNAL, sigev_signo=%s, sigev_value=",
1402 strsig2(se->sigev_signo));
1403 print_sigval(fp, &se->sigev_value);
1404 break;
1405 case SIGEV_THREAD:
1406 fputs("SIGEV_THREAD, sigev_value=", fp);
1407 print_sigval(fp, &se->sigev_value);
1408 break;
1409 case SIGEV_KEVENT:
1410 fprintf(fp, "SIGEV_KEVENT, sigev_notify_kqueue=%d, sigev_notify_kevent_flags=",
1411 se->sigev_notify_kqueue);
1412 print_mask_arg(sysdecode_kevent_flags, fp, se->sigev_notify_kevent_flags);
1413 break;
1414 case SIGEV_THREAD_ID:
1415 fprintf(fp, "SIGEV_THREAD_ID, sigev_notify_thread_id=%d, sigev_signo=%s, sigev_value=",
1416 se->sigev_notify_thread_id, strsig2(se->sigev_signo));
1417 print_sigval(fp, &se->sigev_value);
1418 break;
1419 default:
1420 fprintf(fp, "%d", se->sigev_notify);
1421 break;
1422 }
1423 fputs(" }", fp);
1424 }
1425
1426 static void
print_aiocb(FILE * fp,struct aiocb * cb)1427 print_aiocb(FILE *fp, struct aiocb *cb)
1428 {
1429 fprintf(fp, "{ %d,%jd,%p,%zu,%s,",
1430 cb->aio_fildes,
1431 cb->aio_offset,
1432 cb->aio_buf,
1433 cb->aio_nbytes,
1434 xlookup(lio_opcodes, cb->aio_lio_opcode));
1435 print_sigevent(fp, &cb->aio_sigevent);
1436 fputs(" }", fp);
1437 }
1438
1439 static void
print_gen_cmsg(FILE * fp,struct cmsghdr * cmsghdr)1440 print_gen_cmsg(FILE *fp, struct cmsghdr *cmsghdr)
1441 {
1442 u_char *q;
1443
1444 fputs("{", fp);
1445 for (q = CMSG_DATA(cmsghdr);
1446 q < (u_char *)cmsghdr + cmsghdr->cmsg_len; q++) {
1447 fprintf(fp, "%s0x%02x", q == CMSG_DATA(cmsghdr) ? "" : ",", *q);
1448 }
1449 fputs("}", fp);
1450 }
1451
1452 static void
print_sctp_initmsg(FILE * fp,struct sctp_initmsg * init)1453 print_sctp_initmsg(FILE *fp, struct sctp_initmsg *init)
1454 {
1455 fprintf(fp, "{out=%u,", init->sinit_num_ostreams);
1456 fprintf(fp, "in=%u,", init->sinit_max_instreams);
1457 fprintf(fp, "max_rtx=%u,", init->sinit_max_attempts);
1458 fprintf(fp, "max_rto=%u}", init->sinit_max_init_timeo);
1459 }
1460
1461 static void
print_sctp_sndrcvinfo(FILE * fp,bool receive,struct sctp_sndrcvinfo * info)1462 print_sctp_sndrcvinfo(FILE *fp, bool receive, struct sctp_sndrcvinfo *info)
1463 {
1464 fprintf(fp, "{sid=%u,", info->sinfo_stream);
1465 if (receive) {
1466 fprintf(fp, "ssn=%u,", info->sinfo_ssn);
1467 }
1468 fputs("flgs=", fp);
1469 sysdecode_sctp_sinfo_flags(fp, info->sinfo_flags);
1470 fprintf(fp, ",ppid=%u,", ntohl(info->sinfo_ppid));
1471 if (!receive) {
1472 fprintf(fp, "ctx=%u,", info->sinfo_context);
1473 fprintf(fp, "ttl=%u,", info->sinfo_timetolive);
1474 }
1475 if (receive) {
1476 fprintf(fp, "tsn=%u,", info->sinfo_tsn);
1477 fprintf(fp, "cumtsn=%u,", info->sinfo_cumtsn);
1478 }
1479 fprintf(fp, "id=%u}", info->sinfo_assoc_id);
1480 }
1481
1482 static void
print_sctp_sndinfo(FILE * fp,struct sctp_sndinfo * info)1483 print_sctp_sndinfo(FILE *fp, struct sctp_sndinfo *info)
1484 {
1485 fprintf(fp, "{sid=%u,", info->snd_sid);
1486 fputs("flgs=", fp);
1487 print_mask_arg(sysdecode_sctp_snd_flags, fp, info->snd_flags);
1488 fprintf(fp, ",ppid=%u,", ntohl(info->snd_ppid));
1489 fprintf(fp, "ctx=%u,", info->snd_context);
1490 fprintf(fp, "id=%u}", info->snd_assoc_id);
1491 }
1492
1493 static void
print_sctp_rcvinfo(FILE * fp,struct sctp_rcvinfo * info)1494 print_sctp_rcvinfo(FILE *fp, struct sctp_rcvinfo *info)
1495 {
1496 fprintf(fp, "{sid=%u,", info->rcv_sid);
1497 fprintf(fp, "ssn=%u,", info->rcv_ssn);
1498 fputs("flgs=", fp);
1499 print_mask_arg(sysdecode_sctp_rcv_flags, fp, info->rcv_flags);
1500 fprintf(fp, ",ppid=%u,", ntohl(info->rcv_ppid));
1501 fprintf(fp, "tsn=%u,", info->rcv_tsn);
1502 fprintf(fp, "cumtsn=%u,", info->rcv_cumtsn);
1503 fprintf(fp, "ctx=%u,", info->rcv_context);
1504 fprintf(fp, "id=%u}", info->rcv_assoc_id);
1505 }
1506
1507 static void
print_sctp_nxtinfo(FILE * fp,struct sctp_nxtinfo * info)1508 print_sctp_nxtinfo(FILE *fp, struct sctp_nxtinfo *info)
1509 {
1510 fprintf(fp, "{sid=%u,", info->nxt_sid);
1511 fputs("flgs=", fp);
1512 print_mask_arg(sysdecode_sctp_nxt_flags, fp, info->nxt_flags);
1513 fprintf(fp, ",ppid=%u,", ntohl(info->nxt_ppid));
1514 fprintf(fp, "len=%u,", info->nxt_length);
1515 fprintf(fp, "id=%u}", info->nxt_assoc_id);
1516 }
1517
1518 static void
print_sctp_prinfo(FILE * fp,struct sctp_prinfo * info)1519 print_sctp_prinfo(FILE *fp, struct sctp_prinfo *info)
1520 {
1521 fputs("{pol=", fp);
1522 print_integer_arg(sysdecode_sctp_pr_policy, fp, info->pr_policy);
1523 fprintf(fp, ",val=%u}", info->pr_value);
1524 }
1525
1526 static void
print_sctp_authinfo(FILE * fp,struct sctp_authinfo * info)1527 print_sctp_authinfo(FILE *fp, struct sctp_authinfo *info)
1528 {
1529 fprintf(fp, "{num=%u}", info->auth_keynumber);
1530 }
1531
1532 static void
print_sctp_ipv4_addr(FILE * fp,struct in_addr * addr)1533 print_sctp_ipv4_addr(FILE *fp, struct in_addr *addr)
1534 {
1535 char buf[INET_ADDRSTRLEN];
1536 const char *s;
1537
1538 s = inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN);
1539 if (s != NULL)
1540 fprintf(fp, "{addr=%s}", s);
1541 else
1542 fputs("{addr=???}", fp);
1543 }
1544
1545 static void
print_sctp_ipv6_addr(FILE * fp,struct in6_addr * addr)1546 print_sctp_ipv6_addr(FILE *fp, struct in6_addr *addr)
1547 {
1548 char buf[INET6_ADDRSTRLEN];
1549 const char *s;
1550
1551 s = inet_ntop(AF_INET6, addr, buf, INET6_ADDRSTRLEN);
1552 if (s != NULL)
1553 fprintf(fp, "{addr=%s}", s);
1554 else
1555 fputs("{addr=???}", fp);
1556 }
1557
1558 static void
print_sctp_cmsg(FILE * fp,bool receive,struct cmsghdr * cmsghdr)1559 print_sctp_cmsg(FILE *fp, bool receive, struct cmsghdr *cmsghdr)
1560 {
1561 void *data;
1562 socklen_t len;
1563
1564 len = cmsghdr->cmsg_len;
1565 data = CMSG_DATA(cmsghdr);
1566 switch (cmsghdr->cmsg_type) {
1567 case SCTP_INIT:
1568 if (len == CMSG_LEN(sizeof(struct sctp_initmsg)))
1569 print_sctp_initmsg(fp, (struct sctp_initmsg *)data);
1570 else
1571 print_gen_cmsg(fp, cmsghdr);
1572 break;
1573 case SCTP_SNDRCV:
1574 if (len == CMSG_LEN(sizeof(struct sctp_sndrcvinfo)))
1575 print_sctp_sndrcvinfo(fp, receive,
1576 (struct sctp_sndrcvinfo *)data);
1577 else
1578 print_gen_cmsg(fp, cmsghdr);
1579 break;
1580 #if 0
1581 case SCTP_EXTRCV:
1582 if (len == CMSG_LEN(sizeof(struct sctp_extrcvinfo)))
1583 print_sctp_extrcvinfo(fp,
1584 (struct sctp_extrcvinfo *)data);
1585 else
1586 print_gen_cmsg(fp, cmsghdr);
1587 break;
1588 #endif
1589 case SCTP_SNDINFO:
1590 if (len == CMSG_LEN(sizeof(struct sctp_sndinfo)))
1591 print_sctp_sndinfo(fp, (struct sctp_sndinfo *)data);
1592 else
1593 print_gen_cmsg(fp, cmsghdr);
1594 break;
1595 case SCTP_RCVINFO:
1596 if (len == CMSG_LEN(sizeof(struct sctp_rcvinfo)))
1597 print_sctp_rcvinfo(fp, (struct sctp_rcvinfo *)data);
1598 else
1599 print_gen_cmsg(fp, cmsghdr);
1600 break;
1601 case SCTP_NXTINFO:
1602 if (len == CMSG_LEN(sizeof(struct sctp_nxtinfo)))
1603 print_sctp_nxtinfo(fp, (struct sctp_nxtinfo *)data);
1604 else
1605 print_gen_cmsg(fp, cmsghdr);
1606 break;
1607 case SCTP_PRINFO:
1608 if (len == CMSG_LEN(sizeof(struct sctp_prinfo)))
1609 print_sctp_prinfo(fp, (struct sctp_prinfo *)data);
1610 else
1611 print_gen_cmsg(fp, cmsghdr);
1612 break;
1613 case SCTP_AUTHINFO:
1614 if (len == CMSG_LEN(sizeof(struct sctp_authinfo)))
1615 print_sctp_authinfo(fp, (struct sctp_authinfo *)data);
1616 else
1617 print_gen_cmsg(fp, cmsghdr);
1618 break;
1619 case SCTP_DSTADDRV4:
1620 if (len == CMSG_LEN(sizeof(struct in_addr)))
1621 print_sctp_ipv4_addr(fp, (struct in_addr *)data);
1622 else
1623 print_gen_cmsg(fp, cmsghdr);
1624 break;
1625 case SCTP_DSTADDRV6:
1626 if (len == CMSG_LEN(sizeof(struct in6_addr)))
1627 print_sctp_ipv6_addr(fp, (struct in6_addr *)data);
1628 else
1629 print_gen_cmsg(fp, cmsghdr);
1630 break;
1631 default:
1632 print_gen_cmsg(fp, cmsghdr);
1633 }
1634 }
1635
1636 static void
print_cmsgs(FILE * fp,pid_t pid,bool receive,struct msghdr * msghdr)1637 print_cmsgs(FILE *fp, pid_t pid, bool receive, struct msghdr *msghdr)
1638 {
1639 struct cmsghdr *cmsghdr;
1640 char *cmsgbuf;
1641 const char *temp;
1642 socklen_t len;
1643 int level, type;
1644 bool first;
1645
1646 len = msghdr->msg_controllen;
1647 if (len == 0) {
1648 fputs("{}", fp);
1649 return;
1650 }
1651 cmsgbuf = calloc(1, len);
1652 if (get_struct(pid, (uintptr_t)msghdr->msg_control, cmsgbuf, len) == -1) {
1653 print_pointer(fp, (uintptr_t)msghdr->msg_control);
1654 free(cmsgbuf);
1655 return;
1656 }
1657 msghdr->msg_control = cmsgbuf;
1658 first = true;
1659 fputs("{", fp);
1660 for (cmsghdr = CMSG_FIRSTHDR(msghdr);
1661 cmsghdr != NULL;
1662 cmsghdr = CMSG_NXTHDR(msghdr, cmsghdr)) {
1663 level = cmsghdr->cmsg_level;
1664 type = cmsghdr->cmsg_type;
1665 len = cmsghdr->cmsg_len;
1666 fprintf(fp, "%s{level=", first ? "" : ",");
1667 print_integer_arg(sysdecode_sockopt_level, fp, level);
1668 fputs(",type=", fp);
1669 temp = sysdecode_cmsg_type(level, type);
1670 if (temp) {
1671 fputs(temp, fp);
1672 } else {
1673 fprintf(fp, "%d", type);
1674 }
1675 fputs(",data=", fp);
1676 switch (level) {
1677 case IPPROTO_SCTP:
1678 print_sctp_cmsg(fp, receive, cmsghdr);
1679 break;
1680 default:
1681 print_gen_cmsg(fp, cmsghdr);
1682 break;
1683 }
1684 fputs("}", fp);
1685 first = false;
1686 }
1687 fputs("}", fp);
1688 free(cmsgbuf);
1689 }
1690
1691 static void
print_sysctl_oid(FILE * fp,int * oid,size_t len)1692 print_sysctl_oid(FILE *fp, int *oid, size_t len)
1693 {
1694 size_t i;
1695 bool first;
1696
1697 first = true;
1698 fprintf(fp, "{ ");
1699 for (i = 0; i < len; i++) {
1700 fprintf(fp, "%s%d", first ? "" : ".", oid[i]);
1701 first = false;
1702 }
1703 fprintf(fp, " }");
1704 }
1705
1706 static void
print_sysctl(FILE * fp,int * oid,size_t len)1707 print_sysctl(FILE *fp, int *oid, size_t len)
1708 {
1709 char name[BUFSIZ];
1710 int qoid[CTL_MAXNAME + 2];
1711 size_t i;
1712
1713 qoid[0] = CTL_SYSCTL;
1714 qoid[1] = CTL_SYSCTL_NAME;
1715 memcpy(qoid + 2, oid, len * sizeof(int));
1716 i = sizeof(name);
1717 if (sysctl(qoid, len + 2, name, &i, 0, 0) == -1)
1718 print_sysctl_oid(fp, oid, len);
1719 else
1720 fprintf(fp, "%s", name);
1721 }
1722
1723 /*
1724 * Convert a 32-bit user-space pointer to psaddr_t. Currently, this
1725 * sign-extends on MIPS and zero-extends on all other architectures.
1726 */
1727 static psaddr_t
user_ptr32_to_psaddr(int32_t user_pointer)1728 user_ptr32_to_psaddr(int32_t user_pointer)
1729 {
1730 #if defined(__mips__)
1731 return ((psaddr_t)(intptr_t)user_pointer);
1732 #else
1733 return ((psaddr_t)(uintptr_t)user_pointer);
1734 #endif
1735 }
1736
1737 /*
1738 * Converts a syscall argument into a string. Said string is
1739 * allocated via malloc(), so needs to be free()'d. sc is
1740 * a pointer to the syscall description (see above); args is
1741 * an array of all of the system call arguments.
1742 */
1743 char *
print_arg(struct syscall_arg * sc,unsigned long * args,register_t * retval,struct trussinfo * trussinfo)1744 print_arg(struct syscall_arg *sc, unsigned long *args, register_t *retval,
1745 struct trussinfo *trussinfo)
1746 {
1747 FILE *fp;
1748 char *tmp;
1749 size_t tmplen;
1750 pid_t pid;
1751
1752 fp = open_memstream(&tmp, &tmplen);
1753 pid = trussinfo->curthread->proc->pid;
1754 switch (sc->type & ARG_MASK) {
1755 case Hex:
1756 fprintf(fp, "0x%x", (int)args[sc->offset]);
1757 break;
1758 case Octal:
1759 fprintf(fp, "0%o", (int)args[sc->offset]);
1760 break;
1761 case Int:
1762 fprintf(fp, "%d", (int)args[sc->offset]);
1763 break;
1764 case UInt:
1765 fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1766 break;
1767 case PUInt: {
1768 unsigned int val;
1769
1770 if (get_struct(pid, args[sc->offset], &val,
1771 sizeof(val)) == 0)
1772 fprintf(fp, "{ %u }", val);
1773 else
1774 print_pointer(fp, args[sc->offset]);
1775 break;
1776 }
1777 case LongHex:
1778 fprintf(fp, "0x%lx", args[sc->offset]);
1779 break;
1780 case Long:
1781 fprintf(fp, "%ld", args[sc->offset]);
1782 break;
1783 case Sizet:
1784 fprintf(fp, "%zu", (size_t)args[sc->offset]);
1785 break;
1786 case ShmName:
1787 /* Handle special SHM_ANON value. */
1788 if ((char *)(uintptr_t)args[sc->offset] == SHM_ANON) {
1789 fprintf(fp, "SHM_ANON");
1790 break;
1791 }
1792 /* FALLTHROUGH */
1793 case Name: {
1794 /* NULL-terminated string. */
1795 char *tmp2;
1796
1797 tmp2 = get_string(pid, args[sc->offset], 0);
1798 fprintf(fp, "\"%s\"", tmp2);
1799 free(tmp2);
1800 break;
1801 }
1802 case BinString: {
1803 /*
1804 * Binary block of data that might have printable characters.
1805 * XXX If type|OUT, assume that the length is the syscall's
1806 * return value. Otherwise, assume that the length of the block
1807 * is in the next syscall argument.
1808 */
1809 int max_string = trussinfo->strsize;
1810 char tmp2[max_string + 1], *tmp3;
1811 int len;
1812 int truncated = 0;
1813
1814 if (sc->type & OUT)
1815 len = retval[0];
1816 else
1817 len = args[sc->offset + 1];
1818
1819 /*
1820 * Don't print more than max_string characters, to avoid word
1821 * wrap. If we have to truncate put some ... after the string.
1822 */
1823 if (len > max_string) {
1824 len = max_string;
1825 truncated = 1;
1826 }
1827 if (len && get_struct(pid, args[sc->offset], &tmp2, len)
1828 != -1) {
1829 tmp3 = malloc(len * 4 + 1);
1830 while (len) {
1831 if (strvisx(tmp3, tmp2, len,
1832 VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1833 break;
1834 len--;
1835 truncated = 1;
1836 }
1837 fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1838 "..." : "");
1839 free(tmp3);
1840 } else {
1841 print_pointer(fp, args[sc->offset]);
1842 }
1843 break;
1844 }
1845 case ExecArgs:
1846 case ExecEnv:
1847 case StringArray: {
1848 psaddr_t addr;
1849 union {
1850 int32_t strarray32[PAGE_SIZE / sizeof(int32_t)];
1851 int64_t strarray64[PAGE_SIZE / sizeof(int64_t)];
1852 char buf[PAGE_SIZE];
1853 } u;
1854 char *string;
1855 size_t len;
1856 u_int first, i;
1857 size_t pointer_size =
1858 trussinfo->curthread->proc->abi->pointer_size;
1859
1860 /*
1861 * Only parse argv[] and environment arrays from exec calls
1862 * if requested.
1863 */
1864 if (((sc->type & ARG_MASK) == ExecArgs &&
1865 (trussinfo->flags & EXECVEARGS) == 0) ||
1866 ((sc->type & ARG_MASK) == ExecEnv &&
1867 (trussinfo->flags & EXECVEENVS) == 0)) {
1868 print_pointer(fp, args[sc->offset]);
1869 break;
1870 }
1871
1872 /*
1873 * Read a page of pointers at a time. Punt if the top-level
1874 * pointer is not aligned. Note that the first read is of
1875 * a partial page.
1876 */
1877 addr = args[sc->offset];
1878 if (!__is_aligned(addr, pointer_size)) {
1879 print_pointer(fp, args[sc->offset]);
1880 break;
1881 }
1882
1883 len = PAGE_SIZE - (addr & PAGE_MASK);
1884 if (get_struct(pid, addr, u.buf, len) == -1) {
1885 print_pointer(fp, args[sc->offset]);
1886 break;
1887 }
1888 assert(len > 0);
1889
1890 fputc('[', fp);
1891 first = 1;
1892 i = 0;
1893 for (;;) {
1894 psaddr_t straddr;
1895 if (pointer_size == 4) {
1896 straddr = user_ptr32_to_psaddr(u.strarray32[i]);
1897 } else if (pointer_size == 8) {
1898 straddr = (psaddr_t)u.strarray64[i];
1899 } else {
1900 errx(1, "Unsupported pointer size: %zu",
1901 pointer_size);
1902 }
1903
1904 /* Stop once we read the first NULL pointer. */
1905 if (straddr == 0)
1906 break;
1907 string = get_string(pid, straddr, 0);
1908 fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1909 free(string);
1910 first = 0;
1911
1912 i++;
1913 if (i == len / pointer_size) {
1914 addr += len;
1915 len = PAGE_SIZE;
1916 if (get_struct(pid, addr, u.buf, len) == -1) {
1917 fprintf(fp, ", <inval>");
1918 break;
1919 }
1920 i = 0;
1921 }
1922 }
1923 fputs(" ]", fp);
1924 break;
1925 }
1926 case Quad:
1927 case QuadHex: {
1928 uint64_t value;
1929 size_t pointer_size =
1930 trussinfo->curthread->proc->abi->pointer_size;
1931
1932 if (pointer_size == 4) {
1933 #if _BYTE_ORDER == _LITTLE_ENDIAN
1934 value = (uint64_t)args[sc->offset + 1] << 32 |
1935 args[sc->offset];
1936 #else
1937 value = (uint64_t)args[sc->offset] << 32 |
1938 args[sc->offset + 1];
1939 #endif
1940 } else {
1941 value = (uint64_t)args[sc->offset];
1942 }
1943 if ((sc->type & ARG_MASK) == Quad)
1944 fprintf(fp, "%jd", (intmax_t)value);
1945 else
1946 fprintf(fp, "0x%jx", (intmax_t)value);
1947 break;
1948 }
1949 case PQuadHex: {
1950 uint64_t val;
1951
1952 if (get_struct(pid, args[sc->offset], &val,
1953 sizeof(val)) == 0)
1954 fprintf(fp, "{ 0x%jx }", (uintmax_t)val);
1955 else
1956 print_pointer(fp, args[sc->offset]);
1957 break;
1958 }
1959 case Ptr:
1960 print_pointer(fp, args[sc->offset]);
1961 break;
1962 case Readlinkres: {
1963 char *tmp2;
1964
1965 if (retval[0] == -1)
1966 break;
1967 tmp2 = get_string(pid, args[sc->offset], retval[0]);
1968 fprintf(fp, "\"%s\"", tmp2);
1969 free(tmp2);
1970 break;
1971 }
1972 case Ioctl: {
1973 const char *temp;
1974 unsigned long cmd;
1975
1976 cmd = args[sc->offset];
1977 temp = sysdecode_ioctlname(cmd);
1978 if (temp)
1979 fputs(temp, fp);
1980 else {
1981 fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1982 cmd, cmd & IOC_OUT ? "R" : "",
1983 cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1984 isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1985 cmd & 0xFF, IOCPARM_LEN(cmd));
1986 }
1987 break;
1988 }
1989 case Timespec: {
1990 struct timespec ts;
1991
1992 if (get_struct(pid, args[sc->offset], &ts, sizeof(ts)) != -1)
1993 fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1994 ts.tv_nsec);
1995 else
1996 print_pointer(fp, args[sc->offset]);
1997 break;
1998 }
1999 case Timespec2: {
2000 struct timespec ts[2];
2001 const char *sep;
2002 unsigned int i;
2003
2004 if (get_struct(pid, args[sc->offset], &ts, sizeof(ts)) != -1) {
2005 fputs("{ ", fp);
2006 sep = "";
2007 for (i = 0; i < nitems(ts); i++) {
2008 fputs(sep, fp);
2009 sep = ", ";
2010 switch (ts[i].tv_nsec) {
2011 case UTIME_NOW:
2012 fprintf(fp, "UTIME_NOW");
2013 break;
2014 case UTIME_OMIT:
2015 fprintf(fp, "UTIME_OMIT");
2016 break;
2017 default:
2018 fprintf(fp, "%jd.%09ld",
2019 (intmax_t)ts[i].tv_sec,
2020 ts[i].tv_nsec);
2021 break;
2022 }
2023 }
2024 fputs(" }", fp);
2025 } else
2026 print_pointer(fp, args[sc->offset]);
2027 break;
2028 }
2029 case Timeval: {
2030 struct timeval tv;
2031
2032 if (get_struct(pid, args[sc->offset], &tv, sizeof(tv)) != -1)
2033 fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
2034 tv.tv_usec);
2035 else
2036 print_pointer(fp, args[sc->offset]);
2037 break;
2038 }
2039 case Timeval2: {
2040 struct timeval tv[2];
2041
2042 if (get_struct(pid, args[sc->offset], &tv, sizeof(tv)) != -1)
2043 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
2044 (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
2045 (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
2046 else
2047 print_pointer(fp, args[sc->offset]);
2048 break;
2049 }
2050 case Itimerval: {
2051 struct itimerval itv;
2052
2053 if (get_struct(pid, args[sc->offset], &itv, sizeof(itv)) != -1)
2054 fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
2055 (intmax_t)itv.it_interval.tv_sec,
2056 itv.it_interval.tv_usec,
2057 (intmax_t)itv.it_value.tv_sec,
2058 itv.it_value.tv_usec);
2059 else
2060 print_pointer(fp, args[sc->offset]);
2061 break;
2062 }
2063 case LinuxSockArgs:
2064 {
2065 struct linux_socketcall_args largs;
2066
2067 if (get_struct(pid, args[sc->offset], (void *)&largs,
2068 sizeof(largs)) != -1)
2069 fprintf(fp, "{ %s, 0x%lx }",
2070 lookup(linux_socketcall_ops, largs.what, 10),
2071 (long unsigned int)largs.args);
2072 else
2073 print_pointer(fp, args[sc->offset]);
2074 break;
2075 }
2076 case Pollfd: {
2077 /*
2078 * XXX: A Pollfd argument expects the /next/ syscall argument
2079 * to be the number of fds in the array. This matches the poll
2080 * syscall.
2081 */
2082 struct pollfd *pfd;
2083 int numfds = args[sc->offset + 1];
2084 size_t bytes = sizeof(struct pollfd) * numfds;
2085 int i;
2086
2087 if ((pfd = malloc(bytes)) == NULL)
2088 err(1, "Cannot malloc %zu bytes for pollfd array",
2089 bytes);
2090 if (get_struct(pid, args[sc->offset], pfd, bytes) != -1) {
2091 fputs("{", fp);
2092 for (i = 0; i < numfds; i++) {
2093 fprintf(fp, " %d/%s", pfd[i].fd,
2094 xlookup_bits(poll_flags, pfd[i].events));
2095 }
2096 fputs(" }", fp);
2097 } else {
2098 print_pointer(fp, args[sc->offset]);
2099 }
2100 free(pfd);
2101 break;
2102 }
2103 case Fd_set: {
2104 /*
2105 * XXX: A Fd_set argument expects the /first/ syscall argument
2106 * to be the number of fds in the array. This matches the
2107 * select syscall.
2108 */
2109 fd_set *fds;
2110 int numfds = args[0];
2111 size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
2112 int i;
2113
2114 if ((fds = malloc(bytes)) == NULL)
2115 err(1, "Cannot malloc %zu bytes for fd_set array",
2116 bytes);
2117 if (get_struct(pid, args[sc->offset], fds, bytes) != -1) {
2118 fputs("{", fp);
2119 for (i = 0; i < numfds; i++) {
2120 if (FD_ISSET(i, fds))
2121 fprintf(fp, " %d", i);
2122 }
2123 fputs(" }", fp);
2124 } else
2125 print_pointer(fp, args[sc->offset]);
2126 free(fds);
2127 break;
2128 }
2129 case Signal:
2130 fputs(strsig2(args[sc->offset]), fp);
2131 break;
2132 case Sigset: {
2133 sigset_t ss;
2134 int i, first;
2135
2136 if (get_struct(pid, args[sc->offset], (void *)&ss,
2137 sizeof(ss)) == -1) {
2138 print_pointer(fp, args[sc->offset]);
2139 break;
2140 }
2141 fputs("{ ", fp);
2142 first = 1;
2143 for (i = 1; i < sys_nsig; i++) {
2144 if (sigismember(&ss, i)) {
2145 fprintf(fp, "%s%s", !first ? "|" : "",
2146 strsig2(i));
2147 first = 0;
2148 }
2149 }
2150 if (!first)
2151 fputc(' ', fp);
2152 fputc('}', fp);
2153 break;
2154 }
2155 case Sigprocmask:
2156 print_integer_arg(sysdecode_sigprocmask_how, fp,
2157 args[sc->offset]);
2158 break;
2159 case Fcntlflag:
2160 /* XXX: Output depends on the value of the previous argument. */
2161 if (sysdecode_fcntl_arg_p(args[sc->offset - 1]))
2162 sysdecode_fcntl_arg(fp, args[sc->offset - 1],
2163 args[sc->offset], 16);
2164 break;
2165 case Open:
2166 print_mask_arg(sysdecode_open_flags, fp, args[sc->offset]);
2167 break;
2168 case Fcntl:
2169 print_integer_arg(sysdecode_fcntl_cmd, fp, args[sc->offset]);
2170 break;
2171 case Closerangeflags:
2172 print_mask_arg(sysdecode_close_range_flags, fp, args[sc->offset]);
2173 break;
2174 case Mprot:
2175 print_mask_arg(sysdecode_mmap_prot, fp, args[sc->offset]);
2176 break;
2177 case Mmapflags:
2178 print_mask_arg(sysdecode_mmap_flags, fp, args[sc->offset]);
2179 break;
2180 case Whence:
2181 print_integer_arg(sysdecode_whence, fp, args[sc->offset]);
2182 break;
2183 case ShmFlags:
2184 print_mask_arg(sysdecode_shmflags, fp, args[sc->offset]);
2185 break;
2186 case Sockdomain:
2187 print_integer_arg(sysdecode_socketdomain, fp, args[sc->offset]);
2188 break;
2189 case Socktype:
2190 print_mask_arg(sysdecode_socket_type, fp, args[sc->offset]);
2191 break;
2192 case Shutdown:
2193 print_integer_arg(sysdecode_shutdown_how, fp, args[sc->offset]);
2194 break;
2195 case Resource:
2196 print_integer_arg(sysdecode_rlimit, fp, args[sc->offset]);
2197 break;
2198 case RusageWho:
2199 print_integer_arg(sysdecode_getrusage_who, fp, args[sc->offset]);
2200 break;
2201 case Pathconf:
2202 print_integer_arg(sysdecode_pathconf_name, fp, args[sc->offset]);
2203 break;
2204 case Rforkflags:
2205 print_mask_arg(sysdecode_rfork_flags, fp, args[sc->offset]);
2206 break;
2207 case Sockaddr: {
2208 socklen_t len;
2209
2210 if (args[sc->offset] == 0) {
2211 fputs("NULL", fp);
2212 break;
2213 }
2214
2215 /*
2216 * Extract the address length from the next argument. If
2217 * this is an output sockaddr (OUT is set), then the
2218 * next argument is a pointer to a socklen_t. Otherwise
2219 * the next argument contains a socklen_t by value.
2220 */
2221 if (sc->type & OUT) {
2222 if (get_struct(pid, args[sc->offset + 1], &len,
2223 sizeof(len)) == -1) {
2224 print_pointer(fp, args[sc->offset]);
2225 break;
2226 }
2227 } else
2228 len = args[sc->offset + 1];
2229
2230 print_sockaddr(fp, trussinfo, args[sc->offset], len);
2231 break;
2232 }
2233 case Sigaction: {
2234 struct sigaction sa;
2235
2236 if (get_struct(pid, args[sc->offset], &sa, sizeof(sa)) != -1) {
2237 fputs("{ ", fp);
2238 if (sa.sa_handler == SIG_DFL)
2239 fputs("SIG_DFL", fp);
2240 else if (sa.sa_handler == SIG_IGN)
2241 fputs("SIG_IGN", fp);
2242 else
2243 fprintf(fp, "%p", sa.sa_handler);
2244 fprintf(fp, " %s ss_t }",
2245 xlookup_bits(sigaction_flags, sa.sa_flags));
2246 } else
2247 print_pointer(fp, args[sc->offset]);
2248 break;
2249 }
2250 case Sigevent: {
2251 struct sigevent se;
2252
2253 if (get_struct(pid, args[sc->offset], &se, sizeof(se)) != -1)
2254 print_sigevent(fp, &se);
2255 else
2256 print_pointer(fp, args[sc->offset]);
2257 break;
2258 }
2259 case Kevent: {
2260 /*
2261 * XXX XXX: The size of the array is determined by either the
2262 * next syscall argument, or by the syscall return value,
2263 * depending on which argument number we are. This matches the
2264 * kevent syscall, but luckily that's the only syscall that uses
2265 * them.
2266 */
2267 struct kevent *ke;
2268 int numevents = -1;
2269 size_t bytes;
2270 int i;
2271
2272 if (sc->offset == 1)
2273 numevents = args[sc->offset+1];
2274 else if (sc->offset == 3 && retval[0] != -1)
2275 numevents = retval[0];
2276
2277 if (numevents >= 0) {
2278 bytes = sizeof(struct kevent) * numevents;
2279 if ((ke = malloc(bytes)) == NULL)
2280 err(1,
2281 "Cannot malloc %zu bytes for kevent array",
2282 bytes);
2283 } else
2284 ke = NULL;
2285 if (numevents >= 0 && get_struct(pid, args[sc->offset],
2286 ke, bytes) != -1) {
2287 fputc('{', fp);
2288 for (i = 0; i < numevents; i++) {
2289 fputc(' ', fp);
2290 print_kevent(fp, &ke[i]);
2291 }
2292 fputs(" }", fp);
2293 } else {
2294 print_pointer(fp, args[sc->offset]);
2295 }
2296 free(ke);
2297 break;
2298 }
2299 case Kevent11: {
2300 struct kevent_freebsd11 *ke11;
2301 struct kevent ke;
2302 int numevents = -1;
2303 size_t bytes;
2304 int i;
2305
2306 if (sc->offset == 1)
2307 numevents = args[sc->offset+1];
2308 else if (sc->offset == 3 && retval[0] != -1)
2309 numevents = retval[0];
2310
2311 if (numevents >= 0) {
2312 bytes = sizeof(struct kevent_freebsd11) * numevents;
2313 if ((ke11 = malloc(bytes)) == NULL)
2314 err(1,
2315 "Cannot malloc %zu bytes for kevent array",
2316 bytes);
2317 } else
2318 ke11 = NULL;
2319 memset(&ke, 0, sizeof(ke));
2320 if (numevents >= 0 && get_struct(pid, args[sc->offset],
2321 ke11, bytes) != -1) {
2322 fputc('{', fp);
2323 for (i = 0; i < numevents; i++) {
2324 fputc(' ', fp);
2325 ke.ident = ke11[i].ident;
2326 ke.filter = ke11[i].filter;
2327 ke.flags = ke11[i].flags;
2328 ke.fflags = ke11[i].fflags;
2329 ke.data = ke11[i].data;
2330 ke.udata = ke11[i].udata;
2331 print_kevent(fp, &ke);
2332 }
2333 fputs(" }", fp);
2334 } else {
2335 print_pointer(fp, args[sc->offset]);
2336 }
2337 free(ke11);
2338 break;
2339 }
2340 case Stat: {
2341 struct stat st;
2342
2343 if (get_struct(pid, args[sc->offset], &st, sizeof(st))
2344 != -1) {
2345 char mode[12];
2346
2347 strmode(st.st_mode, mode);
2348 fprintf(fp,
2349 "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
2350 (uintmax_t)st.st_ino, (intmax_t)st.st_size,
2351 (long)st.st_blksize);
2352 } else {
2353 print_pointer(fp, args[sc->offset]);
2354 }
2355 break;
2356 }
2357 case Stat11: {
2358 struct freebsd11_stat st;
2359
2360 if (get_struct(pid, args[sc->offset], &st, sizeof(st))
2361 != -1) {
2362 char mode[12];
2363
2364 strmode(st.st_mode, mode);
2365 fprintf(fp,
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);
2369 } else {
2370 print_pointer(fp, args[sc->offset]);
2371 }
2372 break;
2373 }
2374 case StatFs: {
2375 unsigned int i;
2376 struct statfs buf;
2377
2378 if (get_struct(pid, args[sc->offset], &buf,
2379 sizeof(buf)) != -1) {
2380 char fsid[17];
2381
2382 bzero(fsid, sizeof(fsid));
2383 if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
2384 for (i = 0; i < sizeof(buf.f_fsid); i++)
2385 snprintf(&fsid[i*2],
2386 sizeof(fsid) - (i*2), "%02x",
2387 ((u_char *)&buf.f_fsid)[i]);
2388 }
2389 fprintf(fp,
2390 "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
2391 "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
2392 buf.f_mntfromname, fsid);
2393 } else
2394 print_pointer(fp, args[sc->offset]);
2395 break;
2396 }
2397
2398 case Rusage: {
2399 struct rusage ru;
2400
2401 if (get_struct(pid, args[sc->offset], &ru, sizeof(ru))
2402 != -1) {
2403 fprintf(fp,
2404 "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
2405 (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
2406 (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
2407 ru.ru_inblock, ru.ru_oublock);
2408 } else
2409 print_pointer(fp, args[sc->offset]);
2410 break;
2411 }
2412 case Rlimit: {
2413 struct rlimit rl;
2414
2415 if (get_struct(pid, args[sc->offset], &rl, sizeof(rl))
2416 != -1) {
2417 fprintf(fp, "{ cur=%ju,max=%ju }",
2418 rl.rlim_cur, rl.rlim_max);
2419 } else
2420 print_pointer(fp, args[sc->offset]);
2421 break;
2422 }
2423 case ExitStatus: {
2424 int status;
2425
2426 if (get_struct(pid, args[sc->offset], &status,
2427 sizeof(status)) != -1) {
2428 fputs("{ ", fp);
2429 if (WIFCONTINUED(status))
2430 fputs("CONTINUED", fp);
2431 else if (WIFEXITED(status))
2432 fprintf(fp, "EXITED,val=%d",
2433 WEXITSTATUS(status));
2434 else if (WIFSIGNALED(status))
2435 fprintf(fp, "SIGNALED,sig=%s%s",
2436 strsig2(WTERMSIG(status)),
2437 WCOREDUMP(status) ? ",cored" : "");
2438 else
2439 fprintf(fp, "STOPPED,sig=%s",
2440 strsig2(WTERMSIG(status)));
2441 fputs(" }", fp);
2442 } else
2443 print_pointer(fp, args[sc->offset]);
2444 break;
2445 }
2446 case Waitoptions:
2447 print_mask_arg(sysdecode_wait6_options, fp, args[sc->offset]);
2448 break;
2449 case Idtype:
2450 print_integer_arg(sysdecode_idtype, fp, args[sc->offset]);
2451 break;
2452 case Procctl:
2453 print_integer_arg(sysdecode_procctl_cmd, fp, args[sc->offset]);
2454 break;
2455 case Umtxop: {
2456 int rem;
2457
2458 if (print_mask_arg_part(sysdecode_umtx_op_flags, fp,
2459 args[sc->offset], &rem))
2460 fprintf(fp, "|");
2461 print_integer_arg(sysdecode_umtx_op, fp, rem);
2462 break;
2463 }
2464 case Atfd:
2465 print_integer_arg(sysdecode_atfd, fp, args[sc->offset]);
2466 break;
2467 case Atflags:
2468 print_mask_arg(sysdecode_atflags, fp, args[sc->offset]);
2469 break;
2470 case Accessmode:
2471 print_mask_arg(sysdecode_access_mode, fp, args[sc->offset]);
2472 break;
2473 case Sysarch:
2474 print_integer_arg(sysdecode_sysarch_number, fp,
2475 args[sc->offset]);
2476 break;
2477 case Sysctl: {
2478 char name[BUFSIZ];
2479 int oid[CTL_MAXNAME + 2];
2480 size_t len;
2481
2482 memset(name, 0, sizeof(name));
2483 len = args[sc->offset + 1];
2484 if (get_struct(pid, args[sc->offset], oid,
2485 len * sizeof(oid[0])) != -1) {
2486 fprintf(fp, "\"");
2487 if (oid[0] == CTL_SYSCTL) {
2488 fprintf(fp, "sysctl.");
2489 switch (oid[1]) {
2490 case CTL_SYSCTL_DEBUG:
2491 fprintf(fp, "debug");
2492 break;
2493 case CTL_SYSCTL_NAME:
2494 fprintf(fp, "name ");
2495 print_sysctl_oid(fp, oid + 2, len - 2);
2496 break;
2497 case CTL_SYSCTL_NEXT:
2498 fprintf(fp, "next");
2499 break;
2500 case CTL_SYSCTL_NAME2OID:
2501 fprintf(fp, "name2oid %s",
2502 get_string(pid,
2503 args[sc->offset + 4],
2504 args[sc->offset + 5]));
2505 break;
2506 case CTL_SYSCTL_OIDFMT:
2507 fprintf(fp, "oidfmt ");
2508 print_sysctl(fp, oid + 2, len - 2);
2509 break;
2510 case CTL_SYSCTL_OIDDESCR:
2511 fprintf(fp, "oiddescr ");
2512 print_sysctl(fp, oid + 2, len - 2);
2513 break;
2514 case CTL_SYSCTL_OIDLABEL:
2515 fprintf(fp, "oidlabel ");
2516 print_sysctl(fp, oid + 2, len - 2);
2517 break;
2518 case CTL_SYSCTL_NEXTNOSKIP:
2519 fprintf(fp, "nextnoskip");
2520 break;
2521 default:
2522 print_sysctl(fp, oid + 1, len - 1);
2523 }
2524 } else {
2525 print_sysctl(fp, oid, len);
2526 }
2527 fprintf(fp, "\"");
2528 }
2529 break;
2530 }
2531 case PipeFds:
2532 /*
2533 * The pipe() system call in the kernel returns its
2534 * two file descriptors via return values. However,
2535 * the interface exposed by libc is that pipe()
2536 * accepts a pointer to an array of descriptors.
2537 * Format the output to match the libc API by printing
2538 * the returned file descriptors as a fake argument.
2539 *
2540 * Overwrite the first retval to signal a successful
2541 * return as well.
2542 */
2543 fprintf(fp, "{ %d, %d }", (int)retval[0], (int)retval[1]);
2544 retval[0] = 0;
2545 break;
2546 case Utrace: {
2547 size_t len;
2548 void *utrace_addr;
2549
2550 len = args[sc->offset + 1];
2551 utrace_addr = calloc(1, len);
2552 if (get_struct(pid, args[sc->offset],
2553 (void *)utrace_addr, len) != -1)
2554 print_utrace(fp, utrace_addr, len);
2555 else
2556 print_pointer(fp, args[sc->offset]);
2557 free(utrace_addr);
2558 break;
2559 }
2560 case IntArray: {
2561 int descriptors[16];
2562 unsigned long i, ndescriptors;
2563 bool truncated;
2564
2565 ndescriptors = args[sc->offset + 1];
2566 truncated = false;
2567 if (ndescriptors > nitems(descriptors)) {
2568 ndescriptors = nitems(descriptors);
2569 truncated = true;
2570 }
2571 if (get_struct(pid, args[sc->offset],
2572 descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
2573 fprintf(fp, "{");
2574 for (i = 0; i < ndescriptors; i++)
2575 fprintf(fp, i == 0 ? " %d" : ", %d",
2576 descriptors[i]);
2577 fprintf(fp, truncated ? ", ... }" : " }");
2578 } else
2579 print_pointer(fp, args[sc->offset]);
2580 break;
2581 }
2582 case Pipe2:
2583 print_mask_arg(sysdecode_pipe2_flags, fp, args[sc->offset]);
2584 break;
2585 case CapFcntlRights: {
2586 uint32_t rights;
2587
2588 if (sc->type & OUT) {
2589 if (get_struct(pid, args[sc->offset], &rights,
2590 sizeof(rights)) == -1) {
2591 print_pointer(fp, args[sc->offset]);
2592 break;
2593 }
2594 } else
2595 rights = args[sc->offset];
2596 print_mask_arg32(sysdecode_cap_fcntlrights, fp, rights);
2597 break;
2598 }
2599 case Fadvice:
2600 print_integer_arg(sysdecode_fadvice, fp, args[sc->offset]);
2601 break;
2602 case FileFlags: {
2603 fflags_t rem;
2604
2605 if (!sysdecode_fileflags(fp, args[sc->offset], &rem))
2606 fprintf(fp, "0x%x", rem);
2607 else if (rem != 0)
2608 fprintf(fp, "|0x%x", rem);
2609 break;
2610 }
2611 case Flockop:
2612 print_mask_arg(sysdecode_flock_operation, fp, args[sc->offset]);
2613 break;
2614 case Getfsstatmode:
2615 print_integer_arg(sysdecode_getfsstat_mode, fp,
2616 args[sc->offset]);
2617 break;
2618 case Kldsymcmd:
2619 print_integer_arg(sysdecode_kldsym_cmd, fp, args[sc->offset]);
2620 break;
2621 case Kldunloadflags:
2622 print_integer_arg(sysdecode_kldunload_flags, fp,
2623 args[sc->offset]);
2624 break;
2625 case AiofsyncOp:
2626 fputs(xlookup(aio_fsync_ops, args[sc->offset]), fp);
2627 break;
2628 case LioMode:
2629 fputs(xlookup(lio_modes, args[sc->offset]), fp);
2630 break;
2631 case Madvice:
2632 print_integer_arg(sysdecode_madvice, fp, args[sc->offset]);
2633 break;
2634 case Socklent:
2635 fprintf(fp, "%u", (socklen_t)args[sc->offset]);
2636 break;
2637 case Sockprotocol: {
2638 const char *temp;
2639 int domain, protocol;
2640
2641 domain = args[sc->offset - 2];
2642 protocol = args[sc->offset];
2643 if (protocol == 0) {
2644 fputs("0", fp);
2645 } else {
2646 temp = sysdecode_socket_protocol(domain, protocol);
2647 if (temp) {
2648 fputs(temp, fp);
2649 } else {
2650 fprintf(fp, "%d", protocol);
2651 }
2652 }
2653 break;
2654 }
2655 case Sockoptlevel:
2656 print_integer_arg(sysdecode_sockopt_level, fp,
2657 args[sc->offset]);
2658 break;
2659 case Sockoptname: {
2660 const char *temp;
2661 int level, name;
2662
2663 level = args[sc->offset - 1];
2664 name = args[sc->offset];
2665 temp = sysdecode_sockopt_name(level, name);
2666 if (temp) {
2667 fputs(temp, fp);
2668 } else {
2669 fprintf(fp, "%d", name);
2670 }
2671 break;
2672 }
2673 case Msgflags:
2674 print_mask_arg(sysdecode_msg_flags, fp, args[sc->offset]);
2675 break;
2676 case CapRights: {
2677 cap_rights_t rights;
2678
2679 if (get_struct(pid, args[sc->offset], &rights,
2680 sizeof(rights)) != -1) {
2681 fputs("{ ", fp);
2682 sysdecode_cap_rights(fp, &rights);
2683 fputs(" }", fp);
2684 } else
2685 print_pointer(fp, args[sc->offset]);
2686 break;
2687 }
2688 case Acltype:
2689 print_integer_arg(sysdecode_acltype, fp, args[sc->offset]);
2690 break;
2691 case Extattrnamespace:
2692 print_integer_arg(sysdecode_extattrnamespace, fp,
2693 args[sc->offset]);
2694 break;
2695 case Minherit:
2696 print_integer_arg(sysdecode_minherit_inherit, fp,
2697 args[sc->offset]);
2698 break;
2699 case Mlockall:
2700 print_mask_arg(sysdecode_mlockall_flags, fp, args[sc->offset]);
2701 break;
2702 case Mountflags:
2703 print_mask_arg(sysdecode_mount_flags, fp, args[sc->offset]);
2704 break;
2705 case Msync:
2706 print_mask_arg(sysdecode_msync_flags, fp, args[sc->offset]);
2707 break;
2708 case Priowhich:
2709 print_integer_arg(sysdecode_prio_which, fp, args[sc->offset]);
2710 break;
2711 case Ptraceop:
2712 print_integer_arg(sysdecode_ptrace_request, fp,
2713 args[sc->offset]);
2714 break;
2715 case Sendfileflags:
2716 print_mask_arg(sysdecode_sendfile_flags, fp, args[sc->offset]);
2717 break;
2718 case Sendfilehdtr: {
2719 struct sf_hdtr hdtr;
2720
2721 if (get_struct(pid, args[sc->offset], &hdtr, sizeof(hdtr)) !=
2722 -1) {
2723 fprintf(fp, "{");
2724 print_iovec(fp, trussinfo, (uintptr_t)hdtr.headers,
2725 hdtr.hdr_cnt);
2726 print_iovec(fp, trussinfo, (uintptr_t)hdtr.trailers,
2727 hdtr.trl_cnt);
2728 fprintf(fp, "}");
2729 } else
2730 print_pointer(fp, args[sc->offset]);
2731 break;
2732 }
2733 case Quotactlcmd:
2734 if (!sysdecode_quotactl_cmd(fp, args[sc->offset]))
2735 fprintf(fp, "%#x", (int)args[sc->offset]);
2736 break;
2737 case Reboothowto:
2738 print_mask_arg(sysdecode_reboot_howto, fp, args[sc->offset]);
2739 break;
2740 case Rtpriofunc:
2741 print_integer_arg(sysdecode_rtprio_function, fp,
2742 args[sc->offset]);
2743 break;
2744 case Schedpolicy:
2745 print_integer_arg(sysdecode_scheduler_policy, fp,
2746 args[sc->offset]);
2747 break;
2748 case Schedparam: {
2749 struct sched_param sp;
2750
2751 if (get_struct(pid, args[sc->offset], &sp, sizeof(sp)) != -1)
2752 fprintf(fp, "{ %d }", sp.sched_priority);
2753 else
2754 print_pointer(fp, args[sc->offset]);
2755 break;
2756 }
2757 case PSig: {
2758 int sig;
2759
2760 if (get_struct(pid, args[sc->offset], &sig, sizeof(sig)) == 0)
2761 fprintf(fp, "{ %s }", strsig2(sig));
2762 else
2763 print_pointer(fp, args[sc->offset]);
2764 break;
2765 }
2766 case Siginfo: {
2767 siginfo_t si;
2768
2769 if (get_struct(pid, args[sc->offset], &si, sizeof(si)) != -1) {
2770 fprintf(fp, "{ signo=%s", strsig2(si.si_signo));
2771 decode_siginfo(fp, &si);
2772 fprintf(fp, " }");
2773 } else
2774 print_pointer(fp, args[sc->offset]);
2775 break;
2776 }
2777 case Iovec:
2778 /*
2779 * Print argument as an array of struct iovec, where the next
2780 * syscall argument is the number of elements of the array.
2781 */
2782
2783 print_iovec(fp, trussinfo, args[sc->offset],
2784 (int)args[sc->offset + 1]);
2785 break;
2786 case Aiocb: {
2787 struct aiocb cb;
2788
2789 if (get_struct(pid, args[sc->offset], &cb, sizeof(cb)) != -1)
2790 print_aiocb(fp, &cb);
2791 else
2792 print_pointer(fp, args[sc->offset]);
2793 break;
2794 }
2795 case AiocbArray: {
2796 /*
2797 * Print argment as an array of pointers to struct aiocb, where
2798 * the next syscall argument is the number of elements.
2799 */
2800 uintptr_t cbs[16];
2801 unsigned int nent;
2802 bool truncated;
2803
2804 nent = args[sc->offset + 1];
2805 truncated = false;
2806 if (nent > nitems(cbs)) {
2807 nent = nitems(cbs);
2808 truncated = true;
2809 }
2810
2811 if (get_struct(pid, args[sc->offset], cbs, sizeof(uintptr_t) * nent) != -1) {
2812 unsigned int i;
2813 fputs("[", fp);
2814 for (i = 0; i < nent; ++i) {
2815 struct aiocb cb;
2816 if (i > 0)
2817 fputc(',', fp);
2818 if (get_struct(pid, cbs[i], &cb, sizeof(cb)) != -1)
2819 print_aiocb(fp, &cb);
2820 else
2821 print_pointer(fp, cbs[i]);
2822 }
2823 if (truncated)
2824 fputs(",...", fp);
2825 fputs("]", fp);
2826 } else
2827 print_pointer(fp, args[sc->offset]);
2828 break;
2829 }
2830 case AiocbPointer: {
2831 /*
2832 * aio_waitcomplete(2) assigns a pointer to a pointer to struct
2833 * aiocb, so we need to handle the extra layer of indirection.
2834 */
2835 uintptr_t cbp;
2836 struct aiocb cb;
2837
2838 if (get_struct(pid, args[sc->offset], &cbp, sizeof(cbp)) != -1) {
2839 if (get_struct(pid, cbp, &cb, sizeof(cb)) != -1)
2840 print_aiocb(fp, &cb);
2841 else
2842 print_pointer(fp, cbp);
2843 } else
2844 print_pointer(fp, args[sc->offset]);
2845 break;
2846 }
2847 case Sctpsndrcvinfo: {
2848 struct sctp_sndrcvinfo info;
2849
2850 if (get_struct(pid, args[sc->offset],
2851 &info, sizeof(struct sctp_sndrcvinfo)) == -1) {
2852 print_pointer(fp, args[sc->offset]);
2853 break;
2854 }
2855 print_sctp_sndrcvinfo(fp, sc->type & OUT, &info);
2856 break;
2857 }
2858 case Msghdr: {
2859 struct msghdr msghdr;
2860
2861 if (get_struct(pid, args[sc->offset],
2862 &msghdr, sizeof(struct msghdr)) == -1) {
2863 print_pointer(fp, args[sc->offset]);
2864 break;
2865 }
2866 fputs("{", fp);
2867 print_sockaddr(fp, trussinfo, (uintptr_t)msghdr.msg_name, msghdr.msg_namelen);
2868 fprintf(fp, ",%d,", msghdr.msg_namelen);
2869 print_iovec(fp, trussinfo, (uintptr_t)msghdr.msg_iov, msghdr.msg_iovlen);
2870 fprintf(fp, ",%d,", msghdr.msg_iovlen);
2871 print_cmsgs(fp, pid, sc->type & OUT, &msghdr);
2872 fprintf(fp, ",%u,", msghdr.msg_controllen);
2873 print_mask_arg(sysdecode_msg_flags, fp, msghdr.msg_flags);
2874 fputs("}", fp);
2875 break;
2876 }
2877
2878 case CloudABIAdvice:
2879 fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
2880 break;
2881 case CloudABIClockID:
2882 fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
2883 break;
2884 case CloudABIFDSFlags:
2885 fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
2886 break;
2887 case CloudABIFDStat: {
2888 cloudabi_fdstat_t fds;
2889 if (get_struct(pid, args[sc->offset], &fds, sizeof(fds))
2890 != -1) {
2891 fprintf(fp, "{ %s, ",
2892 xlookup(cloudabi_filetype, fds.fs_filetype));
2893 fprintf(fp, "%s, ... }",
2894 xlookup_bits(cloudabi_fdflags, fds.fs_flags));
2895 } else
2896 print_pointer(fp, args[sc->offset]);
2897 break;
2898 }
2899 case CloudABIFileStat: {
2900 cloudabi_filestat_t fsb;
2901 if (get_struct(pid, args[sc->offset], &fsb, sizeof(fsb))
2902 != -1)
2903 fprintf(fp, "{ %s, %ju }",
2904 xlookup(cloudabi_filetype, fsb.st_filetype),
2905 (uintmax_t)fsb.st_size);
2906 else
2907 print_pointer(fp, args[sc->offset]);
2908 break;
2909 }
2910 case CloudABIFileType:
2911 fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
2912 break;
2913 case CloudABIFSFlags:
2914 fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
2915 break;
2916 case CloudABILookup:
2917 if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
2918 fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
2919 (int)args[sc->offset]);
2920 else
2921 fprintf(fp, "%d", (int)args[sc->offset]);
2922 break;
2923 case CloudABIMFlags:
2924 fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
2925 break;
2926 case CloudABIMProt:
2927 fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
2928 break;
2929 case CloudABIMSFlags:
2930 fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
2931 break;
2932 case CloudABIOFlags:
2933 fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
2934 break;
2935 case CloudABISDFlags:
2936 fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
2937 break;
2938 case CloudABISignal:
2939 fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
2940 break;
2941 case CloudABITimestamp:
2942 fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
2943 args[sc->offset] % 1000000000);
2944 break;
2945 case CloudABIULFlags:
2946 fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
2947 break;
2948 case CloudABIWhence:
2949 fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
2950 break;
2951
2952 default:
2953 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
2954 }
2955 fclose(fp);
2956 return (tmp);
2957 }
2958
2959 /*
2960 * Print (to outfile) the system call and its arguments.
2961 */
2962 void
print_syscall(struct trussinfo * trussinfo)2963 print_syscall(struct trussinfo *trussinfo)
2964 {
2965 struct threadinfo *t;
2966 const char *name;
2967 char **s_args;
2968 int i, len, nargs;
2969
2970 t = trussinfo->curthread;
2971
2972 name = t->cs.sc->name;
2973 nargs = t->cs.nargs;
2974 s_args = t->cs.s_args;
2975
2976 len = print_line_prefix(trussinfo);
2977 len += fprintf(trussinfo->outfile, "%s(", name);
2978
2979 for (i = 0; i < nargs; i++) {
2980 if (s_args[i] != NULL)
2981 len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2982 else
2983 len += fprintf(trussinfo->outfile,
2984 "<missing argument>");
2985 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2986 "," : "");
2987 }
2988 len += fprintf(trussinfo->outfile, ")");
2989 for (i = 0; i < 6 - (len / 8); i++)
2990 fprintf(trussinfo->outfile, "\t");
2991 }
2992
2993 void
print_syscall_ret(struct trussinfo * trussinfo,int error,register_t * retval)2994 print_syscall_ret(struct trussinfo *trussinfo, int error, register_t *retval)
2995 {
2996 struct timespec timediff;
2997 struct threadinfo *t;
2998 struct syscall *sc;
2999
3000 t = trussinfo->curthread;
3001 sc = t->cs.sc;
3002 if (trussinfo->flags & COUNTONLY) {
3003 timespecsub(&t->after, &t->before, &timediff);
3004 timespecadd(&sc->time, &timediff, &sc->time);
3005 sc->ncalls++;
3006 if (error != 0)
3007 sc->nerror++;
3008 return;
3009 }
3010
3011 print_syscall(trussinfo);
3012 fflush(trussinfo->outfile);
3013
3014 if (retval == NULL) {
3015 /*
3016 * This system call resulted in the current thread's exit,
3017 * so there is no return value or error to display.
3018 */
3019 fprintf(trussinfo->outfile, "\n");
3020 return;
3021 }
3022
3023 if (error == ERESTART)
3024 fprintf(trussinfo->outfile, " ERESTART\n");
3025 else if (error == EJUSTRETURN)
3026 fprintf(trussinfo->outfile, " EJUSTRETURN\n");
3027 else if (error != 0) {
3028 fprintf(trussinfo->outfile, " ERR#%d '%s'\n",
3029 sysdecode_freebsd_to_abi_errno(t->proc->abi->abi, error),
3030 strerror(error));
3031 } else if (sc->decode.ret_type == 2 &&
3032 t->proc->abi->pointer_size == 4) {
3033 off_t off;
3034 #if _BYTE_ORDER == _LITTLE_ENDIAN
3035 off = (off_t)retval[1] << 32 | retval[0];
3036 #else
3037 off = (off_t)retval[0] << 32 | retval[1];
3038 #endif
3039 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
3040 (intmax_t)off);
3041 } else {
3042 fprintf(trussinfo->outfile, " = %jd (0x%jx)\n",
3043 (intmax_t)retval[0], (intmax_t)retval[0]);
3044 }
3045 }
3046
3047 void
print_summary(struct trussinfo * trussinfo)3048 print_summary(struct trussinfo *trussinfo)
3049 {
3050 struct timespec total = {0, 0};
3051 struct syscall *sc;
3052 int ncall, nerror;
3053
3054 fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
3055 "syscall", "seconds", "calls", "errors");
3056 ncall = nerror = 0;
3057 STAILQ_FOREACH(sc, &seen_syscalls, entries) {
3058 if (sc->ncalls) {
3059 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
3060 sc->name, (intmax_t)sc->time.tv_sec,
3061 sc->time.tv_nsec, sc->ncalls, sc->nerror);
3062 timespecadd(&total, &sc->time, &total);
3063 ncall += sc->ncalls;
3064 nerror += sc->nerror;
3065 }
3066 }
3067 fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
3068 "", "-------------", "-------", "-------");
3069 fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
3070 "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);
3071 }
3072