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