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