syscalls.c revision 307144
1/*
2 * Copyright 1997 Sean Eric Fagan
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 * 3. All advertising materials mentioning features or use of this software
13 *    must display the following acknowledgement:
14 *	This product includes software developed by Sean Eric Fagan
15 * 4. Neither the name of the author may be used to endorse or promote
16 *    products derived from this software without specific prior written
17 *    permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: stable/11/usr.bin/truss/syscalls.c 307144 2016-10-12 12:17:41Z ed $");
34
35/*
36 * This file has routines used to print out system calls and their
37 * arguments.
38 */
39
40#include <sys/types.h>
41#include <sys/event.h>
42#include <sys/ioccom.h>
43#include <sys/mman.h>
44#include <sys/mount.h>
45#include <sys/procctl.h>
46#include <sys/ptrace.h>
47#include <sys/resource.h>
48#include <sys/socket.h>
49#include <sys/stat.h>
50#include <sys/umtx.h>
51#include <sys/un.h>
52#include <sys/wait.h>
53#include <machine/sysarch.h>
54#include <netinet/in.h>
55#include <arpa/inet.h>
56
57#include <ctype.h>
58#include <err.h>
59#include <fcntl.h>
60#include <poll.h>
61#include <signal.h>
62#include <stdbool.h>
63#include <stddef.h>
64#include <stdint.h>
65#include <stdio.h>
66#include <stdlib.h>
67#include <string.h>
68#include <sysdecode.h>
69#include <time.h>
70#include <unistd.h>
71#include <vis.h>
72
73#include <contrib/cloudabi/cloudabi_types_common.h>
74
75#include "truss.h"
76#include "extern.h"
77#include "syscall.h"
78
79/* 64-bit alignment on 32-bit platforms. */
80#if !defined(__LP64__) && defined(__powerpc__)
81#define	QUAD_ALIGN	1
82#else
83#define	QUAD_ALIGN	0
84#endif
85
86/* Number of slots needed for a 64-bit argument. */
87#ifdef __LP64__
88#define	QUAD_SLOTS	1
89#else
90#define	QUAD_SLOTS	2
91#endif
92
93/*
94 * This should probably be in its own file, sorted alphabetically.
95 */
96static struct syscall decoded_syscalls[] = {
97	/* Native ABI */
98	{ .name = "__getcwd", .ret_type = 1, .nargs = 2,
99	  .args = { { Name | OUT, 0 }, { Int, 1 } } },
100	{ .name = "_umtx_op", .ret_type = 1, .nargs = 5,
101	  .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
102		    { Ptr, 4 } } },
103	{ .name = "accept", .ret_type = 1, .nargs = 3,
104	  .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
105	{ .name = "access", .ret_type = 1, .nargs = 2,
106	  .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
107	{ .name = "bind", .ret_type = 1, .nargs = 3,
108	  .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
109	{ .name = "bindat", .ret_type = 1, .nargs = 4,
110	  .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
111		    { Int, 3 } } },
112	{ .name = "break", .ret_type = 1, .nargs = 1,
113	  .args = { { Ptr, 0 } } },
114	{ .name = "chdir", .ret_type = 1, .nargs = 1,
115	  .args = { { Name, 0 } } },
116	{ .name = "chflags", .ret_type = 1, .nargs = 2,
117	  .args = { { Name | IN, 0 }, { Hex, 1 } } },
118	{ .name = "chmod", .ret_type = 1, .nargs = 2,
119	  .args = { { Name, 0 }, { Octal, 1 } } },
120	{ .name = "chown", .ret_type = 1, .nargs = 3,
121	  .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
122	{ .name = "chroot", .ret_type = 1, .nargs = 1,
123	  .args = { { Name, 0 } } },
124	{ .name = "clock_gettime", .ret_type = 1, .nargs = 2,
125	  .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
126	{ .name = "close", .ret_type = 1, .nargs = 1,
127	  .args = { { Int, 0 } } },
128	{ .name = "connect", .ret_type = 1, .nargs = 3,
129	  .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
130	{ .name = "connectat", .ret_type = 1, .nargs = 4,
131	  .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
132		    { Int, 3 } } },
133	{ .name = "eaccess", .ret_type = 1, .nargs = 2,
134	  .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
135	{ .name = "execve", .ret_type = 1, .nargs = 3,
136	  .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
137		    { ExecEnv | IN, 2 } } },
138	{ .name = "exit", .ret_type = 0, .nargs = 1,
139	  .args = { { Hex, 0 } } },
140	{ .name = "faccessat", .ret_type = 1, .nargs = 4,
141	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
142		    { Atflags, 3 } } },
143	{ .name = "fchmod", .ret_type = 1, .nargs = 2,
144	  .args = { { Int, 0 }, { Octal, 1 } } },
145	{ .name = "fchmodat", .ret_type = 1, .nargs = 4,
146	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
147	{ .name = "fchown", .ret_type = 1, .nargs = 3,
148	  .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
149	{ .name = "fchownat", .ret_type = 1, .nargs = 5,
150	  .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
151		    { Atflags, 4 } } },
152	{ .name = "fcntl", .ret_type = 1, .nargs = 3,
153	  .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
154	{ .name = "fstat", .ret_type = 1, .nargs = 2,
155	  .args = { { Int, 0 }, { Stat | OUT, 1 } } },
156	{ .name = "fstatat", .ret_type = 1, .nargs = 4,
157	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
158		    { Atflags, 3 } } },
159	{ .name = "fstatfs", .ret_type = 1, .nargs = 2,
160	  .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
161	{ .name = "ftruncate", .ret_type = 1, .nargs = 2,
162	  .args = { { Int | IN, 0 }, { QuadHex | IN, 1 + QUAD_ALIGN } } },
163	{ .name = "futimens", .ret_type = 1, .nargs = 2,
164	  .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
165	{ .name = "futimes", .ret_type = 1, .nargs = 2,
166	  .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
167	{ .name = "futimesat", .ret_type = 1, .nargs = 3,
168	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
169	{ .name = "getitimer", .ret_type = 1, .nargs = 2,
170	  .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
171	{ .name = "getpeername", .ret_type = 1, .nargs = 3,
172	  .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
173	{ .name = "getpgid", .ret_type = 1, .nargs = 1,
174	  .args = { { Int, 0 } } },
175	{ .name = "getrlimit", .ret_type = 1, .nargs = 2,
176	  .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
177	{ .name = "getrusage", .ret_type = 1, .nargs = 2,
178	  .args = { { Int, 0 }, { Rusage | OUT, 1 } } },
179	{ .name = "getsid", .ret_type = 1, .nargs = 1,
180	  .args = { { Int, 0 } } },
181	{ .name = "getsockname", .ret_type = 1, .nargs = 3,
182	  .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
183	{ .name = "gettimeofday", .ret_type = 1, .nargs = 2,
184	  .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
185	{ .name = "ioctl", .ret_type = 1, .nargs = 3,
186	  .args = { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 } } },
187	{ .name = "kevent", .ret_type = 1, .nargs = 6,
188	  .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
189		    { Int, 4 }, { Timespec, 5 } } },
190	{ .name = "kill", .ret_type = 1, .nargs = 2,
191	  .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
192	{ .name = "kldfind", .ret_type = 1, .nargs = 1,
193	  .args = { { Name | IN, 0 } } },
194	{ .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
195	  .args = { { Int, 0 } } },
196	{ .name = "kldload", .ret_type = 1, .nargs = 1,
197	  .args = { { Name | IN, 0 } } },
198	{ .name = "kldnext", .ret_type = 1, .nargs = 1,
199	  .args = { { Int, 0 } } },
200	{ .name = "kldstat", .ret_type = 1, .nargs = 2,
201	  .args = { { Int, 0 }, { Ptr, 1 } } },
202	{ .name = "kldunload", .ret_type = 1, .nargs = 1,
203	  .args = { { Int, 0 } } },
204	{ .name = "kse_release", .ret_type = 0, .nargs = 1,
205	  .args = { { Timespec, 0 } } },
206	{ .name = "lchflags", .ret_type = 1, .nargs = 2,
207	  .args = { { Name | IN, 0 }, { Hex, 1 } } },
208	{ .name = "lchmod", .ret_type = 1, .nargs = 2,
209	  .args = { { Name, 0 }, { Octal, 1 } } },
210	{ .name = "lchown", .ret_type = 1, .nargs = 3,
211	  .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
212	{ .name = "link", .ret_type = 1, .nargs = 2,
213	  .args = { { Name, 0 }, { Name, 1 } } },
214	{ .name = "linkat", .ret_type = 1, .nargs = 5,
215	  .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
216		    { Atflags, 4 } } },
217	{ .name = "lseek", .ret_type = 2, .nargs = 3,
218	  .args = { { Int, 0 }, { QuadHex, 1 + QUAD_ALIGN },
219		    { Whence, 1 + QUAD_SLOTS + QUAD_ALIGN } } },
220	{ .name = "lstat", .ret_type = 1, .nargs = 2,
221	  .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
222	{ .name = "lutimes", .ret_type = 1, .nargs = 2,
223	  .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
224	{ .name = "mkdir", .ret_type = 1, .nargs = 2,
225	  .args = { { Name, 0 }, { Octal, 1 } } },
226	{ .name = "mkdirat", .ret_type = 1, .nargs = 3,
227	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
228	{ .name = "mkfifo", .ret_type = 1, .nargs = 2,
229	  .args = { { Name, 0 }, { Octal, 1 } } },
230	{ .name = "mkfifoat", .ret_type = 1, .nargs = 3,
231	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
232	{ .name = "mknod", .ret_type = 1, .nargs = 3,
233	  .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
234	{ .name = "mknodat", .ret_type = 1, .nargs = 4,
235	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
236	{ .name = "mmap", .ret_type = 1, .nargs = 6,
237	  .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
238		    { Int, 4 }, { QuadHex, 5 + QUAD_ALIGN } } },
239	{ .name = "modfind", .ret_type = 1, .nargs = 1,
240	  .args = { { Name | IN, 0 } } },
241	{ .name = "mount", .ret_type = 1, .nargs = 4,
242	  .args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } },
243	{ .name = "mprotect", .ret_type = 1, .nargs = 3,
244	  .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 } } },
245	{ .name = "munmap", .ret_type = 1, .nargs = 2,
246	  .args = { { Ptr, 0 }, { Int, 1 } } },
247	{ .name = "nanosleep", .ret_type = 1, .nargs = 1,
248	  .args = { { Timespec, 0 } } },
249	{ .name = "open", .ret_type = 1, .nargs = 3,
250	  .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
251	{ .name = "openat", .ret_type = 1, .nargs = 4,
252	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
253		    { Octal, 3 } } },
254	{ .name = "pathconf", .ret_type = 1, .nargs = 2,
255	  .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
256	{ .name = "pipe", .ret_type = 1, .nargs = 1,
257	  .args = { { PipeFds | OUT, 0 } } },
258	{ .name = "pipe2", .ret_type = 1, .nargs = 2,
259	  .args = { { Ptr, 0 }, { Open, 1 } } },
260	{ .name = "poll", .ret_type = 1, .nargs = 3,
261	  .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
262	{ .name = "posix_openpt", .ret_type = 1, .nargs = 1,
263	  .args = { { Open, 0 } } },
264	{ .name = "procctl", .ret_type = 1, .nargs = 4,
265	  .args = { { Idtype, 0 }, { Quad, 1 + QUAD_ALIGN },
266		    { Procctl, 1 + QUAD_ALIGN + QUAD_SLOTS },
267		    { Ptr, 2 + QUAD_ALIGN + QUAD_SLOTS } } },
268	{ .name = "read", .ret_type = 1, .nargs = 3,
269	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 } } },
270	{ .name = "readlink", .ret_type = 1, .nargs = 3,
271	  .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Int, 2 } } },
272	{ .name = "readlinkat", .ret_type = 1, .nargs = 4,
273	  .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
274		    { Int, 3 } } },
275	{ .name = "recvfrom", .ret_type = 1, .nargs = 6,
276	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Hex, 3 },
277		    { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } },
278	{ .name = "rename", .ret_type = 1, .nargs = 2,
279	  .args = { { Name, 0 }, { Name, 1 } } },
280	{ .name = "renameat", .ret_type = 1, .nargs = 4,
281	  .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
282	{ .name = "rfork", .ret_type = 1, .nargs = 1,
283	  .args = { { Rforkflags, 0 } } },
284	{ .name = "rmdir", .ret_type = 1, .nargs = 1,
285	  .args = { { Name, 0 } } },
286	{ .name = "select", .ret_type = 1, .nargs = 5,
287	  .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
288		    { Timeval, 4 } } },
289	{ .name = "sendto", .ret_type = 1, .nargs = 6,
290	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Hex, 3 },
291		    { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } },
292	{ .name = "setitimer", .ret_type = 1, .nargs = 3,
293	  .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
294	{ .name = "setrlimit", .ret_type = 1, .nargs = 2,
295	  .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
296	{ .name = "shutdown", .ret_type = 1, .nargs = 2,
297	  .args = { { Int, 0 }, { Shutdown, 1 } } },
298	{ .name = "sigaction", .ret_type = 1, .nargs = 3,
299	  .args = { { Signal, 0 }, { Sigaction | IN, 1 },
300		    { Sigaction | OUT, 2 } } },
301	{ .name = "sigpending", .ret_type = 1, .nargs = 1,
302	  .args = { { Sigset | OUT, 0 } } },
303	{ .name = "sigprocmask", .ret_type = 1, .nargs = 3,
304	  .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
305	{ .name = "sigqueue", .ret_type = 1, .nargs = 3,
306	  .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
307	{ .name = "sigreturn", .ret_type = 1, .nargs = 1,
308	  .args = { { Ptr, 0 } } },
309	{ .name = "sigsuspend", .ret_type = 1, .nargs = 1,
310	  .args = { { Sigset | IN, 0 } } },
311	{ .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
312	  .args = { { Sigset | IN, 0 }, { Ptr, 1 }, { Timespec | IN, 2 } } },
313	{ .name = "sigwait", .ret_type = 1, .nargs = 2,
314	  .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
315	{ .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
316	  .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
317	{ .name = "socket", .ret_type = 1, .nargs = 3,
318	  .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Int, 2 } } },
319	{ .name = "stat", .ret_type = 1, .nargs = 2,
320	  .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
321	{ .name = "statfs", .ret_type = 1, .nargs = 2,
322	  .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } },
323	{ .name = "symlink", .ret_type = 1, .nargs = 2,
324	  .args = { { Name, 0 }, { Name, 1 } } },
325	{ .name = "symlinkat", .ret_type = 1, .nargs = 3,
326	  .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } },
327	{ .name = "sysarch", .ret_type = 1, .nargs = 2,
328	  .args = { { Sysarch, 0 }, { Ptr, 1 } } },
329	{ .name = "thr_kill", .ret_type = 1, .nargs = 2,
330	  .args = { { Long, 0 }, { Signal, 1 } } },
331	{ .name = "thr_self", .ret_type = 1, .nargs = 1,
332	  .args = { { Ptr, 0 } } },
333	{ .name = "truncate", .ret_type = 1, .nargs = 2,
334	  .args = { { Name | IN, 0 }, { QuadHex | IN, 1 + QUAD_ALIGN } } },
335#if 0
336	/* Does not exist */
337	{ .name = "umount", .ret_type = 1, .nargs = 2,
338	  .args = { { Name, 0 }, { Int, 2 } } },
339#endif
340	{ .name = "unlink", .ret_type = 1, .nargs = 1,
341	  .args = { { Name, 0 } } },
342	{ .name = "unlinkat", .ret_type = 1, .nargs = 3,
343	  .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
344	{ .name = "unmount", .ret_type = 1, .nargs = 2,
345	  .args = { { Name, 0 }, { Int, 1 } } },
346	{ .name = "utimensat", .ret_type = 1, .nargs = 4,
347	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
348		    { Atflags, 3 } } },
349	{ .name = "utimes", .ret_type = 1, .nargs = 2,
350	  .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
351	{ .name = "utrace", .ret_type = 1, .nargs = 1,
352	  .args = { { Utrace, 0 } } },
353	{ .name = "wait4", .ret_type = 1, .nargs = 4,
354	  .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
355		    { Rusage | OUT, 3 } } },
356	{ .name = "wait6", .ret_type = 1, .nargs = 6,
357	  .args = { { Idtype, 0 }, { Quad, 1 + QUAD_ALIGN },
358		    { ExitStatus | OUT, 1 + QUAD_ALIGN + QUAD_SLOTS },
359		    { Waitoptions, 2 + QUAD_ALIGN + QUAD_SLOTS },
360		    { Rusage | OUT, 3 + QUAD_ALIGN + QUAD_SLOTS },
361		    { Ptr, 4 + QUAD_ALIGN + QUAD_SLOTS } } },
362	{ .name = "write", .ret_type = 1, .nargs = 3,
363	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 } } },
364
365	/* Linux ABI */
366	{ .name = "linux_access", .ret_type = 1, .nargs = 2,
367	  .args = { { Name, 0 }, { Accessmode, 1 } } },
368	{ .name = "linux_execve", .ret_type = 1, .nargs = 3,
369	  .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
370		    { ExecEnv | IN, 2 } } },
371	{ .name = "linux_lseek", .ret_type = 2, .nargs = 3,
372	  .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
373	{ .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
374	  .args = { { Name | IN, 0 }, { Int, 1 } } },
375	{ .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
376	  .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
377	{ .name = "linux_newstat", .ret_type = 1, .nargs = 2,
378	  .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
379	{ .name = "linux_open", .ret_type = 1, .nargs = 3,
380	  .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
381	{ .name = "linux_readlink", .ret_type = 1, .nargs = 3,
382	  .args = { { Name, 0 }, { Name | OUT, 1 }, { Int, 2 } } },
383	{ .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
384	  .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
385	{ .name = "linux_stat64", .ret_type = 1, .nargs = 3,
386	  .args = { { Name | IN, 0 }, { Ptr | OUT, 1 }, { Ptr | IN, 1 } } },
387
388	/* CloudABI system calls. */
389	{ .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
390	  .args = { { CloudABIClockID, 0 } } },
391	{ .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
392	  .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
393	{ .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
394	  .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
395	{ .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
396	  .args = { { Int, 0 } } },
397	{ .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
398	  .args = { { CloudABIFileType, 0 } } },
399	{ .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
400	  .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
401	{ .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
402	  .args = { { Int, 0 } } },
403	{ .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
404	  .args = { { Int, 0 } } },
405	{ .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
406	  .args = { { Int, 0 }, { Int, 1 } } },
407	{ .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
408	  .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
409	{ .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
410	  .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
411	{ .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
412	  .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
413	            { ClouduABIFDSFlags, 2 } } },
414	{ .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
415	  .args = { { Int, 0 } } },
416	{ .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
417	  .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
418	            { CloudABIAdvice, 3 } } },
419	{ .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
420	  .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
421	{ .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
422	  .args = { { Int, 0 }, { BinString | IN, 1 },
423	            { CloudABIFileType, 3 } } },
424	{ .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
425	  .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
426	            { Int, 3 }, { BinString | IN, 4 } } },
427	{ .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
428	  .args = { { Int, 0 }, { BinString | IN, 1 },
429	            { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
430	{ .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
431	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
432	            { Int, 3 } } },
433	{ .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
434	  .args = { { Int, 0 }, { BinString | IN, 1 },
435	            { BinString | OUT, 3 }, { Int, 4 } } },
436	{ .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
437	  .args = { { Int, 0 }, { BinString | IN, 1 },
438	            { Int, 3 }, { BinString | IN, 4 } } },
439	{ .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
440	  .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
441	{ .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
442	  .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
443	            { CloudABIFSFlags, 2 } } },
444	{ .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
445	  .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
446	            { CloudABIFileStat | OUT, 3 } } },
447	{ .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
448	  .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
449	            { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
450	{ .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
451	  .args = { { BinString | IN, 0 },
452	            { Int, 2 }, { BinString | IN, 3 } } },
453	{ .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
454	  .args = { { Int, 0 }, { BinString | IN, 1 },
455	            { CloudABIULFlags, 3 } } },
456	{ .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
457	  .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
458	{ .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
459	  .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
460	{ .name = "cloudabi_sys_mem_lock", .ret_type = 1, .nargs = 2,
461	  .args = { { Ptr, 0 }, { Int, 1 } } },
462	{ .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
463	  .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
464	            { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
465	{ .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
466	  .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
467	{ .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
468	  .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
469	{ .name = "cloudabi_sys_mem_unlock", .ret_type = 1, .nargs = 2,
470	  .args = { { Ptr, 0 }, { Int, 1 } } },
471	{ .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
472	  .args = { { Ptr, 0 }, { Int, 1 } } },
473	{ .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
474	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
475	            { IntArray, 3 }, { Int, 4 } } },
476	{ .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
477	  .args = { { Int, 0 } } },
478	{ .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
479	{ .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
480	  .args = { { CloudABISignal, 0 } } },
481	{ .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
482	  .args = { { BinString | OUT, 0 }, { Int, 1 } } },
483	{ .name = "cloudabi_sys_sock_accept", .ret_type = 1, .nargs = 2,
484	  .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 } } },
485	{ .name = "cloudabi_sys_sock_bind", .ret_type = 1, .nargs = 3,
486	  .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
487	{ .name = "cloudabi_sys_sock_connect", .ret_type = 1, .nargs = 3,
488	  .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
489	{ .name = "cloudabi_sys_sock_listen", .ret_type = 1, .nargs = 2,
490	  .args = { { Int, 0 }, { Int, 1 } } },
491	{ .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
492	  .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
493	{ .name = "cloudabi_sys_sock_stat_get", .ret_type = 1, .nargs = 3,
494	  .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 },
495	            { CloudABISSFlags, 2 } } },
496	{ .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
497	  .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
498	{ .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
499
500	{ .name = 0 },
501};
502static STAILQ_HEAD(, syscall) syscalls;
503
504/* Xlat idea taken from strace */
505struct xlat {
506	int val;
507	const char *str;
508};
509
510#define	X(a)	{ a, #a },
511#define	XEND	{ 0, NULL }
512
513static struct xlat kevent_filters[] = {
514	X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
515	X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
516	X(EVFILT_PROCDESC) X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER)
517	X(EVFILT_SENDFILE) XEND
518};
519
520static struct xlat kevent_flags[] = {
521	X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
522	X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH) X(EV_FORCEONESHOT)
523	X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
524};
525
526static struct xlat kevent_user_ffctrl[] = {
527	X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
528	XEND
529};
530
531static struct xlat kevent_rdwr_fflags[] = {
532	X(NOTE_LOWAT) X(NOTE_FILE_POLL) XEND
533};
534
535static struct xlat kevent_vnode_fflags[] = {
536	X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB)
537	X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND
538};
539
540static struct xlat kevent_proc_fflags[] = {
541	X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR)
542	X(NOTE_CHILD) XEND
543};
544
545static struct xlat kevent_timer_fflags[] = {
546	X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS)
547	XEND
548};
549
550static struct xlat poll_flags[] = {
551	X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
552	X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
553	X(POLLWRBAND) X(POLLINIGNEOF) XEND
554};
555
556static struct xlat mmap_flags[] = {
557	X(MAP_SHARED) X(MAP_PRIVATE) X(MAP_FIXED) X(MAP_RESERVED0020)
558	X(MAP_RESERVED0040) X(MAP_RESERVED0080) X(MAP_RESERVED0100)
559	X(MAP_HASSEMAPHORE) X(MAP_STACK) X(MAP_NOSYNC) X(MAP_ANON)
560	X(MAP_EXCL) X(MAP_NOCORE) X(MAP_PREFAULT_READ)
561#ifdef MAP_32BIT
562	X(MAP_32BIT)
563#endif
564	XEND
565};
566
567static struct xlat mprot_flags[] = {
568	X(PROT_NONE) X(PROT_READ) X(PROT_WRITE) X(PROT_EXEC) XEND
569};
570
571static struct xlat whence_arg[] = {
572	X(SEEK_SET) X(SEEK_CUR) X(SEEK_END) X(SEEK_DATA) X(SEEK_HOLE) XEND
573};
574
575static struct xlat sigaction_flags[] = {
576	X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
577	X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
578};
579
580static struct xlat fcntl_arg[] = {
581	X(F_DUPFD) X(F_GETFD) X(F_SETFD) X(F_GETFL) X(F_SETFL)
582	X(F_GETOWN) X(F_SETOWN) X(F_OGETLK) X(F_OSETLK) X(F_OSETLKW)
583	X(F_DUP2FD) X(F_GETLK) X(F_SETLK) X(F_SETLKW) X(F_SETLK_REMOTE)
584	X(F_READAHEAD) X(F_RDAHEAD) X(F_DUPFD_CLOEXEC) X(F_DUP2FD_CLOEXEC)
585	XEND
586};
587
588static struct xlat fcntlfd_arg[] = {
589	X(FD_CLOEXEC) XEND
590};
591
592static struct xlat fcntlfl_arg[] = {
593	X(O_APPEND) X(O_ASYNC) X(O_FSYNC) X(O_NONBLOCK) X(O_NOFOLLOW)
594	X(FRDAHEAD) X(O_DIRECT) XEND
595};
596
597static struct xlat sockdomain_arg[] = {
598	X(PF_UNSPEC) X(PF_LOCAL) X(PF_UNIX) X(PF_INET) X(PF_IMPLINK)
599	X(PF_PUP) X(PF_CHAOS) X(PF_NETBIOS) X(PF_ISO) X(PF_OSI)
600	X(PF_ECMA) X(PF_DATAKIT) X(PF_CCITT) X(PF_SNA) X(PF_DECnet)
601	X(PF_DLI) X(PF_LAT) X(PF_HYLINK) X(PF_APPLETALK) X(PF_ROUTE)
602	X(PF_LINK) X(PF_XTP) X(PF_COIP) X(PF_CNT) X(PF_SIP) X(PF_IPX)
603	X(PF_RTIP) X(PF_PIP) X(PF_ISDN) X(PF_KEY) X(PF_INET6)
604	X(PF_NATM) X(PF_ATM) X(PF_NETGRAPH) X(PF_SLOW) X(PF_SCLUSTER)
605	X(PF_ARP) X(PF_BLUETOOTH) X(PF_IEEE80211) X(PF_INET_SDP)
606	X(PF_INET6_SDP) XEND
607};
608
609static struct xlat socktype_arg[] = {
610	X(SOCK_STREAM) X(SOCK_DGRAM) X(SOCK_RAW) X(SOCK_RDM)
611	X(SOCK_SEQPACKET) XEND
612};
613
614static struct xlat open_flags[] = {
615	X(O_RDONLY) X(O_WRONLY) X(O_RDWR) X(O_ACCMODE) X(O_NONBLOCK)
616	X(O_APPEND) X(O_SHLOCK) X(O_EXLOCK) X(O_ASYNC) X(O_FSYNC)
617	X(O_NOFOLLOW) X(O_CREAT) X(O_TRUNC) X(O_EXCL) X(O_NOCTTY)
618	X(O_DIRECT) X(O_DIRECTORY) X(O_EXEC) X(O_TTY_INIT) X(O_CLOEXEC)
619	X(O_VERIFY) XEND
620};
621
622static struct xlat shutdown_arg[] = {
623	X(SHUT_RD) X(SHUT_WR) X(SHUT_RDWR) XEND
624};
625
626static struct xlat resource_arg[] = {
627	X(RLIMIT_CPU) X(RLIMIT_FSIZE) X(RLIMIT_DATA) X(RLIMIT_STACK)
628	X(RLIMIT_CORE) X(RLIMIT_RSS) X(RLIMIT_MEMLOCK) X(RLIMIT_NPROC)
629	X(RLIMIT_NOFILE) X(RLIMIT_SBSIZE) X(RLIMIT_VMEM) X(RLIMIT_NPTS)
630	X(RLIMIT_SWAP) X(RLIMIT_KQUEUES) XEND
631};
632
633static struct xlat pathconf_arg[] = {
634	X(_PC_LINK_MAX)  X(_PC_MAX_CANON)  X(_PC_MAX_INPUT)
635	X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF)
636	X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE)
637	X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO)
638	X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS)
639	X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE)
640	X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
641	X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
642	X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
643	X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND
644};
645
646static struct xlat rfork_flags[] = {
647	X(RFFDG) X(RFPROC) X(RFMEM) X(RFNOWAIT) X(RFCFDG) X(RFTHREAD)
648	X(RFSIGSHARE) X(RFLINUXTHPN) X(RFTSIGZMB) X(RFPPWAIT) XEND
649};
650
651static struct xlat wait_options[] = {
652	X(WNOHANG) X(WUNTRACED) X(WCONTINUED) X(WNOWAIT) X(WEXITED)
653	X(WTRAPPED) XEND
654};
655
656static struct xlat idtype_arg[] = {
657	X(P_PID) X(P_PPID) X(P_PGID) X(P_SID) X(P_CID) X(P_UID) X(P_GID)
658	X(P_ALL) X(P_LWPID) X(P_TASKID) X(P_PROJID) X(P_POOLID) X(P_JAILID)
659	X(P_CTID) X(P_CPUID) X(P_PSETID) XEND
660};
661
662static struct xlat procctl_arg[] = {
663	X(PROC_SPROTECT) X(PROC_REAP_ACQUIRE) X(PROC_REAP_RELEASE)
664	X(PROC_REAP_STATUS) X(PROC_REAP_GETPIDS) X(PROC_REAP_KILL)
665	X(PROC_TRACE_CTL) X(PROC_TRACE_STATUS) XEND
666};
667
668static struct xlat umtx_ops[] = {
669	X(UMTX_OP_RESERVED0) X(UMTX_OP_RESERVED1) X(UMTX_OP_WAIT)
670	X(UMTX_OP_WAKE) X(UMTX_OP_MUTEX_TRYLOCK) X(UMTX_OP_MUTEX_LOCK)
671	X(UMTX_OP_MUTEX_UNLOCK) X(UMTX_OP_SET_CEILING) X(UMTX_OP_CV_WAIT)
672	X(UMTX_OP_CV_SIGNAL) X(UMTX_OP_CV_BROADCAST) X(UMTX_OP_WAIT_UINT)
673	X(UMTX_OP_RW_RDLOCK) X(UMTX_OP_RW_WRLOCK) X(UMTX_OP_RW_UNLOCK)
674	X(UMTX_OP_WAIT_UINT_PRIVATE) X(UMTX_OP_WAKE_PRIVATE)
675	X(UMTX_OP_MUTEX_WAIT) X(UMTX_OP_MUTEX_WAKE) X(UMTX_OP_SEM_WAIT)
676	X(UMTX_OP_SEM_WAKE) X(UMTX_OP_NWAKE_PRIVATE) X(UMTX_OP_MUTEX_WAKE2)
677	X(UMTX_OP_SEM2_WAIT) X(UMTX_OP_SEM2_WAKE)
678	XEND
679};
680
681static struct xlat at_flags[] = {
682	X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW)
683	X(AT_REMOVEDIR) XEND
684};
685
686static struct xlat access_modes[] = {
687	X(R_OK) X(W_OK) X(X_OK) XEND
688};
689
690static struct xlat sysarch_ops[] = {
691#if defined(__i386__) || defined(__amd64__)
692	X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM)
693	X(I386_VM86) X(I386_GET_FSBASE) X(I386_SET_FSBASE) X(I386_GET_GSBASE)
694	X(I386_SET_GSBASE) X(I386_GET_XFPUSTATE) X(AMD64_GET_FSBASE)
695	X(AMD64_SET_FSBASE) X(AMD64_GET_GSBASE) X(AMD64_SET_GSBASE)
696	X(AMD64_GET_XFPUSTATE)
697#endif
698	XEND
699};
700
701static struct xlat linux_socketcall_ops[] = {
702	X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
703	X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
704	X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
705	X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
706	X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
707	XEND
708};
709
710static struct xlat sigprocmask_ops[] = {
711	X(SIG_BLOCK) X(SIG_UNBLOCK) X(SIG_SETMASK)
712	XEND
713};
714
715#undef X
716#define	X(a)	{ CLOUDABI_##a, #a },
717
718static struct xlat cloudabi_advice[] = {
719	X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
720	X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
721	XEND
722};
723
724static struct xlat cloudabi_clockid[] = {
725	X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
726	X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
727	XEND
728};
729
730static struct xlat cloudabi_errno[] = {
731	X(E2BIG) X(EACCES) X(EADDRINUSE) X(EADDRNOTAVAIL)
732	X(EAFNOSUPPORT) X(EAGAIN) X(EALREADY) X(EBADF) X(EBADMSG)
733	X(EBUSY) X(ECANCELED) X(ECHILD) X(ECONNABORTED) X(ECONNREFUSED)
734	X(ECONNRESET) X(EDEADLK) X(EDESTADDRREQ) X(EDOM) X(EDQUOT)
735	X(EEXIST) X(EFAULT) X(EFBIG) X(EHOSTUNREACH) X(EIDRM) X(EILSEQ)
736	X(EINPROGRESS) X(EINTR) X(EINVAL) X(EIO) X(EISCONN) X(EISDIR)
737	X(ELOOP) X(EMFILE) X(EMLINK) X(EMSGSIZE) X(EMULTIHOP)
738	X(ENAMETOOLONG) X(ENETDOWN) X(ENETRESET) X(ENETUNREACH)
739	X(ENFILE) X(ENOBUFS) X(ENODEV) X(ENOENT) X(ENOEXEC) X(ENOLCK)
740	X(ENOLINK) X(ENOMEM) X(ENOMSG) X(ENOPROTOOPT) X(ENOSPC)
741	X(ENOSYS) X(ENOTCONN) X(ENOTDIR) X(ENOTEMPTY) X(ENOTRECOVERABLE)
742	X(ENOTSOCK) X(ENOTSUP) X(ENOTTY) X(ENXIO) X(EOVERFLOW)
743	X(EOWNERDEAD) X(EPERM) X(EPIPE) X(EPROTO) X(EPROTONOSUPPORT)
744	X(EPROTOTYPE) X(ERANGE) X(EROFS) X(ESPIPE) X(ESRCH) X(ESTALE)
745	X(ETIMEDOUT) X(ETXTBSY) X(EXDEV) X(ENOTCAPABLE)
746	XEND
747};
748
749static struct xlat cloudabi_fdflags[] = {
750	X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
751	X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
752	XEND
753};
754
755static struct xlat cloudabi_fdsflags[] = {
756	X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
757	XEND
758};
759
760static struct xlat cloudabi_filetype[] = {
761	X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
762	X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
763	X(FILETYPE_FIFO) X(FILETYPE_POLL) X(FILETYPE_PROCESS)
764	X(FILETYPE_REGULAR_FILE) X(FILETYPE_SHARED_MEMORY)
765	X(FILETYPE_SOCKET_DGRAM) X(FILETYPE_SOCKET_SEQPACKET)
766	X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK)
767	XEND
768};
769
770static struct xlat cloudabi_fsflags[] = {
771	X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
772	X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
773	XEND
774};
775
776static struct xlat cloudabi_mflags[] = {
777	X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
778	XEND
779};
780
781static struct xlat cloudabi_mprot[] = {
782	X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
783	XEND
784};
785
786static struct xlat cloudabi_msflags[] = {
787	X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
788	XEND
789};
790
791static struct xlat cloudabi_oflags[] = {
792	X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
793	XEND
794};
795
796static struct xlat cloudabi_sa_family[] = {
797	X(AF_UNSPEC) X(AF_INET) X(AF_INET6) X(AF_UNIX)
798	XEND
799};
800
801static struct xlat cloudabi_sdflags[] = {
802	X(SHUT_RD) X(SHUT_WR)
803	XEND
804};
805
806static struct xlat cloudabi_signal[] = {
807	X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
808	X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
809	X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
810	X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
811	X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
812	XEND
813};
814
815static struct xlat cloudabi_ssflags[] = {
816	X(SOCKSTAT_CLEAR_ERROR)
817	XEND
818};
819
820static struct xlat cloudabi_ssstate[] = {
821	X(SOCKSTATE_ACCEPTCONN)
822	XEND
823};
824
825static struct xlat cloudabi_ulflags[] = {
826	X(UNLINK_REMOVEDIR)
827	XEND
828};
829
830static struct xlat cloudabi_whence[] = {
831	X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
832	XEND
833};
834
835#undef X
836#undef XEND
837
838/*
839 * Searches an xlat array for a value, and returns it if found.  Otherwise
840 * return a string representation.
841 */
842static const char *
843lookup(struct xlat *xlat, int val, int base)
844{
845	static char tmp[16];
846
847	for (; xlat->str != NULL; xlat++)
848		if (xlat->val == val)
849			return (xlat->str);
850	switch (base) {
851		case 8:
852			sprintf(tmp, "0%o", val);
853			break;
854		case 16:
855			sprintf(tmp, "0x%x", val);
856			break;
857		case 10:
858			sprintf(tmp, "%u", val);
859			break;
860		default:
861			errx(1,"Unknown lookup base");
862			break;
863	}
864	return (tmp);
865}
866
867static const char *
868xlookup(struct xlat *xlat, int val)
869{
870
871	return (lookup(xlat, val, 16));
872}
873
874/*
875 * Searches an xlat array containing bitfield values.  Remaining bits
876 * set after removing the known ones are printed at the end:
877 * IN|0x400.
878 */
879static char *
880xlookup_bits(struct xlat *xlat, int val)
881{
882	int len, rem;
883	static char str[512];
884
885	len = 0;
886	rem = val;
887	for (; xlat->str != NULL; xlat++) {
888		if ((xlat->val & rem) == xlat->val) {
889			/*
890			 * Don't print the "all-bits-zero" string unless all
891			 * bits are really zero.
892			 */
893			if (xlat->val == 0 && val != 0)
894				continue;
895			len += sprintf(str + len, "%s|", xlat->str);
896			rem &= ~(xlat->val);
897		}
898	}
899
900	/*
901	 * If we have leftover bits or didn't match anything, print
902	 * the remainder.
903	 */
904	if (rem || len == 0)
905		len += sprintf(str + len, "0x%x", rem);
906	if (len && str[len - 1] == '|')
907		len--;
908	str[len] = 0;
909	return (str);
910}
911
912void
913init_syscalls(void)
914{
915	struct syscall *sc;
916
917	STAILQ_INIT(&syscalls);
918	for (sc = decoded_syscalls; sc->name != NULL; sc++)
919		STAILQ_INSERT_HEAD(&syscalls, sc, entries);
920}
921/*
922 * If/when the list gets big, it might be desirable to do it
923 * as a hash table or binary search.
924 */
925struct syscall *
926get_syscall(const char *name, int nargs)
927{
928	struct syscall *sc;
929	int i;
930
931	if (name == NULL)
932		return (NULL);
933	STAILQ_FOREACH(sc, &syscalls, entries)
934		if (strcmp(name, sc->name) == 0)
935			return (sc);
936
937	/* It is unknown.  Add it into the list. */
938#if DEBUG
939	fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
940	    nargs);
941#endif
942
943	sc = calloc(1, sizeof(struct syscall));
944	sc->name = strdup(name);
945	sc->ret_type = 1;
946	sc->nargs = nargs;
947	for (i = 0; i < nargs; i++) {
948		sc->args[i].offset = i;
949		/* Treat all unknown arguments as LongHex. */
950		sc->args[i].type = LongHex;
951	}
952	STAILQ_INSERT_HEAD(&syscalls, sc, entries);
953
954	return (sc);
955}
956
957/*
958 * Copy a fixed amount of bytes from the process.
959 */
960static int
961get_struct(pid_t pid, void *offset, void *buf, int len)
962{
963	struct ptrace_io_desc iorequest;
964
965	iorequest.piod_op = PIOD_READ_D;
966	iorequest.piod_offs = offset;
967	iorequest.piod_addr = buf;
968	iorequest.piod_len = len;
969	if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
970		return (-1);
971	return (0);
972}
973
974#define	MAXSIZE		4096
975
976/*
977 * Copy a string from the process.  Note that it is
978 * expected to be a C string, but if max is set, it will
979 * only get that much.
980 */
981static char *
982get_string(pid_t pid, void *addr, int max)
983{
984	struct ptrace_io_desc iorequest;
985	char *buf, *nbuf;
986	size_t offset, size, totalsize;
987
988	offset = 0;
989	if (max)
990		size = max + 1;
991	else {
992		/* Read up to the end of the current page. */
993		size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE);
994		if (size > MAXSIZE)
995			size = MAXSIZE;
996	}
997	totalsize = size;
998	buf = malloc(totalsize);
999	if (buf == NULL)
1000		return (NULL);
1001	for (;;) {
1002		iorequest.piod_op = PIOD_READ_D;
1003		iorequest.piod_offs = (char *)addr + offset;
1004		iorequest.piod_addr = buf + offset;
1005		iorequest.piod_len = size;
1006		if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
1007			free(buf);
1008			return (NULL);
1009		}
1010		if (memchr(buf + offset, '\0', size) != NULL)
1011			return (buf);
1012		offset += size;
1013		if (totalsize < MAXSIZE && max == 0) {
1014			size = MAXSIZE - totalsize;
1015			if (size > PAGE_SIZE)
1016				size = PAGE_SIZE;
1017			nbuf = realloc(buf, totalsize + size);
1018			if (nbuf == NULL) {
1019				buf[totalsize - 1] = '\0';
1020				return (buf);
1021			}
1022			buf = nbuf;
1023			totalsize += size;
1024		} else {
1025			buf[totalsize - 1] = '\0';
1026			return (buf);
1027		}
1028	}
1029}
1030
1031static char *
1032strsig2(int sig)
1033{
1034	static char tmp[sizeof(int) * 3 + 1];
1035	char *ret;
1036
1037	ret = strsig(sig);
1038	if (ret == NULL) {
1039		snprintf(tmp, sizeof(tmp), "%d", sig);
1040		ret = tmp;
1041	}
1042	return (ret);
1043}
1044
1045static void
1046print_kevent(FILE *fp, struct kevent *ke, int input)
1047{
1048
1049	switch (ke->filter) {
1050	case EVFILT_READ:
1051	case EVFILT_WRITE:
1052	case EVFILT_VNODE:
1053	case EVFILT_PROC:
1054	case EVFILT_TIMER:
1055	case EVFILT_PROCDESC:
1056		fprintf(fp, "%ju", (uintmax_t)ke->ident);
1057		break;
1058	case EVFILT_SIGNAL:
1059		fputs(strsig2(ke->ident), fp);
1060		break;
1061	default:
1062		fprintf(fp, "%p", (void *)ke->ident);
1063	}
1064	fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter),
1065	    xlookup_bits(kevent_flags, ke->flags));
1066	switch (ke->filter) {
1067	case EVFILT_READ:
1068	case EVFILT_WRITE:
1069		fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp);
1070		break;
1071	case EVFILT_VNODE:
1072		fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp);
1073		break;
1074	case EVFILT_PROC:
1075	case EVFILT_PROCDESC:
1076		fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp);
1077		break;
1078	case EVFILT_TIMER:
1079		fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp);
1080		break;
1081	case EVFILT_USER: {
1082		int ctrl, data;
1083
1084		ctrl = ke->fflags & NOTE_FFCTRLMASK;
1085		data = ke->fflags & NOTE_FFLAGSMASK;
1086		if (input) {
1087			fputs(xlookup(kevent_user_ffctrl, ctrl), fp);
1088			if (ke->fflags & NOTE_TRIGGER)
1089				fputs("|NOTE_TRIGGER", fp);
1090			if (data != 0)
1091				fprintf(fp, "|%#x", data);
1092		} else {
1093			fprintf(fp, "%#x", data);
1094		}
1095		break;
1096	}
1097	default:
1098		fprintf(fp, "%#x", ke->fflags);
1099	}
1100	fprintf(fp, ",%p,%p", (void *)ke->data, (void *)ke->udata);
1101}
1102
1103static void
1104print_utrace(FILE *fp, void *utrace_addr, size_t len)
1105{
1106	unsigned char *utrace_buffer;
1107
1108	fprintf(fp, "{ ");
1109	if (sysdecode_utrace(fp, utrace_addr, len)) {
1110		fprintf(fp, " }");
1111		return;
1112	}
1113
1114	utrace_buffer = utrace_addr;
1115	fprintf(fp, "%zu:", len);
1116	while (len--)
1117		fprintf(fp, " %02x", *utrace_buffer++);
1118	fprintf(fp, " }");
1119}
1120
1121/*
1122 * Converts a syscall argument into a string.  Said string is
1123 * allocated via malloc(), so needs to be free()'d.  sc is
1124 * a pointer to the syscall description (see above); args is
1125 * an array of all of the system call arguments.
1126 */
1127char *
1128print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
1129    struct trussinfo *trussinfo)
1130{
1131	FILE *fp;
1132	char *tmp;
1133	size_t tmplen;
1134	pid_t pid;
1135
1136	fp = open_memstream(&tmp, &tmplen);
1137	pid = trussinfo->curthread->proc->pid;
1138	switch (sc->type & ARG_MASK) {
1139	case Hex:
1140		fprintf(fp, "0x%x", (int)args[sc->offset]);
1141		break;
1142	case Octal:
1143		fprintf(fp, "0%o", (int)args[sc->offset]);
1144		break;
1145	case Int:
1146		fprintf(fp, "%d", (int)args[sc->offset]);
1147		break;
1148	case UInt:
1149		fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1150		break;
1151	case LongHex:
1152		fprintf(fp, "0x%lx", args[sc->offset]);
1153		break;
1154	case Long:
1155		fprintf(fp, "%ld", args[sc->offset]);
1156		break;
1157	case Name: {
1158		/* NULL-terminated string. */
1159		char *tmp2;
1160
1161		tmp2 = get_string(pid, (void*)args[sc->offset], 0);
1162		fprintf(fp, "\"%s\"", tmp2);
1163		free(tmp2);
1164		break;
1165	}
1166	case BinString: {
1167		/*
1168		 * Binary block of data that might have printable characters.
1169		 * XXX If type|OUT, assume that the length is the syscall's
1170		 * return value.  Otherwise, assume that the length of the block
1171		 * is in the next syscall argument.
1172		 */
1173		int max_string = trussinfo->strsize;
1174		char tmp2[max_string + 1], *tmp3;
1175		int len;
1176		int truncated = 0;
1177
1178		if (sc->type & OUT)
1179			len = retval[0];
1180		else
1181			len = args[sc->offset + 1];
1182
1183		/*
1184		 * Don't print more than max_string characters, to avoid word
1185		 * wrap.  If we have to truncate put some ... after the string.
1186		 */
1187		if (len > max_string) {
1188			len = max_string;
1189			truncated = 1;
1190		}
1191		if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
1192		    != -1) {
1193			tmp3 = malloc(len * 4 + 1);
1194			while (len) {
1195				if (strvisx(tmp3, tmp2, len,
1196				    VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1197					break;
1198				len--;
1199				truncated = 1;
1200			}
1201			fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1202			    "..." : "");
1203			free(tmp3);
1204		} else {
1205			fprintf(fp, "0x%lx", args[sc->offset]);
1206		}
1207		break;
1208	}
1209	case ExecArgs:
1210	case ExecEnv:
1211	case StringArray: {
1212		uintptr_t addr;
1213		union {
1214			char *strarray[0];
1215			char buf[PAGE_SIZE];
1216		} u;
1217		char *string;
1218		size_t len;
1219		u_int first, i;
1220
1221		/*
1222		 * Only parse argv[] and environment arrays from exec calls
1223		 * if requested.
1224		 */
1225		if (((sc->type & ARG_MASK) == ExecArgs &&
1226		    (trussinfo->flags & EXECVEARGS) == 0) ||
1227		    ((sc->type & ARG_MASK) == ExecEnv &&
1228		    (trussinfo->flags & EXECVEENVS) == 0)) {
1229			fprintf(fp, "0x%lx", args[sc->offset]);
1230			break;
1231		}
1232
1233		/*
1234		 * Read a page of pointers at a time.  Punt if the top-level
1235		 * pointer is not aligned.  Note that the first read is of
1236		 * a partial page.
1237		 */
1238		addr = args[sc->offset];
1239		if (addr % sizeof(char *) != 0) {
1240			fprintf(fp, "0x%lx", args[sc->offset]);
1241			break;
1242		}
1243
1244		len = PAGE_SIZE - (addr & PAGE_MASK);
1245		if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
1246			fprintf(fp, "0x%lx", args[sc->offset]);
1247			break;
1248		}
1249
1250		fputc('[', fp);
1251		first = 1;
1252		i = 0;
1253		while (u.strarray[i] != NULL) {
1254			string = get_string(pid, u.strarray[i], 0);
1255			fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1256			free(string);
1257			first = 0;
1258
1259			i++;
1260			if (i == len / sizeof(char *)) {
1261				addr += len;
1262				len = PAGE_SIZE;
1263				if (get_struct(pid, (void *)addr, u.buf, len) ==
1264				    -1) {
1265					fprintf(fp, ", <inval>");
1266					break;
1267				}
1268				i = 0;
1269			}
1270		}
1271		fputs(" ]", fp);
1272		break;
1273	}
1274#ifdef __LP64__
1275	case Quad:
1276		fprintf(fp, "%ld", args[sc->offset]);
1277		break;
1278	case QuadHex:
1279		fprintf(fp, "0x%lx", args[sc->offset]);
1280		break;
1281#else
1282	case Quad:
1283	case QuadHex: {
1284		unsigned long long ll;
1285
1286#if _BYTE_ORDER == _LITTLE_ENDIAN
1287		ll = (unsigned long long)args[sc->offset + 1] << 32 |
1288		    args[sc->offset];
1289#else
1290		ll = (unsigned long long)args[sc->offset] << 32 |
1291		    args[sc->offset + 1];
1292#endif
1293		if ((sc->type & ARG_MASK) == Quad)
1294			fprintf(fp, "%lld", ll);
1295		else
1296			fprintf(fp, "0x%llx", ll);
1297		break;
1298	}
1299#endif
1300	case Ptr:
1301		fprintf(fp, "0x%lx", args[sc->offset]);
1302		break;
1303	case Readlinkres: {
1304		char *tmp2;
1305
1306		if (retval[0] == -1)
1307			break;
1308		tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
1309		fprintf(fp, "\"%s\"", tmp2);
1310		free(tmp2);
1311		break;
1312	}
1313	case Ioctl: {
1314		const char *temp;
1315		unsigned long cmd;
1316
1317		cmd = args[sc->offset];
1318		temp = sysdecode_ioctlname(cmd);
1319		if (temp)
1320			fputs(temp, fp);
1321		else {
1322			fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1323			    cmd, cmd & IOC_OUT ? "R" : "",
1324			    cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1325			    isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1326			    cmd & 0xFF, IOCPARM_LEN(cmd));
1327		}
1328		break;
1329	}
1330	case Timespec: {
1331		struct timespec ts;
1332
1333		if (get_struct(pid, (void *)args[sc->offset], &ts,
1334		    sizeof(ts)) != -1)
1335			fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1336			    ts.tv_nsec);
1337		else
1338			fprintf(fp, "0x%lx", args[sc->offset]);
1339		break;
1340	}
1341	case Timespec2: {
1342		struct timespec ts[2];
1343		const char *sep;
1344		unsigned int i;
1345
1346		if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
1347		    != -1) {
1348			fputs("{ ", fp);
1349			sep = "";
1350			for (i = 0; i < nitems(ts); i++) {
1351				fputs(sep, fp);
1352				sep = ", ";
1353				switch (ts[i].tv_nsec) {
1354				case UTIME_NOW:
1355					fprintf(fp, "UTIME_NOW");
1356					break;
1357				case UTIME_OMIT:
1358					fprintf(fp, "UTIME_OMIT");
1359					break;
1360				default:
1361					fprintf(fp, "%jd.%09ld",
1362					    (intmax_t)ts[i].tv_sec,
1363					    ts[i].tv_nsec);
1364					break;
1365				}
1366			}
1367			fputs(" }", fp);
1368		} else
1369			fprintf(fp, "0x%lx", args[sc->offset]);
1370		break;
1371	}
1372	case Timeval: {
1373		struct timeval tv;
1374
1375		if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1376		    != -1)
1377			fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1378			    tv.tv_usec);
1379		else
1380			fprintf(fp, "0x%lx", args[sc->offset]);
1381		break;
1382	}
1383	case Timeval2: {
1384		struct timeval tv[2];
1385
1386		if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1387		    != -1)
1388			fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1389			    (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1390			    (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1391		else
1392			fprintf(fp, "0x%lx", args[sc->offset]);
1393		break;
1394	}
1395	case Itimerval: {
1396		struct itimerval itv;
1397
1398		if (get_struct(pid, (void *)args[sc->offset], &itv,
1399		    sizeof(itv)) != -1)
1400			fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1401			    (intmax_t)itv.it_interval.tv_sec,
1402			    itv.it_interval.tv_usec,
1403			    (intmax_t)itv.it_value.tv_sec,
1404			    itv.it_value.tv_usec);
1405		else
1406			fprintf(fp, "0x%lx", args[sc->offset]);
1407		break;
1408	}
1409	case LinuxSockArgs:
1410	{
1411		struct linux_socketcall_args largs;
1412
1413		if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
1414		    sizeof(largs)) != -1)
1415			fprintf(fp, "{ %s, 0x%lx }",
1416			    lookup(linux_socketcall_ops, largs.what, 10),
1417			    (long unsigned int)largs.args);
1418		else
1419			fprintf(fp, "0x%lx", args[sc->offset]);
1420		break;
1421	}
1422	case Pollfd: {
1423		/*
1424		 * XXX: A Pollfd argument expects the /next/ syscall argument
1425		 * to be the number of fds in the array. This matches the poll
1426		 * syscall.
1427		 */
1428		struct pollfd *pfd;
1429		int numfds = args[sc->offset + 1];
1430		size_t bytes = sizeof(struct pollfd) * numfds;
1431		int i;
1432
1433		if ((pfd = malloc(bytes)) == NULL)
1434			err(1, "Cannot malloc %zu bytes for pollfd array",
1435			    bytes);
1436		if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
1437		    != -1) {
1438			fputs("{", fp);
1439			for (i = 0; i < numfds; i++) {
1440				fprintf(fp, " %d/%s", pfd[i].fd,
1441				    xlookup_bits(poll_flags, pfd[i].events));
1442			}
1443			fputs(" }", fp);
1444		} else {
1445			fprintf(fp, "0x%lx", args[sc->offset]);
1446		}
1447		free(pfd);
1448		break;
1449	}
1450	case Fd_set: {
1451		/*
1452		 * XXX: A Fd_set argument expects the /first/ syscall argument
1453		 * to be the number of fds in the array.  This matches the
1454		 * select syscall.
1455		 */
1456		fd_set *fds;
1457		int numfds = args[0];
1458		size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1459		int i;
1460
1461		if ((fds = malloc(bytes)) == NULL)
1462			err(1, "Cannot malloc %zu bytes for fd_set array",
1463			    bytes);
1464		if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
1465		    != -1) {
1466			fputs("{", fp);
1467			for (i = 0; i < numfds; i++) {
1468				if (FD_ISSET(i, fds))
1469					fprintf(fp, " %d", i);
1470			}
1471			fputs(" }", fp);
1472		} else
1473			fprintf(fp, "0x%lx", args[sc->offset]);
1474		free(fds);
1475		break;
1476	}
1477	case Signal:
1478		fputs(strsig2(args[sc->offset]), fp);
1479		break;
1480	case Sigset: {
1481		long sig;
1482		sigset_t ss;
1483		int i, first;
1484
1485		sig = args[sc->offset];
1486		if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
1487		    sizeof(ss)) == -1) {
1488			fprintf(fp, "0x%lx", args[sc->offset]);
1489			break;
1490		}
1491		fputs("{ ", fp);
1492		first = 1;
1493		for (i = 1; i < sys_nsig; i++) {
1494			if (sigismember(&ss, i)) {
1495				fprintf(fp, "%s%s", !first ? "|" : "",
1496				    strsig(i));
1497				first = 0;
1498			}
1499		}
1500		if (!first)
1501			fputc(' ', fp);
1502		fputc('}', fp);
1503		break;
1504	}
1505	case Sigprocmask: {
1506		fputs(xlookup(sigprocmask_ops, args[sc->offset]), fp);
1507		break;
1508	}
1509	case Fcntlflag: {
1510		/* XXX: Output depends on the value of the previous argument. */
1511		switch (args[sc->offset - 1]) {
1512		case F_SETFD:
1513			fputs(xlookup_bits(fcntlfd_arg, args[sc->offset]), fp);
1514			break;
1515		case F_SETFL:
1516			fputs(xlookup_bits(fcntlfl_arg, args[sc->offset]), fp);
1517			break;
1518		case F_GETFD:
1519		case F_GETFL:
1520		case F_GETOWN:
1521			break;
1522		default:
1523			fprintf(fp, "0x%lx", args[sc->offset]);
1524			break;
1525		}
1526		break;
1527	}
1528	case Open:
1529		fputs(xlookup_bits(open_flags, args[sc->offset]), fp);
1530		break;
1531	case Fcntl:
1532		fputs(xlookup(fcntl_arg, args[sc->offset]), fp);
1533		break;
1534	case Mprot:
1535		fputs(xlookup_bits(mprot_flags, args[sc->offset]), fp);
1536		break;
1537	case Mmapflags: {
1538		int align, flags;
1539
1540		/*
1541		 * MAP_ALIGNED can't be handled by xlookup_bits(), so
1542		 * generate that string manually and prepend it to the
1543		 * string from xlookup_bits().  Have to be careful to
1544		 * avoid outputting MAP_ALIGNED|0 if MAP_ALIGNED is
1545		 * the only flag.
1546		 */
1547		flags = args[sc->offset] & ~MAP_ALIGNMENT_MASK;
1548		align = args[sc->offset] & MAP_ALIGNMENT_MASK;
1549		if (align != 0) {
1550			if (align == MAP_ALIGNED_SUPER)
1551				fputs("MAP_ALIGNED_SUPER", fp);
1552			else
1553				fprintf(fp, "MAP_ALIGNED(%d)",
1554				    align >> MAP_ALIGNMENT_SHIFT);
1555			if (flags == 0)
1556				break;
1557			fputc('|', fp);
1558		}
1559		fputs(xlookup_bits(mmap_flags, flags), fp);
1560		break;
1561	}
1562	case Whence:
1563		fputs(xlookup(whence_arg, args[sc->offset]), fp);
1564		break;
1565	case Sockdomain:
1566		fputs(xlookup(sockdomain_arg, args[sc->offset]), fp);
1567		break;
1568	case Socktype: {
1569		int type, flags;
1570
1571		flags = args[sc->offset] & (SOCK_CLOEXEC | SOCK_NONBLOCK);
1572		type = args[sc->offset] & ~flags;
1573		fputs(xlookup(socktype_arg, type), fp);
1574		if (flags & SOCK_CLOEXEC)
1575			fprintf(fp, "|SOCK_CLOEXEC");
1576		if (flags & SOCK_NONBLOCK)
1577			fprintf(fp, "|SOCK_NONBLOCK");
1578		break;
1579	}
1580	case Shutdown:
1581		fputs(xlookup(shutdown_arg, args[sc->offset]), fp);
1582		break;
1583	case Resource:
1584		fputs(xlookup(resource_arg, args[sc->offset]), fp);
1585		break;
1586	case Pathconf:
1587		fputs(xlookup(pathconf_arg, args[sc->offset]), fp);
1588		break;
1589	case Rforkflags:
1590		fputs(xlookup_bits(rfork_flags, args[sc->offset]), fp);
1591		break;
1592	case Sockaddr: {
1593		char addr[64];
1594		struct sockaddr_in *lsin;
1595		struct sockaddr_in6 *lsin6;
1596		struct sockaddr_un *sun;
1597		struct sockaddr *sa;
1598		socklen_t len;
1599		u_char *q;
1600
1601		if (args[sc->offset] == 0) {
1602			fputs("NULL", fp);
1603			break;
1604		}
1605
1606		/*
1607		 * Extract the address length from the next argument.  If
1608		 * this is an output sockaddr (OUT is set), then the
1609		 * next argument is a pointer to a socklen_t.  Otherwise
1610		 * the next argument contains a socklen_t by value.
1611		 */
1612		if (sc->type & OUT) {
1613			if (get_struct(pid, (void *)args[sc->offset + 1],
1614			    &len, sizeof(len)) == -1) {
1615				fprintf(fp, "0x%lx", args[sc->offset]);
1616				break;
1617			}
1618		} else
1619			len = args[sc->offset + 1];
1620
1621		/* If the length is too small, just bail. */
1622		if (len < sizeof(*sa)) {
1623			fprintf(fp, "0x%lx", args[sc->offset]);
1624			break;
1625		}
1626
1627		sa = calloc(1, len);
1628		if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) {
1629			free(sa);
1630			fprintf(fp, "0x%lx", args[sc->offset]);
1631			break;
1632		}
1633
1634		switch (sa->sa_family) {
1635		case AF_INET:
1636			if (len < sizeof(*lsin))
1637				goto sockaddr_short;
1638			lsin = (struct sockaddr_in *)(void *)sa;
1639			inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1640			fprintf(fp, "{ AF_INET %s:%d }", addr,
1641			    htons(lsin->sin_port));
1642			break;
1643		case AF_INET6:
1644			if (len < sizeof(*lsin6))
1645				goto sockaddr_short;
1646			lsin6 = (struct sockaddr_in6 *)(void *)sa;
1647			inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1648			    sizeof(addr));
1649			fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1650			    htons(lsin6->sin6_port));
1651			break;
1652		case AF_UNIX:
1653			sun = (struct sockaddr_un *)sa;
1654			fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1655			    (int)(len - offsetof(struct sockaddr_un, sun_path)),
1656			    sun->sun_path);
1657			break;
1658		default:
1659		sockaddr_short:
1660			fprintf(fp,
1661			    "{ sa_len = %d, sa_family = %d, sa_data = {",
1662			    (int)sa->sa_len, (int)sa->sa_family);
1663			for (q = (u_char *)sa->sa_data;
1664			     q < (u_char *)sa + len; q++)
1665				fprintf(fp, "%s 0x%02x",
1666				    q == (u_char *)sa->sa_data ? "" : ",",
1667				    *q);
1668			fputs(" } }", fp);
1669		}
1670		free(sa);
1671		break;
1672	}
1673	case Sigaction: {
1674		struct sigaction sa;
1675
1676		if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
1677		    != -1) {
1678			fputs("{ ", fp);
1679			if (sa.sa_handler == SIG_DFL)
1680				fputs("SIG_DFL", fp);
1681			else if (sa.sa_handler == SIG_IGN)
1682				fputs("SIG_IGN", fp);
1683			else
1684				fprintf(fp, "%p", sa.sa_handler);
1685			fprintf(fp, " %s ss_t }",
1686			    xlookup_bits(sigaction_flags, sa.sa_flags));
1687		} else
1688			fprintf(fp, "0x%lx", args[sc->offset]);
1689		break;
1690	}
1691	case Kevent: {
1692		/*
1693		 * XXX XXX: The size of the array is determined by either the
1694		 * next syscall argument, or by the syscall return value,
1695		 * depending on which argument number we are.  This matches the
1696		 * kevent syscall, but luckily that's the only syscall that uses
1697		 * them.
1698		 */
1699		struct kevent *ke;
1700		int numevents = -1;
1701		size_t bytes;
1702		int i;
1703
1704		if (sc->offset == 1)
1705			numevents = args[sc->offset+1];
1706		else if (sc->offset == 3 && retval[0] != -1)
1707			numevents = retval[0];
1708
1709		if (numevents >= 0) {
1710			bytes = sizeof(struct kevent) * numevents;
1711			if ((ke = malloc(bytes)) == NULL)
1712				err(1,
1713				    "Cannot malloc %zu bytes for kevent array",
1714				    bytes);
1715		} else
1716			ke = NULL;
1717		if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
1718		    ke, bytes) != -1) {
1719			fputc('{', fp);
1720			for (i = 0; i < numevents; i++) {
1721				fputc(' ', fp);
1722				print_kevent(fp, &ke[i], sc->offset == 1);
1723			}
1724			fputs(" }", fp);
1725		} else {
1726			fprintf(fp, "0x%lx", args[sc->offset]);
1727		}
1728		free(ke);
1729		break;
1730	}
1731	case Stat: {
1732		struct stat st;
1733
1734		if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1735		    != -1) {
1736			char mode[12];
1737
1738			strmode(st.st_mode, mode);
1739			fprintf(fp,
1740			    "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1741			    (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1742			    (long)st.st_blksize);
1743		} else {
1744			fprintf(fp, "0x%lx", args[sc->offset]);
1745		}
1746		break;
1747	}
1748	case StatFs: {
1749		unsigned int i;
1750		struct statfs buf;
1751
1752		if (get_struct(pid, (void *)args[sc->offset], &buf,
1753		    sizeof(buf)) != -1) {
1754			char fsid[17];
1755
1756			bzero(fsid, sizeof(fsid));
1757			if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
1758			        for (i = 0; i < sizeof(buf.f_fsid); i++)
1759					snprintf(&fsid[i*2],
1760					    sizeof(fsid) - (i*2), "%02x",
1761					    ((u_char *)&buf.f_fsid)[i]);
1762			}
1763			fprintf(fp,
1764			    "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
1765			    "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
1766			    buf.f_mntfromname, fsid);
1767		} else
1768			fprintf(fp, "0x%lx", args[sc->offset]);
1769		break;
1770	}
1771
1772	case Rusage: {
1773		struct rusage ru;
1774
1775		if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
1776		    != -1) {
1777			fprintf(fp,
1778			    "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
1779			    (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
1780			    (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
1781			    ru.ru_inblock, ru.ru_oublock);
1782		} else
1783			fprintf(fp, "0x%lx", args[sc->offset]);
1784		break;
1785	}
1786	case Rlimit: {
1787		struct rlimit rl;
1788
1789		if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
1790		    != -1) {
1791			fprintf(fp, "{ cur=%ju,max=%ju }",
1792			    rl.rlim_cur, rl.rlim_max);
1793		} else
1794			fprintf(fp, "0x%lx", args[sc->offset]);
1795		break;
1796	}
1797	case ExitStatus: {
1798		int status;
1799
1800		if (get_struct(pid, (void *)args[sc->offset], &status,
1801		    sizeof(status)) != -1) {
1802			fputs("{ ", fp);
1803			if (WIFCONTINUED(status))
1804				fputs("CONTINUED", fp);
1805			else if (WIFEXITED(status))
1806				fprintf(fp, "EXITED,val=%d",
1807				    WEXITSTATUS(status));
1808			else if (WIFSIGNALED(status))
1809				fprintf(fp, "SIGNALED,sig=%s%s",
1810				    strsig2(WTERMSIG(status)),
1811				    WCOREDUMP(status) ? ",cored" : "");
1812			else
1813				fprintf(fp, "STOPPED,sig=%s",
1814				    strsig2(WTERMSIG(status)));
1815			fputs(" }", fp);
1816		} else
1817			fprintf(fp, "0x%lx", args[sc->offset]);
1818		break;
1819	}
1820	case Waitoptions:
1821		fputs(xlookup_bits(wait_options, args[sc->offset]), fp);
1822		break;
1823	case Idtype:
1824		fputs(xlookup(idtype_arg, args[sc->offset]), fp);
1825		break;
1826	case Procctl:
1827		fputs(xlookup(procctl_arg, args[sc->offset]), fp);
1828		break;
1829	case Umtxop:
1830		fputs(xlookup(umtx_ops, args[sc->offset]), fp);
1831		break;
1832	case Atfd:
1833		if ((int)args[sc->offset] == AT_FDCWD)
1834			fputs("AT_FDCWD", fp);
1835		else
1836			fprintf(fp, "%d", (int)args[sc->offset]);
1837		break;
1838	case Atflags:
1839		fputs(xlookup_bits(at_flags, args[sc->offset]), fp);
1840		break;
1841	case Accessmode:
1842		if (args[sc->offset] == F_OK)
1843			fputs("F_OK", fp);
1844		else
1845			fputs(xlookup_bits(access_modes, args[sc->offset]), fp);
1846		break;
1847	case Sysarch:
1848		fputs(xlookup(sysarch_ops, args[sc->offset]), fp);
1849		break;
1850	case PipeFds:
1851		/*
1852		 * The pipe() system call in the kernel returns its
1853		 * two file descriptors via return values.  However,
1854		 * the interface exposed by libc is that pipe()
1855		 * accepts a pointer to an array of descriptors.
1856		 * Format the output to match the libc API by printing
1857		 * the returned file descriptors as a fake argument.
1858		 *
1859		 * Overwrite the first retval to signal a successful
1860		 * return as well.
1861		 */
1862		fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
1863		retval[0] = 0;
1864		break;
1865	case Utrace: {
1866		size_t len;
1867		void *utrace_addr;
1868
1869		len = args[sc->offset + 1];
1870		utrace_addr = calloc(1, len);
1871		if (get_struct(pid, (void *)args[sc->offset],
1872		    (void *)utrace_addr, len) != -1)
1873			print_utrace(fp, utrace_addr, len);
1874		else
1875			fprintf(fp, "0x%lx", args[sc->offset]);
1876		free(utrace_addr);
1877		break;
1878	}
1879	case IntArray: {
1880		int descriptors[16];
1881		unsigned long i, ndescriptors;
1882		bool truncated;
1883
1884		ndescriptors = args[sc->offset + 1];
1885		truncated = false;
1886		if (ndescriptors > nitems(descriptors)) {
1887			ndescriptors = nitems(descriptors);
1888			truncated = true;
1889		}
1890		if (get_struct(pid, (void *)args[sc->offset],
1891		    descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
1892			fprintf(fp, "{");
1893			for (i = 0; i < ndescriptors; i++)
1894				fprintf(fp, i == 0 ? " %d" : ", %d",
1895				    descriptors[i]);
1896			fprintf(fp, truncated ? ", ... }" : " }");
1897		} else
1898			fprintf(fp, "0x%lx", args[sc->offset]);
1899		break;
1900	}
1901
1902	case CloudABIAdvice:
1903		fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
1904		break;
1905	case CloudABIClockID:
1906		fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
1907		break;
1908	case ClouduABIFDSFlags:
1909		fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
1910		break;
1911	case CloudABIFDStat: {
1912		cloudabi_fdstat_t fds;
1913		if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds))
1914		    != -1) {
1915			fprintf(fp, "{ %s, ",
1916			    xlookup(cloudabi_filetype, fds.fs_filetype));
1917			fprintf(fp, "%s, ... }",
1918			    xlookup_bits(cloudabi_fdflags, fds.fs_flags));
1919		} else
1920			fprintf(fp, "0x%lx", args[sc->offset]);
1921		break;
1922	}
1923	case CloudABIFileStat: {
1924		cloudabi_filestat_t fsb;
1925		if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb))
1926		    != -1)
1927			fprintf(fp, "{ %s, %lu }",
1928			    xlookup(cloudabi_filetype, fsb.st_filetype),
1929			    fsb.st_size);
1930		else
1931			fprintf(fp, "0x%lx", args[sc->offset]);
1932		break;
1933	}
1934	case CloudABIFileType:
1935		fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
1936		break;
1937	case CloudABIFSFlags:
1938		fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
1939		break;
1940	case CloudABILookup:
1941		if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
1942			fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
1943			    (int)args[sc->offset]);
1944		else
1945			fprintf(fp, "%d", (int)args[sc->offset]);
1946		break;
1947	case CloudABIMFlags:
1948		fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
1949		break;
1950	case CloudABIMProt:
1951		fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
1952		break;
1953	case CloudABIMSFlags:
1954		fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
1955		break;
1956	case CloudABIOFlags:
1957		fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
1958		break;
1959	case CloudABISDFlags:
1960		fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
1961		break;
1962	case CloudABISignal:
1963		fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
1964		break;
1965	case CloudABISockStat: {
1966		cloudabi_sockstat_t ss;
1967		if (get_struct(pid, (void *)args[sc->offset], &ss, sizeof(ss))
1968		    != -1) {
1969			fprintf(fp, "{ %s, ", xlookup(
1970			    cloudabi_sa_family, ss.ss_sockname.sa_family));
1971			fprintf(fp, "%s, ", xlookup(
1972			    cloudabi_sa_family, ss.ss_peername.sa_family));
1973			fprintf(fp, "%s, ", xlookup(
1974			    cloudabi_errno, ss.ss_error));
1975			fprintf(fp, "%s }", xlookup_bits(
1976			    cloudabi_ssstate, ss.ss_state));
1977		} else
1978			fprintf(fp, "0x%lx", args[sc->offset]);
1979		break;
1980	}
1981	case CloudABISSFlags:
1982		fputs(xlookup_bits(cloudabi_ssflags, args[sc->offset]), fp);
1983		break;
1984	case CloudABITimestamp:
1985		fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
1986		    args[sc->offset] % 1000000000);
1987		break;
1988	case CloudABIULFlags:
1989		fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
1990		break;
1991	case CloudABIWhence:
1992		fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
1993		break;
1994
1995	default:
1996		errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
1997	}
1998	fclose(fp);
1999	return (tmp);
2000}
2001
2002/*
2003 * Print (to outfile) the system call and its arguments.
2004 */
2005void
2006print_syscall(struct trussinfo *trussinfo)
2007{
2008	struct threadinfo *t;
2009	const char *name;
2010	char **s_args;
2011	int i, len, nargs;
2012
2013	t = trussinfo->curthread;
2014
2015	name = t->cs.name;
2016	nargs = t->cs.nargs;
2017	s_args = t->cs.s_args;
2018
2019	len = print_line_prefix(trussinfo);
2020	len += fprintf(trussinfo->outfile, "%s(", name);
2021
2022	for (i = 0; i < nargs; i++) {
2023		if (s_args[i] != NULL)
2024			len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2025		else
2026			len += fprintf(trussinfo->outfile,
2027			    "<missing argument>");
2028		len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2029		    "," : "");
2030	}
2031	len += fprintf(trussinfo->outfile, ")");
2032	for (i = 0; i < 6 - (len / 8); i++)
2033		fprintf(trussinfo->outfile, "\t");
2034}
2035
2036void
2037print_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
2038{
2039	struct timespec timediff;
2040	struct threadinfo *t;
2041	struct syscall *sc;
2042	int error;
2043
2044	t = trussinfo->curthread;
2045	sc = t->cs.sc;
2046	if (trussinfo->flags & COUNTONLY) {
2047		timespecsubt(&t->after, &t->before, &timediff);
2048		timespecadd(&sc->time, &timediff, &sc->time);
2049		sc->ncalls++;
2050		if (errorp)
2051			sc->nerror++;
2052		return;
2053	}
2054
2055	print_syscall(trussinfo);
2056	fflush(trussinfo->outfile);
2057
2058	if (retval == NULL) {
2059		/*
2060		 * This system call resulted in the current thread's exit,
2061		 * so there is no return value or error to display.
2062		 */
2063		fprintf(trussinfo->outfile, "\n");
2064		return;
2065	}
2066
2067	if (errorp) {
2068		error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi,
2069		    retval[0]);
2070		fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
2071		    error == INT_MAX ? "Unknown error" : strerror(error));
2072	}
2073#ifndef __LP64__
2074	else if (sc->ret_type == 2) {
2075		off_t off;
2076
2077#if _BYTE_ORDER == _LITTLE_ENDIAN
2078		off = (off_t)retval[1] << 32 | retval[0];
2079#else
2080		off = (off_t)retval[0] << 32 | retval[1];
2081#endif
2082		fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2083		    (intmax_t)off);
2084	}
2085#endif
2086	else
2087		fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
2088		    retval[0]);
2089}
2090
2091void
2092print_summary(struct trussinfo *trussinfo)
2093{
2094	struct timespec total = {0, 0};
2095	struct syscall *sc;
2096	int ncall, nerror;
2097
2098	fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2099	    "syscall", "seconds", "calls", "errors");
2100	ncall = nerror = 0;
2101	STAILQ_FOREACH(sc, &syscalls, entries)
2102		if (sc->ncalls) {
2103			fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2104			    sc->name, (intmax_t)sc->time.tv_sec,
2105			    sc->time.tv_nsec, sc->ncalls, sc->nerror);
2106			timespecadd(&total, &sc->time, &total);
2107			ncall += sc->ncalls;
2108			nerror += sc->nerror;
2109		}
2110	fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2111	    "", "-------------", "-------", "-------");
2112	fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2113	    "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);
2114}
2115