131567Ssef/*
2204977Simp * Copyright 1997 Sean Eric Fagan
331899Ssef *
431899Ssef * Redistribution and use in source and binary forms, with or without
531899Ssef * modification, are permitted provided that the following conditions
631899Ssef * are met:
731899Ssef * 1. Redistributions of source code must retain the above copyright
831899Ssef *    notice, this list of conditions and the following disclaimer.
931899Ssef * 2. Redistributions in binary form must reproduce the above copyright
1031899Ssef *    notice, this list of conditions and the following disclaimer in the
1131899Ssef *    documentation and/or other materials provided with the distribution.
1231899Ssef * 3. All advertising materials mentioning features or use of this software
1331899Ssef *    must display the following acknowledgement:
1431899Ssef *	This product includes software developed by Sean Eric Fagan
1531899Ssef * 4. Neither the name of the author may be used to endorse or promote
1631899Ssef *    products derived from this software without specific prior written
1731899Ssef *    permission.
1831899Ssef *
1931899Ssef * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2031899Ssef * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2131899Ssef * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2231899Ssef * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2331899Ssef * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2431899Ssef * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2531899Ssef * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2631899Ssef * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2731899Ssef * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2831899Ssef * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2931899Ssef * SUCH DAMAGE.
3031899Ssef */
3131899Ssef
32288424Sjhb#include <sys/cdefs.h>
33288424Sjhb__FBSDID("$FreeBSD: releng/11.0/usr.bin/truss/syscalls.c 304477 2016-08-19 17:48:47Z bdrewery $");
3432275Scharnier
3531899Ssef/*
3631567Ssef * This file has routines used to print out system calls and their
3731567Ssef * arguments.
3831567Ssef */
3931567Ssef
40255493Sjhb#include <sys/types.h>
41288424Sjhb#include <sys/event.h>
42288424Sjhb#include <sys/ioccom.h>
43127328Salfred#include <sys/mman.h>
44288625Sbdrewery#include <sys/mount.h>
45255708Sjhb#include <sys/procctl.h>
46168569Sdelphij#include <sys/ptrace.h>
47288424Sjhb#include <sys/resource.h>
4885292Sdes#include <sys/socket.h>
49288424Sjhb#include <sys/stat.h>
50288424Sjhb#include <sys/umtx.h>
5185292Sdes#include <sys/un.h>
52255493Sjhb#include <sys/wait.h>
53288424Sjhb#include <machine/sysarch.h>
5485292Sdes#include <netinet/in.h>
5585292Sdes#include <arpa/inet.h>
5685292Sdes
5786138Sgreen#include <ctype.h>
5832275Scharnier#include <err.h>
59127328Salfred#include <fcntl.h>
60127332Sdwmalone#include <poll.h>
6185292Sdes#include <signal.h>
62289004Sed#include <stdbool.h>
63288456Sjhb#include <stddef.h>
64127332Sdwmalone#include <stdint.h>
6531567Ssef#include <stdio.h>
6631567Ssef#include <stdlib.h>
6731567Ssef#include <string.h>
68292236Sjhb#include <sysdecode.h>
69101423Smdodd#include <time.h>
7031567Ssef#include <unistd.h>
71158630Spav#include <vis.h>
7285292Sdes
73297247Sed#include <contrib/cloudabi/cloudabi_types_common.h>
74289004Sed
75101282Smdodd#include "truss.h"
7687703Smarkm#include "extern.h"
7731567Ssef#include "syscall.h"
7831567Ssef
79171646Smarcel/* 64-bit alignment on 32-bit platforms. */
80288454Sjhb#if !defined(__LP64__) && defined(__powerpc__)
81171646Smarcel#define	QUAD_ALIGN	1
82171646Smarcel#else
83171646Smarcel#define	QUAD_ALIGN	0
84171646Smarcel#endif
85171646Smarcel
86171646Smarcel/* Number of slots needed for a 64-bit argument. */
87171646Smarcel#ifdef __LP64__
88171646Smarcel#define	QUAD_SLOTS	1
89171646Smarcel#else
90171646Smarcel#define	QUAD_SLOTS	2
91171646Smarcel#endif
92171646Smarcel
9331567Ssef/*
94158630Spav * This should probably be in its own file, sorted alphabetically.
9531567Ssef */
96288832Sbdrewerystatic struct syscall decoded_syscalls[] = {
97288950Sjhb	/* Native ABI */
98288950Sjhb	{ .name = "__getcwd", .ret_type = 1, .nargs = 2,
99288950Sjhb	  .args = { { Name | OUT, 0 }, { Int, 1 } } },
100288950Sjhb	{ .name = "_umtx_op", .ret_type = 1, .nargs = 5,
101288950Sjhb	  .args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
102288950Sjhb		    { Ptr, 4 } } },
103288950Sjhb	{ .name = "accept", .ret_type = 1, .nargs = 3,
104288950Sjhb	  .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
105288950Sjhb	{ .name = "access", .ret_type = 1, .nargs = 2,
106288950Sjhb	  .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
107288950Sjhb	{ .name = "bind", .ret_type = 1, .nargs = 3,
108288950Sjhb	  .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
109288950Sjhb	{ .name = "bindat", .ret_type = 1, .nargs = 4,
110288950Sjhb	  .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
111286381Sjhb		    { Int, 3 } } },
112288950Sjhb	{ .name = "break", .ret_type = 1, .nargs = 1,
113288950Sjhb	  .args = { { Ptr, 0 } } },
114288424Sjhb	{ .name = "chdir", .ret_type = 1, .nargs = 1,
115192025Sdds	  .args = { { Name, 0 } } },
116288950Sjhb	{ .name = "chflags", .ret_type = 1, .nargs = 2,
117288950Sjhb	  .args = { { Name | IN, 0 }, { Hex, 1 } } },
118288950Sjhb	{ .name = "chmod", .ret_type = 1, .nargs = 2,
119288950Sjhb	  .args = { { Name, 0 }, { Octal, 1 } } },
120288950Sjhb	{ .name = "chown", .ret_type = 1, .nargs = 3,
121288950Sjhb	  .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
122288424Sjhb	{ .name = "chroot", .ret_type = 1, .nargs = 1,
123192025Sdds	  .args = { { Name, 0 } } },
124288950Sjhb	{ .name = "clock_gettime", .ret_type = 1, .nargs = 2,
125288950Sjhb	  .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
126288950Sjhb	{ .name = "close", .ret_type = 1, .nargs = 1,
127288950Sjhb	  .args = { { Int, 0 } } },
128288950Sjhb	{ .name = "connect", .ret_type = 1, .nargs = 3,
129288950Sjhb	  .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
130288950Sjhb	{ .name = "connectat", .ret_type = 1, .nargs = 4,
131288950Sjhb	  .args = { { Atfd, 0 }, { Int, 1 }, { Sockaddr | IN, 2 },
132288950Sjhb		    { Int, 3 } } },
133288950Sjhb	{ .name = "eaccess", .ret_type = 1, .nargs = 2,
134288950Sjhb	  .args = { { Name | IN, 0 }, { Accessmode, 1 } } },
135288950Sjhb	{ .name = "execve", .ret_type = 1, .nargs = 3,
136288950Sjhb	  .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
137288950Sjhb		    { ExecEnv | IN, 2 } } },
138288950Sjhb	{ .name = "exit", .ret_type = 0, .nargs = 1,
139288950Sjhb	  .args = { { Hex, 0 } } },
140288950Sjhb	{ .name = "faccessat", .ret_type = 1, .nargs = 4,
141288950Sjhb	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Accessmode, 2 },
142288950Sjhb		    { Atflags, 3 } } },
143288424Sjhb	{ .name = "fchmod", .ret_type = 1, .nargs = 2,
144286381Sjhb	  .args = { { Int, 0 }, { Octal, 1 } } },
145288424Sjhb	{ .name = "fchmodat", .ret_type = 1, .nargs = 4,
146286381Sjhb	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
147288424Sjhb	{ .name = "fchown", .ret_type = 1, .nargs = 3,
148286381Sjhb	  .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
149288424Sjhb	{ .name = "fchownat", .ret_type = 1, .nargs = 5,
150286381Sjhb	  .args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
151286381Sjhb		    { Atflags, 4 } } },
152288950Sjhb	{ .name = "fcntl", .ret_type = 1, .nargs = 3,
153288950Sjhb	  .args = { { Int, 0 }, { Fcntl, 1 }, { Fcntlflag, 2 } } },
154192025Sdds	{ .name = "fstat", .ret_type = 1, .nargs = 2,
155286330Sjhb	  .args = { { Int, 0 }, { Stat | OUT, 1 } } },
156286381Sjhb	{ .name = "fstatat", .ret_type = 1, .nargs = 4,
157286381Sjhb	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Stat | OUT, 2 },
158286381Sjhb		    { Atflags, 3 } } },
159288625Sbdrewery	{ .name = "fstatfs", .ret_type = 1, .nargs = 2,
160288625Sbdrewery	  .args = { { Int, 0 }, { StatFs | OUT, 1 } } },
161288950Sjhb	{ .name = "ftruncate", .ret_type = 1, .nargs = 2,
162288950Sjhb	  .args = { { Int | IN, 0 }, { QuadHex | IN, 1 + QUAD_ALIGN } } },
163288950Sjhb	{ .name = "futimens", .ret_type = 1, .nargs = 2,
164288950Sjhb	  .args = { { Int, 0 }, { Timespec2 | IN, 1 } } },
165288950Sjhb	{ .name = "futimes", .ret_type = 1, .nargs = 2,
166288950Sjhb	  .args = { { Int, 0 }, { Timeval2 | IN, 1 } } },
167288950Sjhb	{ .name = "futimesat", .ret_type = 1, .nargs = 3,
168288950Sjhb	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timeval2 | IN, 2 } } },
169288950Sjhb	{ .name = "getitimer", .ret_type = 1, .nargs = 2,
170288950Sjhb	  .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
171192025Sdds	{ .name = "getpeername", .ret_type = 1, .nargs = 3,
172192025Sdds	  .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
173288950Sjhb	{ .name = "getpgid", .ret_type = 1, .nargs = 1,
174288950Sjhb	  .args = { { Int, 0 } } },
175288950Sjhb	{ .name = "getrlimit", .ret_type = 1, .nargs = 2,
176288950Sjhb	  .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
177288950Sjhb	{ .name = "getrusage", .ret_type = 1, .nargs = 2,
178288950Sjhb	  .args = { { Int, 0 }, { Rusage | OUT, 1 } } },
179288950Sjhb	{ .name = "getsid", .ret_type = 1, .nargs = 1,
180288950Sjhb	  .args = { { Int, 0 } } },
181192025Sdds	{ .name = "getsockname", .ret_type = 1, .nargs = 3,
182192025Sdds	  .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
183288950Sjhb	{ .name = "gettimeofday", .ret_type = 1, .nargs = 2,
184288950Sjhb	  .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
185288950Sjhb	{ .name = "ioctl", .ret_type = 1, .nargs = 3,
186288950Sjhb	  .args = { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 } } },
187288950Sjhb	{ .name = "kevent", .ret_type = 1, .nargs = 6,
188288950Sjhb	  .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
189288950Sjhb		    { Int, 4 }, { Timespec, 5 } } },
190288950Sjhb	{ .name = "kill", .ret_type = 1, .nargs = 2,
191288950Sjhb	  .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
192288950Sjhb	{ .name = "kldfind", .ret_type = 1, .nargs = 1,
193192025Sdds	  .args = { { Name | IN, 0 } } },
194288950Sjhb	{ .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
195192025Sdds	  .args = { { Int, 0 } } },
196288950Sjhb	{ .name = "kldload", .ret_type = 1, .nargs = 1,
197192025Sdds	  .args = { { Name | IN, 0 } } },
198288424Sjhb	{ .name = "kldnext", .ret_type = 1, .nargs = 1,
199192025Sdds	  .args = { { Int, 0 } } },
200288424Sjhb	{ .name = "kldstat", .ret_type = 1, .nargs = 2,
201192025Sdds	  .args = { { Int, 0 }, { Ptr, 1 } } },
202288950Sjhb	{ .name = "kldunload", .ret_type = 1, .nargs = 1,
203192025Sdds	  .args = { { Int, 0 } } },
204288950Sjhb	{ .name = "kse_release", .ret_type = 0, .nargs = 1,
205288950Sjhb	  .args = { { Timespec, 0 } } },
206288950Sjhb	{ .name = "lchflags", .ret_type = 1, .nargs = 2,
207288950Sjhb	  .args = { { Name | IN, 0 }, { Hex, 1 } } },
208288950Sjhb	{ .name = "lchmod", .ret_type = 1, .nargs = 2,
209288950Sjhb	  .args = { { Name, 0 }, { Octal, 1 } } },
210288950Sjhb	{ .name = "lchown", .ret_type = 1, .nargs = 3,
211288950Sjhb	  .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
212288950Sjhb	{ .name = "link", .ret_type = 1, .nargs = 2,
213288950Sjhb	  .args = { { Name, 0 }, { Name, 1 } } },
214288950Sjhb	{ .name = "linkat", .ret_type = 1, .nargs = 5,
215288950Sjhb	  .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
216288950Sjhb		    { Atflags, 4 } } },
217288950Sjhb	{ .name = "lseek", .ret_type = 2, .nargs = 3,
218288950Sjhb	  .args = { { Int, 0 }, { QuadHex, 1 + QUAD_ALIGN },
219288950Sjhb		    { Whence, 1 + QUAD_SLOTS + QUAD_ALIGN } } },
220288950Sjhb	{ .name = "lstat", .ret_type = 1, .nargs = 2,
221288950Sjhb	  .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
222288950Sjhb	{ .name = "lutimes", .ret_type = 1, .nargs = 2,
223288950Sjhb	  .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
224288950Sjhb	{ .name = "mkdir", .ret_type = 1, .nargs = 2,
225288950Sjhb	  .args = { { Name, 0 }, { Octal, 1 } } },
226288950Sjhb	{ .name = "mkdirat", .ret_type = 1, .nargs = 3,
227288950Sjhb	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
228288950Sjhb	{ .name = "mkfifo", .ret_type = 1, .nargs = 2,
229288950Sjhb	  .args = { { Name, 0 }, { Octal, 1 } } },
230288950Sjhb	{ .name = "mkfifoat", .ret_type = 1, .nargs = 3,
231288950Sjhb	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
232288950Sjhb	{ .name = "mknod", .ret_type = 1, .nargs = 3,
233288950Sjhb	  .args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
234288950Sjhb	{ .name = "mknodat", .ret_type = 1, .nargs = 4,
235288950Sjhb	  .args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
236288950Sjhb	{ .name = "mmap", .ret_type = 1, .nargs = 6,
237288950Sjhb	  .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
238288950Sjhb		    { Int, 4 }, { QuadHex, 5 + QUAD_ALIGN } } },
239288834Sbdrewery	{ .name = "modfind", .ret_type = 1, .nargs = 1,
240288834Sbdrewery	  .args = { { Name | IN, 0 } } },
241288950Sjhb	{ .name = "mount", .ret_type = 1, .nargs = 4,
242288950Sjhb	  .args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } },
243288950Sjhb	{ .name = "mprotect", .ret_type = 1, .nargs = 3,
244288950Sjhb	  .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 } } },
245288950Sjhb	{ .name = "munmap", .ret_type = 1, .nargs = 2,
246288950Sjhb	  .args = { { Ptr, 0 }, { Int, 1 } } },
247288424Sjhb	{ .name = "nanosleep", .ret_type = 1, .nargs = 1,
248192025Sdds	  .args = { { Timespec, 0 } } },
249288950Sjhb	{ .name = "open", .ret_type = 1, .nargs = 3,
250288950Sjhb	  .args = { { Name | IN, 0 }, { Open, 1 }, { Octal, 2 } } },
251288950Sjhb	{ .name = "openat", .ret_type = 1, .nargs = 4,
252288950Sjhb	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Open, 2 },
253288950Sjhb		    { Octal, 3 } } },
254288950Sjhb	{ .name = "pathconf", .ret_type = 1, .nargs = 2,
255288950Sjhb	  .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
256288950Sjhb	{ .name = "pipe", .ret_type = 1, .nargs = 1,
257288950Sjhb	  .args = { { PipeFds | OUT, 0 } } },
258288950Sjhb	{ .name = "pipe2", .ret_type = 1, .nargs = 2,
259288950Sjhb	  .args = { { Ptr, 0 }, { Open, 1 } } },
260288950Sjhb	{ .name = "poll", .ret_type = 1, .nargs = 3,
261288950Sjhb	  .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
262288950Sjhb	{ .name = "posix_openpt", .ret_type = 1, .nargs = 1,
263288950Sjhb	  .args = { { Open, 0 } } },
264288950Sjhb	{ .name = "procctl", .ret_type = 1, .nargs = 4,
265288950Sjhb	  .args = { { Idtype, 0 }, { Quad, 1 + QUAD_ALIGN },
266288950Sjhb		    { Procctl, 1 + QUAD_ALIGN + QUAD_SLOTS },
267288950Sjhb		    { Ptr, 2 + QUAD_ALIGN + QUAD_SLOTS } } },
268288950Sjhb	{ .name = "read", .ret_type = 1, .nargs = 3,
269288950Sjhb	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 } } },
270288950Sjhb	{ .name = "readlink", .ret_type = 1, .nargs = 3,
271288950Sjhb	  .args = { { Name, 0 }, { Readlinkres | OUT, 1 }, { Int, 2 } } },
272288950Sjhb	{ .name = "readlinkat", .ret_type = 1, .nargs = 4,
273288950Sjhb	  .args = { { Atfd, 0 }, { Name, 1 }, { Readlinkres | OUT, 2 },
274288950Sjhb		    { Int, 3 } } },
275288950Sjhb	{ .name = "recvfrom", .ret_type = 1, .nargs = 6,
276288950Sjhb	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Hex, 3 },
277288950Sjhb		    { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } },
278288950Sjhb	{ .name = "rename", .ret_type = 1, .nargs = 2,
279288950Sjhb	  .args = { { Name, 0 }, { Name, 1 } } },
280288950Sjhb	{ .name = "renameat", .ret_type = 1, .nargs = 4,
281288950Sjhb	  .args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 } } },
282288950Sjhb	{ .name = "rfork", .ret_type = 1, .nargs = 1,
283288950Sjhb	  .args = { { Rforkflags, 0 } } },
284304477Sbdrewery	{ .name = "rmdir", .ret_type = 1, .nargs = 1,
285304477Sbdrewery	  .args = { { Name, 0 } } },
286192025Sdds	{ .name = "select", .ret_type = 1, .nargs = 5,
287286383Sjhb	  .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
288286383Sjhb		    { Timeval, 4 } } },
289288950Sjhb	{ .name = "sendto", .ret_type = 1, .nargs = 6,
290288950Sjhb	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Hex, 3 },
291288950Sjhb		    { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } },
292192025Sdds	{ .name = "setitimer", .ret_type = 1, .nargs = 3,
293286330Sjhb	  .args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
294288950Sjhb	{ .name = "setrlimit", .ret_type = 1, .nargs = 2,
295288950Sjhb	  .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
296288950Sjhb	{ .name = "shutdown", .ret_type = 1, .nargs = 2,
297288950Sjhb	  .args = { { Int, 0 }, { Shutdown, 1 } } },
298288950Sjhb	{ .name = "sigaction", .ret_type = 1, .nargs = 3,
299288950Sjhb	  .args = { { Signal, 0 }, { Sigaction | IN, 1 },
300288950Sjhb		    { Sigaction | OUT, 2 } } },
301288424Sjhb	{ .name = "sigpending", .ret_type = 1, .nargs = 1,
302286848Sjhb	  .args = { { Sigset | OUT, 0 } } },
303288424Sjhb	{ .name = "sigprocmask", .ret_type = 1, .nargs = 3,
304192025Sdds	  .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
305288424Sjhb	{ .name = "sigqueue", .ret_type = 1, .nargs = 3,
306286848Sjhb	  .args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
307288424Sjhb	{ .name = "sigreturn", .ret_type = 1, .nargs = 1,
308286848Sjhb	  .args = { { Ptr, 0 } } },
309288424Sjhb	{ .name = "sigsuspend", .ret_type = 1, .nargs = 1,
310286848Sjhb	  .args = { { Sigset | IN, 0 } } },
311286848Sjhb	{ .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
312286848Sjhb	  .args = { { Sigset | IN, 0 }, { Ptr, 1 }, { Timespec | IN, 2 } } },
313286848Sjhb	{ .name = "sigwait", .ret_type = 1, .nargs = 2,
314286848Sjhb	  .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
315286848Sjhb	{ .name = "sigwaitinfo", .ret_type = 1, .nargs = 2,
316286848Sjhb	  .args = { { Sigset | IN, 0 }, { Ptr, 1 } } },
317192025Sdds	{ .name = "socket", .ret_type = 1, .nargs = 3,
318192025Sdds	  .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Int, 2 } } },
319288950Sjhb	{ .name = "stat", .ret_type = 1, .nargs = 2,
320288950Sjhb	  .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
321288950Sjhb	{ .name = "statfs", .ret_type = 1, .nargs = 2,
322288950Sjhb	  .args = { { Name | IN, 0 }, { StatFs | OUT, 1 } } },
323192025Sdds	{ .name = "symlink", .ret_type = 1, .nargs = 2,
324286330Sjhb	  .args = { { Name, 0 }, { Name, 1 } } },
325286381Sjhb	{ .name = "symlinkat", .ret_type = 1, .nargs = 3,
326286381Sjhb	  .args = { { Name, 0 }, { Atfd, 1 }, { Name, 2 } } },
327288950Sjhb	{ .name = "sysarch", .ret_type = 1, .nargs = 2,
328288950Sjhb	  .args = { { Sysarch, 0 }, { Ptr, 1 } } },
329288950Sjhb	{ .name = "thr_kill", .ret_type = 1, .nargs = 2,
330288950Sjhb	  .args = { { Long, 0 }, { Signal, 1 } } },
331288950Sjhb	{ .name = "thr_self", .ret_type = 1, .nargs = 1,
332288950Sjhb	  .args = { { Ptr, 0 } } },
333288950Sjhb	{ .name = "truncate", .ret_type = 1, .nargs = 2,
334288950Sjhb	  .args = { { Name | IN, 0 }, { QuadHex | IN, 1 + QUAD_ALIGN } } },
335288950Sjhb#if 0
336288950Sjhb	/* Does not exist */
337288950Sjhb	{ .name = "umount", .ret_type = 1, .nargs = 2,
338288950Sjhb	  .args = { { Name, 0 }, { Int, 2 } } },
339288950Sjhb#endif
340288950Sjhb	{ .name = "unlink", .ret_type = 1, .nargs = 1,
341288950Sjhb	  .args = { { Name, 0 } } },
342288950Sjhb	{ .name = "unlinkat", .ret_type = 1, .nargs = 3,
343288950Sjhb	  .args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
344288950Sjhb	{ .name = "unmount", .ret_type = 1, .nargs = 2,
345288950Sjhb	  .args = { { Name, 0 }, { Int, 1 } } },
346288950Sjhb	{ .name = "utimensat", .ret_type = 1, .nargs = 4,
347288950Sjhb	  .args = { { Atfd, 0 }, { Name | IN, 1 }, { Timespec2 | IN, 2 },
348288950Sjhb		    { Atflags, 3 } } },
349288950Sjhb	{ .name = "utimes", .ret_type = 1, .nargs = 2,
350288950Sjhb	  .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
351288957Sbdrewery	{ .name = "utrace", .ret_type = 1, .nargs = 1,
352288957Sbdrewery	  .args = { { Utrace, 0 } } },
353255493Sjhb	{ .name = "wait4", .ret_type = 1, .nargs = 4,
354255493Sjhb	  .args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 },
355255493Sjhb		    { Rusage | OUT, 3 } } },
356255493Sjhb	{ .name = "wait6", .ret_type = 1, .nargs = 6,
357288455Sjhb	  .args = { { Idtype, 0 }, { Quad, 1 + QUAD_ALIGN },
358288455Sjhb		    { ExitStatus | OUT, 1 + QUAD_ALIGN + QUAD_SLOTS },
359288455Sjhb		    { Waitoptions, 2 + QUAD_ALIGN + QUAD_SLOTS },
360288455Sjhb		    { Rusage | OUT, 3 + QUAD_ALIGN + QUAD_SLOTS },
361288455Sjhb		    { Ptr, 4 + QUAD_ALIGN + QUAD_SLOTS } } },
362288950Sjhb	{ .name = "write", .ret_type = 1, .nargs = 3,
363288950Sjhb	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 } } },
364288950Sjhb
365288950Sjhb	/* Linux ABI */
366288950Sjhb	{ .name = "linux_access", .ret_type = 1, .nargs = 2,
367288950Sjhb	  .args = { { Name, 0 }, { Accessmode, 1 } } },
368288950Sjhb	{ .name = "linux_execve", .ret_type = 1, .nargs = 3,
369288950Sjhb	  .args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
370288950Sjhb		    { ExecEnv | IN, 2 } } },
371288950Sjhb	{ .name = "linux_lseek", .ret_type = 2, .nargs = 3,
372288950Sjhb	  .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
373288950Sjhb	{ .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
374288950Sjhb	  .args = { { Name | IN, 0 }, { Int, 1 } } },
375288950Sjhb	{ .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
376288950Sjhb	  .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
377288950Sjhb	{ .name = "linux_newstat", .ret_type = 1, .nargs = 2,
378288950Sjhb	  .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
379288950Sjhb	{ .name = "linux_open", .ret_type = 1, .nargs = 3,
380288950Sjhb	  .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
381288950Sjhb	{ .name = "linux_readlink", .ret_type = 1, .nargs = 3,
382288950Sjhb	  .args = { { Name, 0 }, { Name | OUT, 1 }, { Int, 2 } } },
383288950Sjhb	{ .name = "linux_socketcall", .ret_type = 1, .nargs = 2,
384288950Sjhb	  .args = { { Int, 0 }, { LinuxSockArgs, 1 } } },
385288950Sjhb	{ .name = "linux_stat64", .ret_type = 1, .nargs = 3,
386288950Sjhb	  .args = { { Name | IN, 0 }, { Ptr | OUT, 1 }, { Ptr | IN, 1 } } },
387288950Sjhb
388289004Sed	/* CloudABI system calls. */
389289004Sed	{ .name = "cloudabi_sys_clock_res_get", .ret_type = 1, .nargs = 1,
390289004Sed	  .args = { { CloudABIClockID, 0 } } },
391289004Sed	{ .name = "cloudabi_sys_clock_time_get", .ret_type = 1, .nargs = 2,
392289004Sed	  .args = { { CloudABIClockID, 0 }, { CloudABITimestamp, 1 } } },
393289004Sed	{ .name = "cloudabi_sys_condvar_signal", .ret_type = 1, .nargs = 3,
394289004Sed	  .args = { { Ptr, 0 }, { CloudABIMFlags, 1 }, { UInt, 2 } } },
395289004Sed	{ .name = "cloudabi_sys_fd_close", .ret_type = 1, .nargs = 1,
396289004Sed	  .args = { { Int, 0 } } },
397289004Sed	{ .name = "cloudabi_sys_fd_create1", .ret_type = 1, .nargs = 1,
398289004Sed	  .args = { { CloudABIFileType, 0 } } },
399289004Sed	{ .name = "cloudabi_sys_fd_create2", .ret_type = 1, .nargs = 2,
400289004Sed	  .args = { { CloudABIFileType, 0 }, { PipeFds | OUT, 0 } } },
401289004Sed	{ .name = "cloudabi_sys_fd_datasync", .ret_type = 1, .nargs = 1,
402289004Sed	  .args = { { Int, 0 } } },
403289004Sed	{ .name = "cloudabi_sys_fd_dup", .ret_type = 1, .nargs = 1,
404289004Sed	  .args = { { Int, 0 } } },
405289004Sed	{ .name = "cloudabi_sys_fd_replace", .ret_type = 1, .nargs = 2,
406289004Sed	  .args = { { Int, 0 }, { Int, 1 } } },
407289004Sed	{ .name = "cloudabi_sys_fd_seek", .ret_type = 1, .nargs = 3,
408289004Sed	  .args = { { Int, 0 }, { Int, 1 }, { CloudABIWhence, 2 } } },
409289004Sed	{ .name = "cloudabi_sys_fd_stat_get", .ret_type = 1, .nargs = 2,
410289004Sed	  .args = { { Int, 0 }, { CloudABIFDStat | OUT, 1 } } },
411289004Sed	{ .name = "cloudabi_sys_fd_stat_put", .ret_type = 1, .nargs = 3,
412289004Sed	  .args = { { Int, 0 }, { CloudABIFDStat | IN, 1 },
413289004Sed	            { ClouduABIFDSFlags, 2 } } },
414289004Sed	{ .name = "cloudabi_sys_fd_sync", .ret_type = 1, .nargs = 1,
415289004Sed	  .args = { { Int, 0 } } },
416289004Sed	{ .name = "cloudabi_sys_file_advise", .ret_type = 1, .nargs = 4,
417289004Sed	  .args = { { Int, 0 }, { Int, 1 }, { Int, 2 },
418289004Sed	            { CloudABIAdvice, 3 } } },
419289004Sed	{ .name = "cloudabi_sys_file_allocate", .ret_type = 1, .nargs = 3,
420289004Sed	  .args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
421289004Sed	{ .name = "cloudabi_sys_file_create", .ret_type = 1, .nargs = 3,
422289004Sed	  .args = { { Int, 0 }, { BinString | IN, 1 },
423289004Sed	            { CloudABIFileType, 3 } } },
424289004Sed	{ .name = "cloudabi_sys_file_link", .ret_type = 1, .nargs = 4,
425289004Sed	  .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
426289004Sed	            { Int, 3 }, { BinString | IN, 4 } } },
427289004Sed	{ .name = "cloudabi_sys_file_open", .ret_type = 1, .nargs = 4,
428289004Sed	  .args = { { Int, 0 }, { BinString | IN, 1 },
429289004Sed	            { CloudABIOFlags, 3 }, { CloudABIFDStat | IN, 4 } } },
430289004Sed	{ .name = "cloudabi_sys_file_readdir", .ret_type = 1, .nargs = 4,
431289004Sed	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 },
432289004Sed	            { Int, 3 } } },
433289004Sed	{ .name = "cloudabi_sys_file_readlink", .ret_type = 1, .nargs = 4,
434289004Sed	  .args = { { Int, 0 }, { BinString | IN, 1 },
435289004Sed	            { BinString | OUT, 3 }, { Int, 4 } } },
436289004Sed	{ .name = "cloudabi_sys_file_rename", .ret_type = 1, .nargs = 4,
437289004Sed	  .args = { { Int, 0 }, { BinString | IN, 1 },
438289004Sed	            { Int, 3 }, { BinString | IN, 4 } } },
439289004Sed	{ .name = "cloudabi_sys_file_stat_fget", .ret_type = 1, .nargs = 2,
440289004Sed	  .args = { { Int, 0 }, { CloudABIFileStat | OUT, 1 } } },
441289004Sed	{ .name = "cloudabi_sys_file_stat_fput", .ret_type = 1, .nargs = 3,
442289004Sed	  .args = { { Int, 0 }, { CloudABIFileStat | IN, 1 },
443289004Sed	            { CloudABIFSFlags, 2 } } },
444289004Sed	{ .name = "cloudabi_sys_file_stat_get", .ret_type = 1, .nargs = 3,
445289004Sed	  .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
446289004Sed	            { CloudABIFileStat | OUT, 3 } } },
447289004Sed	{ .name = "cloudabi_sys_file_stat_put", .ret_type = 1, .nargs = 4,
448289004Sed	  .args = { { CloudABILookup, 0 }, { BinString | IN, 1 },
449289004Sed	            { CloudABIFileStat | IN, 3 }, { CloudABIFSFlags, 4 } } },
450289004Sed	{ .name = "cloudabi_sys_file_symlink", .ret_type = 1, .nargs = 3,
451289004Sed	  .args = { { BinString | IN, 0 },
452289004Sed	            { Int, 2 }, { BinString | IN, 3 } } },
453289004Sed	{ .name = "cloudabi_sys_file_unlink", .ret_type = 1, .nargs = 3,
454289004Sed	  .args = { { Int, 0 }, { BinString | IN, 1 },
455289004Sed	            { CloudABIULFlags, 3 } } },
456289004Sed	{ .name = "cloudabi_sys_lock_unlock", .ret_type = 1, .nargs = 2,
457289004Sed	  .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
458289004Sed	{ .name = "cloudabi_sys_mem_advise", .ret_type = 1, .nargs = 3,
459289004Sed	  .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIAdvice, 2 } } },
460289004Sed	{ .name = "cloudabi_sys_mem_lock", .ret_type = 1, .nargs = 2,
461289004Sed	  .args = { { Ptr, 0 }, { Int, 1 } } },
462289004Sed	{ .name = "cloudabi_sys_mem_map", .ret_type = 1, .nargs = 6,
463289004Sed	  .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 },
464289004Sed	            { CloudABIMFlags, 3 }, { Int, 4 }, { Int, 5 } } },
465289004Sed	{ .name = "cloudabi_sys_mem_protect", .ret_type = 1, .nargs = 3,
466289004Sed	  .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMProt, 2 } } },
467289004Sed	{ .name = "cloudabi_sys_mem_sync", .ret_type = 1, .nargs = 3,
468289004Sed	  .args = { { Ptr, 0 }, { Int, 1 }, { CloudABIMSFlags, 2 } } },
469289004Sed	{ .name = "cloudabi_sys_mem_unlock", .ret_type = 1, .nargs = 2,
470289004Sed	  .args = { { Ptr, 0 }, { Int, 1 } } },
471289004Sed	{ .name = "cloudabi_sys_mem_unmap", .ret_type = 1, .nargs = 2,
472289004Sed	  .args = { { Ptr, 0 }, { Int, 1 } } },
473289004Sed	{ .name = "cloudabi_sys_proc_exec", .ret_type = 1, .nargs = 5,
474289004Sed	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 },
475289004Sed	            { IntArray, 3 }, { Int, 4 } } },
476289004Sed	{ .name = "cloudabi_sys_proc_exit", .ret_type = 1, .nargs = 1,
477289004Sed	  .args = { { Int, 0 } } },
478289004Sed	{ .name = "cloudabi_sys_proc_fork", .ret_type = 1, .nargs = 0 },
479289004Sed	{ .name = "cloudabi_sys_proc_raise", .ret_type = 1, .nargs = 1,
480289004Sed	  .args = { { CloudABISignal, 0 } } },
481289004Sed	{ .name = "cloudabi_sys_random_get", .ret_type = 1, .nargs = 2,
482289004Sed	  .args = { { BinString | OUT, 0 }, { Int, 1 } } },
483289004Sed	{ .name = "cloudabi_sys_sock_accept", .ret_type = 1, .nargs = 2,
484289004Sed	  .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 } } },
485289004Sed	{ .name = "cloudabi_sys_sock_bind", .ret_type = 1, .nargs = 3,
486289004Sed	  .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
487289004Sed	{ .name = "cloudabi_sys_sock_connect", .ret_type = 1, .nargs = 3,
488289004Sed	  .args = { { Int, 0 }, { Int, 1 }, { BinString | IN, 2 } } },
489289004Sed	{ .name = "cloudabi_sys_sock_listen", .ret_type = 1, .nargs = 2,
490289004Sed	  .args = { { Int, 0 }, { Int, 1 } } },
491289004Sed	{ .name = "cloudabi_sys_sock_shutdown", .ret_type = 1, .nargs = 2,
492289004Sed	  .args = { { Int, 0 }, { CloudABISDFlags, 1 } } },
493289004Sed	{ .name = "cloudabi_sys_sock_stat_get", .ret_type = 1, .nargs = 3,
494289004Sed	  .args = { { Int, 0 }, { CloudABISockStat | OUT, 1 },
495289004Sed	            { CloudABISSFlags, 2 } } },
496289004Sed	{ .name = "cloudabi_sys_thread_exit", .ret_type = 1, .nargs = 2,
497289004Sed	  .args = { { Ptr, 0 }, { CloudABIMFlags, 1 } } },
498289004Sed	{ .name = "cloudabi_sys_thread_tcb_set", .ret_type = 1, .nargs = 1,
499289004Sed	  .args = { { Ptr, 0 } } },
500289004Sed	{ .name = "cloudabi_sys_thread_yield", .ret_type = 1, .nargs = 0 },
501289004Sed
502192025Sdds	{ .name = 0 },
50331567Ssef};
504288832Sbdrewerystatic STAILQ_HEAD(, syscall) syscalls;
50531567Ssef
506158630Spav/* Xlat idea taken from strace */
507158630Spavstruct xlat {
508158630Spav	int val;
509168569Sdelphij	const char *str;
510158630Spav};
511158630Spav
512240005Szont#define	X(a)	{ a, #a },
513240005Szont#define	XEND	{ 0, NULL }
514158630Spav
515158630Spavstatic struct xlat kevent_filters[] = {
516158630Spav	X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
517158630Spav	X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
518286358Sjhb	X(EVFILT_PROCDESC) X(EVFILT_FS) X(EVFILT_LIO) X(EVFILT_USER)
519286358Sjhb	X(EVFILT_SENDFILE) XEND
520158630Spav};
521158630Spav
522158630Spavstatic struct xlat kevent_flags[] = {
523158630Spav	X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
524286358Sjhb	X(EV_CLEAR) X(EV_RECEIPT) X(EV_DISPATCH) X(EV_FORCEONESHOT)
525286358Sjhb	X(EV_DROP) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
526158630Spav};
527158630Spav
528286914Sjhbstatic struct xlat kevent_user_ffctrl[] = {
529286914Sjhb	X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
530286914Sjhb	XEND
531286914Sjhb};
532286914Sjhb
533286914Sjhbstatic struct xlat kevent_rdwr_fflags[] = {
534286914Sjhb	X(NOTE_LOWAT) X(NOTE_FILE_POLL) XEND
535286914Sjhb};
536286914Sjhb
537286914Sjhbstatic struct xlat kevent_vnode_fflags[] = {
538286914Sjhb	X(NOTE_DELETE) X(NOTE_WRITE) X(NOTE_EXTEND) X(NOTE_ATTRIB)
539286914Sjhb	X(NOTE_LINK) X(NOTE_RENAME) X(NOTE_REVOKE) XEND
540286914Sjhb};
541286914Sjhb
542286914Sjhbstatic struct xlat kevent_proc_fflags[] = {
543286914Sjhb	X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR)
544286914Sjhb	X(NOTE_CHILD) XEND
545286914Sjhb};
546286914Sjhb
547286914Sjhbstatic struct xlat kevent_timer_fflags[] = {
548286914Sjhb	X(NOTE_SECONDS) X(NOTE_MSECONDS) X(NOTE_USECONDS) X(NOTE_NSECONDS)
549286914Sjhb	XEND
550286914Sjhb};
551286914Sjhb
552228396Sedstatic struct xlat poll_flags[] = {
553158630Spav	X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
554158630Spav	X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
555158630Spav	X(POLLWRBAND) X(POLLINIGNEOF) XEND
556158630Spav};
557158630Spav
558158630Spavstatic struct xlat mmap_flags[] = {
559273250Sjhb	X(MAP_SHARED) X(MAP_PRIVATE) X(MAP_FIXED) X(MAP_RESERVED0020)
560273250Sjhb	X(MAP_RESERVED0040) X(MAP_RESERVED0080) X(MAP_RESERVED0100)
561158630Spav	X(MAP_HASSEMAPHORE) X(MAP_STACK) X(MAP_NOSYNC) X(MAP_ANON)
562286358Sjhb	X(MAP_EXCL) X(MAP_NOCORE) X(MAP_PREFAULT_READ)
563255426Sjhb#ifdef MAP_32BIT
564255426Sjhb	X(MAP_32BIT)
565255426Sjhb#endif
566255426Sjhb	XEND
567158630Spav};
568158630Spav
569158630Spavstatic struct xlat mprot_flags[] = {
570158630Spav	X(PROT_NONE) X(PROT_READ) X(PROT_WRITE) X(PROT_EXEC) XEND
571158630Spav};
572158630Spav
573158630Spavstatic struct xlat whence_arg[] = {
574286358Sjhb	X(SEEK_SET) X(SEEK_CUR) X(SEEK_END) X(SEEK_DATA) X(SEEK_HOLE) XEND
575158630Spav};
576158630Spav
577158630Spavstatic struct xlat sigaction_flags[] = {
578158630Spav	X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
579158630Spav	X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
580158630Spav};
581158630Spav
582158630Spavstatic struct xlat fcntl_arg[] = {
583158630Spav	X(F_DUPFD) X(F_GETFD) X(F_SETFD) X(F_GETFL) X(F_SETFL)
584286358Sjhb	X(F_GETOWN) X(F_SETOWN) X(F_OGETLK) X(F_OSETLK) X(F_OSETLKW)
585286358Sjhb	X(F_DUP2FD) X(F_GETLK) X(F_SETLK) X(F_SETLKW) X(F_SETLK_REMOTE)
586286358Sjhb	X(F_READAHEAD) X(F_RDAHEAD) X(F_DUPFD_CLOEXEC) X(F_DUP2FD_CLOEXEC)
587286358Sjhb	XEND
588158630Spav};
589158630Spav
590158630Spavstatic struct xlat fcntlfd_arg[] = {
591158630Spav	X(FD_CLOEXEC) XEND
592158630Spav};
593158630Spav
594158630Spavstatic struct xlat fcntlfl_arg[] = {
595158630Spav	X(O_APPEND) X(O_ASYNC) X(O_FSYNC) X(O_NONBLOCK) X(O_NOFOLLOW)
596286358Sjhb	X(FRDAHEAD) X(O_DIRECT) XEND
597158630Spav};
598158630Spav
599158630Spavstatic struct xlat sockdomain_arg[] = {
600158630Spav	X(PF_UNSPEC) X(PF_LOCAL) X(PF_UNIX) X(PF_INET) X(PF_IMPLINK)
601158630Spav	X(PF_PUP) X(PF_CHAOS) X(PF_NETBIOS) X(PF_ISO) X(PF_OSI)
602158630Spav	X(PF_ECMA) X(PF_DATAKIT) X(PF_CCITT) X(PF_SNA) X(PF_DECnet)
603158630Spav	X(PF_DLI) X(PF_LAT) X(PF_HYLINK) X(PF_APPLETALK) X(PF_ROUTE)
604158630Spav	X(PF_LINK) X(PF_XTP) X(PF_COIP) X(PF_CNT) X(PF_SIP) X(PF_IPX)
605158630Spav	X(PF_RTIP) X(PF_PIP) X(PF_ISDN) X(PF_KEY) X(PF_INET6)
606158630Spav	X(PF_NATM) X(PF_ATM) X(PF_NETGRAPH) X(PF_SLOW) X(PF_SCLUSTER)
607286358Sjhb	X(PF_ARP) X(PF_BLUETOOTH) X(PF_IEEE80211) X(PF_INET_SDP)
608286358Sjhb	X(PF_INET6_SDP) XEND
609158630Spav};
610158630Spav
611158630Spavstatic struct xlat socktype_arg[] = {
612158630Spav	X(SOCK_STREAM) X(SOCK_DGRAM) X(SOCK_RAW) X(SOCK_RDM)
613158630Spav	X(SOCK_SEQPACKET) XEND
614158630Spav};
615158630Spav
616158630Spavstatic struct xlat open_flags[] = {
617158630Spav	X(O_RDONLY) X(O_WRONLY) X(O_RDWR) X(O_ACCMODE) X(O_NONBLOCK)
618158630Spav	X(O_APPEND) X(O_SHLOCK) X(O_EXLOCK) X(O_ASYNC) X(O_FSYNC)
619158630Spav	X(O_NOFOLLOW) X(O_CREAT) X(O_TRUNC) X(O_EXCL) X(O_NOCTTY)
620286358Sjhb	X(O_DIRECT) X(O_DIRECTORY) X(O_EXEC) X(O_TTY_INIT) X(O_CLOEXEC)
621286358Sjhb	X(O_VERIFY) XEND
622158630Spav};
623158630Spav
624158630Spavstatic struct xlat shutdown_arg[] = {
625158630Spav	X(SHUT_RD) X(SHUT_WR) X(SHUT_RDWR) XEND
626158630Spav};
627158630Spav
628158630Spavstatic struct xlat resource_arg[] = {
629158630Spav	X(RLIMIT_CPU) X(RLIMIT_FSIZE) X(RLIMIT_DATA) X(RLIMIT_STACK)
630158630Spav	X(RLIMIT_CORE) X(RLIMIT_RSS) X(RLIMIT_MEMLOCK) X(RLIMIT_NPROC)
631286358Sjhb	X(RLIMIT_NOFILE) X(RLIMIT_SBSIZE) X(RLIMIT_VMEM) X(RLIMIT_NPTS)
632286358Sjhb	X(RLIMIT_SWAP) X(RLIMIT_KQUEUES) XEND
633158630Spav};
634158630Spav
635158630Spavstatic struct xlat pathconf_arg[] = {
636158630Spav	X(_PC_LINK_MAX)  X(_PC_MAX_CANON)  X(_PC_MAX_INPUT)
637158630Spav	X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF)
638158630Spav	X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE)
639158630Spav	X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO)
640158630Spav	X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS)
641158630Spav	X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE)
642158630Spav	X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
643158630Spav	X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
644158630Spav	X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
645286358Sjhb	X(_PC_ACL_NFS4) X(_PC_MIN_HOLE_SIZE) XEND
646158630Spav};
647158630Spav
648253850Smarkjstatic struct xlat rfork_flags[] = {
649286358Sjhb	X(RFFDG) X(RFPROC) X(RFMEM) X(RFNOWAIT) X(RFCFDG) X(RFTHREAD)
650286358Sjhb	X(RFSIGSHARE) X(RFLINUXTHPN) X(RFTSIGZMB) X(RFPPWAIT) XEND
651253850Smarkj};
652253850Smarkj
653255493Sjhbstatic struct xlat wait_options[] = {
654255493Sjhb	X(WNOHANG) X(WUNTRACED) X(WCONTINUED) X(WNOWAIT) X(WEXITED)
655255493Sjhb	X(WTRAPPED) XEND
656255493Sjhb};
657255493Sjhb
658255493Sjhbstatic struct xlat idtype_arg[] = {
659255493Sjhb	X(P_PID) X(P_PPID) X(P_PGID) X(P_SID) X(P_CID) X(P_UID) X(P_GID)
660255493Sjhb	X(P_ALL) X(P_LWPID) X(P_TASKID) X(P_PROJID) X(P_POOLID) X(P_JAILID)
661255493Sjhb	X(P_CTID) X(P_CPUID) X(P_PSETID) XEND
662255493Sjhb};
663255493Sjhb
664255708Sjhbstatic struct xlat procctl_arg[] = {
665288405Sjhb	X(PROC_SPROTECT) X(PROC_REAP_ACQUIRE) X(PROC_REAP_RELEASE)
666288405Sjhb	X(PROC_REAP_STATUS) X(PROC_REAP_GETPIDS) X(PROC_REAP_KILL)
667288405Sjhb	X(PROC_TRACE_CTL) X(PROC_TRACE_STATUS) XEND
668255708Sjhb};
669255708Sjhb
670273053Sjhbstatic struct xlat umtx_ops[] = {
671273053Sjhb	X(UMTX_OP_RESERVED0) X(UMTX_OP_RESERVED1) X(UMTX_OP_WAIT)
672273053Sjhb	X(UMTX_OP_WAKE) X(UMTX_OP_MUTEX_TRYLOCK) X(UMTX_OP_MUTEX_LOCK)
673273053Sjhb	X(UMTX_OP_MUTEX_UNLOCK) X(UMTX_OP_SET_CEILING) X(UMTX_OP_CV_WAIT)
674273053Sjhb	X(UMTX_OP_CV_SIGNAL) X(UMTX_OP_CV_BROADCAST) X(UMTX_OP_WAIT_UINT)
675273053Sjhb	X(UMTX_OP_RW_RDLOCK) X(UMTX_OP_RW_WRLOCK) X(UMTX_OP_RW_UNLOCK)
676273053Sjhb	X(UMTX_OP_WAIT_UINT_PRIVATE) X(UMTX_OP_WAKE_PRIVATE)
677273053Sjhb	X(UMTX_OP_MUTEX_WAIT) X(UMTX_OP_MUTEX_WAKE) X(UMTX_OP_SEM_WAIT)
678273053Sjhb	X(UMTX_OP_SEM_WAKE) X(UMTX_OP_NWAKE_PRIVATE) X(UMTX_OP_MUTEX_WAKE2)
679273604Sjhb	X(UMTX_OP_SEM2_WAIT) X(UMTX_OP_SEM2_WAKE)
680273053Sjhb	XEND
681273053Sjhb};
682273053Sjhb
683286381Sjhbstatic struct xlat at_flags[] = {
684286381Sjhb	X(AT_EACCESS) X(AT_SYMLINK_NOFOLLOW) X(AT_SYMLINK_FOLLOW)
685286381Sjhb	X(AT_REMOVEDIR) XEND
686286381Sjhb};
687286381Sjhb
688286381Sjhbstatic struct xlat access_modes[] = {
689286381Sjhb	X(R_OK) X(W_OK) X(X_OK) XEND
690286381Sjhb};
691286381Sjhb
692286848Sjhbstatic struct xlat sysarch_ops[] = {
693286848Sjhb#if defined(__i386__) || defined(__amd64__)
694286848Sjhb	X(I386_GET_LDT) X(I386_SET_LDT) X(I386_GET_IOPERM) X(I386_SET_IOPERM)
695286848Sjhb	X(I386_VM86) X(I386_GET_FSBASE) X(I386_SET_FSBASE) X(I386_GET_GSBASE)
696286848Sjhb	X(I386_SET_GSBASE) X(I386_GET_XFPUSTATE) X(AMD64_GET_FSBASE)
697286848Sjhb	X(AMD64_SET_FSBASE) X(AMD64_GET_GSBASE) X(AMD64_SET_GSBASE)
698286848Sjhb	X(AMD64_GET_XFPUSTATE)
699286848Sjhb#endif
700286848Sjhb	XEND
701286848Sjhb};
702286857Sjhb
703286857Sjhbstatic struct xlat linux_socketcall_ops[] = {
704286857Sjhb	X(LINUX_SOCKET) X(LINUX_BIND) X(LINUX_CONNECT) X(LINUX_LISTEN)
705286857Sjhb	X(LINUX_ACCEPT) X(LINUX_GETSOCKNAME) X(LINUX_GETPEERNAME)
706286857Sjhb	X(LINUX_SOCKETPAIR) X(LINUX_SEND) X(LINUX_RECV) X(LINUX_SENDTO)
707286857Sjhb	X(LINUX_RECVFROM) X(LINUX_SHUTDOWN) X(LINUX_SETSOCKOPT)
708286857Sjhb	X(LINUX_GETSOCKOPT) X(LINUX_SENDMSG) X(LINUX_RECVMSG)
709286857Sjhb	XEND
710286857Sjhb};
711286857Sjhb
712286860Sjhbstatic struct xlat sigprocmask_ops[] = {
713286860Sjhb	X(SIG_BLOCK) X(SIG_UNBLOCK) X(SIG_SETMASK)
714286860Sjhb	XEND
715286860Sjhb};
716286860Sjhb
717158630Spav#undef X
718289004Sed#define	X(a)	{ CLOUDABI_##a, #a },
719289004Sed
720289004Sedstatic struct xlat cloudabi_advice[] = {
721289004Sed	X(ADVICE_DONTNEED) X(ADVICE_NOREUSE) X(ADVICE_NORMAL)
722289004Sed	X(ADVICE_RANDOM) X(ADVICE_SEQUENTIAL) X(ADVICE_WILLNEED)
723289004Sed	XEND
724289004Sed};
725289004Sed
726289004Sedstatic struct xlat cloudabi_clockid[] = {
727289004Sed	X(CLOCK_MONOTONIC) X(CLOCK_PROCESS_CPUTIME_ID)
728289004Sed	X(CLOCK_REALTIME) X(CLOCK_THREAD_CPUTIME_ID)
729289004Sed	XEND
730289004Sed};
731289004Sed
732289004Sedstatic struct xlat cloudabi_errno[] = {
733289004Sed	X(E2BIG) X(EACCES) X(EADDRINUSE) X(EADDRNOTAVAIL)
734289004Sed	X(EAFNOSUPPORT) X(EAGAIN) X(EALREADY) X(EBADF) X(EBADMSG)
735289004Sed	X(EBUSY) X(ECANCELED) X(ECHILD) X(ECONNABORTED) X(ECONNREFUSED)
736289004Sed	X(ECONNRESET) X(EDEADLK) X(EDESTADDRREQ) X(EDOM) X(EDQUOT)
737289004Sed	X(EEXIST) X(EFAULT) X(EFBIG) X(EHOSTUNREACH) X(EIDRM) X(EILSEQ)
738289004Sed	X(EINPROGRESS) X(EINTR) X(EINVAL) X(EIO) X(EISCONN) X(EISDIR)
739289004Sed	X(ELOOP) X(EMFILE) X(EMLINK) X(EMSGSIZE) X(EMULTIHOP)
740289004Sed	X(ENAMETOOLONG) X(ENETDOWN) X(ENETRESET) X(ENETUNREACH)
741289004Sed	X(ENFILE) X(ENOBUFS) X(ENODEV) X(ENOENT) X(ENOEXEC) X(ENOLCK)
742289004Sed	X(ENOLINK) X(ENOMEM) X(ENOMSG) X(ENOPROTOOPT) X(ENOSPC)
743289004Sed	X(ENOSYS) X(ENOTCONN) X(ENOTDIR) X(ENOTEMPTY) X(ENOTRECOVERABLE)
744289004Sed	X(ENOTSOCK) X(ENOTSUP) X(ENOTTY) X(ENXIO) X(EOVERFLOW)
745289004Sed	X(EOWNERDEAD) X(EPERM) X(EPIPE) X(EPROTO) X(EPROTONOSUPPORT)
746289004Sed	X(EPROTOTYPE) X(ERANGE) X(EROFS) X(ESPIPE) X(ESRCH) X(ESTALE)
747289004Sed	X(ETIMEDOUT) X(ETXTBSY) X(EXDEV) X(ENOTCAPABLE)
748289004Sed	XEND
749289004Sed};
750289004Sed
751289004Sedstatic struct xlat cloudabi_fdflags[] = {
752289004Sed	X(FDFLAG_APPEND) X(FDFLAG_DSYNC) X(FDFLAG_NONBLOCK)
753289004Sed	X(FDFLAG_RSYNC) X(FDFLAG_SYNC)
754289004Sed	XEND
755289004Sed};
756289004Sed
757289004Sedstatic struct xlat cloudabi_fdsflags[] = {
758289004Sed	X(FDSTAT_FLAGS) X(FDSTAT_RIGHTS)
759289004Sed	XEND
760289004Sed};
761289004Sed
762289004Sedstatic struct xlat cloudabi_filetype[] = {
763289004Sed	X(FILETYPE_UNKNOWN) X(FILETYPE_BLOCK_DEVICE)
764289004Sed	X(FILETYPE_CHARACTER_DEVICE) X(FILETYPE_DIRECTORY)
765289004Sed	X(FILETYPE_FIFO) X(FILETYPE_POLL) X(FILETYPE_PROCESS)
766289004Sed	X(FILETYPE_REGULAR_FILE) X(FILETYPE_SHARED_MEMORY)
767289004Sed	X(FILETYPE_SOCKET_DGRAM) X(FILETYPE_SOCKET_SEQPACKET)
768289004Sed	X(FILETYPE_SOCKET_STREAM) X(FILETYPE_SYMBOLIC_LINK)
769289004Sed	XEND
770289004Sed};
771289004Sed
772289004Sedstatic struct xlat cloudabi_fsflags[] = {
773289004Sed	X(FILESTAT_ATIM) X(FILESTAT_ATIM_NOW) X(FILESTAT_MTIM)
774289004Sed	X(FILESTAT_MTIM_NOW) X(FILESTAT_SIZE)
775289004Sed	XEND
776289004Sed};
777289004Sed
778289004Sedstatic struct xlat cloudabi_mflags[] = {
779289004Sed	X(MAP_ANON) X(MAP_FIXED) X(MAP_PRIVATE) X(MAP_SHARED)
780289004Sed	XEND
781289004Sed};
782289004Sed
783289004Sedstatic struct xlat cloudabi_mprot[] = {
784289004Sed	X(PROT_EXEC) X(PROT_WRITE) X(PROT_READ)
785289004Sed	XEND
786289004Sed};
787289004Sed
788289004Sedstatic struct xlat cloudabi_msflags[] = {
789289004Sed	X(MS_ASYNC) X(MS_INVALIDATE) X(MS_SYNC)
790289004Sed	XEND
791289004Sed};
792289004Sed
793289004Sedstatic struct xlat cloudabi_oflags[] = {
794289004Sed	X(O_CREAT) X(O_DIRECTORY) X(O_EXCL) X(O_TRUNC)
795289004Sed	XEND
796289004Sed};
797289004Sed
798289004Sedstatic struct xlat cloudabi_sa_family[] = {
799289004Sed	X(AF_UNSPEC) X(AF_INET) X(AF_INET6) X(AF_UNIX)
800289004Sed	XEND
801289004Sed};
802289004Sed
803289004Sedstatic struct xlat cloudabi_sdflags[] = {
804289004Sed	X(SHUT_RD) X(SHUT_WR)
805289004Sed	XEND
806289004Sed};
807289004Sed
808289004Sedstatic struct xlat cloudabi_signal[] = {
809289004Sed	X(SIGABRT) X(SIGALRM) X(SIGBUS) X(SIGCHLD) X(SIGCONT) X(SIGFPE)
810289004Sed	X(SIGHUP) X(SIGILL) X(SIGINT) X(SIGKILL) X(SIGPIPE) X(SIGQUIT)
811289004Sed	X(SIGSEGV) X(SIGSTOP) X(SIGSYS) X(SIGTERM) X(SIGTRAP) X(SIGTSTP)
812289004Sed	X(SIGTTIN) X(SIGTTOU) X(SIGURG) X(SIGUSR1) X(SIGUSR2)
813289004Sed	X(SIGVTALRM) X(SIGXCPU) X(SIGXFSZ)
814289004Sed	XEND
815289004Sed};
816289004Sed
817289004Sedstatic struct xlat cloudabi_ssflags[] = {
818289004Sed	X(SOCKSTAT_CLEAR_ERROR)
819289004Sed	XEND
820289004Sed};
821289004Sed
822289004Sedstatic struct xlat cloudabi_ssstate[] = {
823297247Sed	X(SOCKSTATE_ACCEPTCONN)
824289004Sed	XEND
825289004Sed};
826289004Sed
827289004Sedstatic struct xlat cloudabi_ulflags[] = {
828289004Sed	X(UNLINK_REMOVEDIR)
829289004Sed	XEND
830289004Sed};
831289004Sed
832289004Sedstatic struct xlat cloudabi_whence[] = {
833289004Sed	X(WHENCE_CUR) X(WHENCE_END) X(WHENCE_SET)
834289004Sed	XEND
835289004Sed};
836289004Sed
837289004Sed#undef X
838158630Spav#undef XEND
839158630Spav
840181061Sdes/*
841181061Sdes * Searches an xlat array for a value, and returns it if found.  Otherwise
842181061Sdes * return a string representation.
843181061Sdes */
844181061Sdesstatic const char *
845181061Sdeslookup(struct xlat *xlat, int val, int base)
846158630Spav{
847158630Spav	static char tmp[16];
848181061Sdes
849158630Spav	for (; xlat->str != NULL; xlat++)
850158630Spav		if (xlat->val == val)
851181061Sdes			return (xlat->str);
852158630Spav	switch (base) {
853158630Spav		case 8:
854158630Spav			sprintf(tmp, "0%o", val);
855158630Spav			break;
856158630Spav		case 16:
857158630Spav			sprintf(tmp, "0x%x", val);
858158630Spav			break;
859158630Spav		case 10:
860158630Spav			sprintf(tmp, "%u", val);
861158630Spav			break;
862158630Spav		default:
863158630Spav			errx(1,"Unknown lookup base");
864158630Spav			break;
865158630Spav	}
866181061Sdes	return (tmp);
867158630Spav}
868158630Spav
869168569Sdelphijstatic const char *
870168569Sdelphijxlookup(struct xlat *xlat, int val)
871158630Spav{
872181061Sdes
873181061Sdes	return (lookup(xlat, val, 16));
874158630Spav}
875158630Spav
876286938Sjhb/*
877286938Sjhb * Searches an xlat array containing bitfield values.  Remaining bits
878286938Sjhb * set after removing the known ones are printed at the end:
879286938Sjhb * IN|0x400.
880286938Sjhb */
881181061Sdesstatic char *
882181061Sdesxlookup_bits(struct xlat *xlat, int val)
883158630Spav{
884240005Szont	int len, rem;
885158630Spav	static char str[512];
886158630Spav
887240005Szont	len = 0;
888240005Szont	rem = val;
889181061Sdes	for (; xlat->str != NULL; xlat++) {
890181061Sdes		if ((xlat->val & rem) == xlat->val) {
891286938Sjhb			/*
892286938Sjhb			 * Don't print the "all-bits-zero" string unless all
893286938Sjhb			 * bits are really zero.
894286938Sjhb			 */
895158630Spav			if (xlat->val == 0 && val != 0)
896158630Spav				continue;
897158630Spav			len += sprintf(str + len, "%s|", xlat->str);
898158630Spav			rem &= ~(xlat->val);
899158630Spav		}
900158630Spav	}
901286938Sjhb
902286938Sjhb	/*
903286938Sjhb	 * If we have leftover bits or didn't match anything, print
904286938Sjhb	 * the remainder.
905286938Sjhb	 */
906158630Spav	if (rem || len == 0)
907158630Spav		len += sprintf(str + len, "0x%x", rem);
908158630Spav	if (len && str[len - 1] == '|')
909158630Spav		len--;
910158630Spav	str[len] = 0;
911181061Sdes	return (str);
912158630Spav}
913158630Spav
914288832Sbdreweryvoid
915288832Sbdreweryinit_syscalls(void)
916288832Sbdrewery{
917288832Sbdrewery	struct syscall *sc;
918288832Sbdrewery
919288832Sbdrewery	STAILQ_INIT(&syscalls);
920288832Sbdrewery	for (sc = decoded_syscalls; sc->name != NULL; sc++)
921288832Sbdrewery		STAILQ_INSERT_HEAD(&syscalls, sc, entries);
922288832Sbdrewery}
92331567Ssef/*
92431567Ssef * If/when the list gets big, it might be desirable to do it
92531567Ssef * as a hash table or binary search.
92631567Ssef */
92731567Ssefstruct syscall *
928288832Sbdreweryget_syscall(const char *name, int nargs)
929181061Sdes{
930240005Szont	struct syscall *sc;
931288832Sbdrewery	int i;
93231567Ssef
933133349Salfred	if (name == NULL)
934133349Salfred		return (NULL);
935288832Sbdrewery	STAILQ_FOREACH(sc, &syscalls, entries)
936240005Szont		if (strcmp(name, sc->name) == 0)
937181061Sdes			return (sc);
938288832Sbdrewery
939288832Sbdrewery	/* It is unknown.  Add it into the list. */
940288832Sbdrewery#if DEBUG
941288832Sbdrewery	fprintf(stderr, "unknown syscall %s -- setting args to %d\n", name,
942288832Sbdrewery	    nargs);
943288832Sbdrewery#endif
944288832Sbdrewery
945288832Sbdrewery	sc = calloc(1, sizeof(struct syscall));
946288832Sbdrewery	sc->name = strdup(name);
947288832Sbdrewery	sc->ret_type = 1;
948288832Sbdrewery	sc->nargs = nargs;
949288832Sbdrewery	for (i = 0; i < nargs; i++) {
950288832Sbdrewery		sc->args[i].offset = i;
951288832Sbdrewery		/* Treat all unknown arguments as LongHex. */
952288832Sbdrewery		sc->args[i].type = LongHex;
95331567Ssef	}
954288832Sbdrewery	STAILQ_INSERT_HEAD(&syscalls, sc, entries);
955288832Sbdrewery
956288832Sbdrewery	return (sc);
95731567Ssef}
95831567Ssef
95931567Ssef/*
96085292Sdes * Copy a fixed amount of bytes from the process.
96185292Sdes */
96287703Smarkmstatic int
963239501Szontget_struct(pid_t pid, void *offset, void *buf, int len)
964181061Sdes{
965168569Sdelphij	struct ptrace_io_desc iorequest;
966181061Sdes
967168569Sdelphij	iorequest.piod_op = PIOD_READ_D;
968168569Sdelphij	iorequest.piod_offs = offset;
969168569Sdelphij	iorequest.piod_addr = buf;
970168569Sdelphij	iorequest.piod_len = len;
971168569Sdelphij	if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
972181061Sdes		return (-1);
973181061Sdes	return (0);
97485292Sdes}
97585292Sdes
976240005Szont#define	MAXSIZE		4096
977286331Sjhb
97885292Sdes/*
97931567Ssef * Copy a string from the process.  Note that it is
98031567Ssef * expected to be a C string, but if max is set, it will
98131567Ssef * only get that much.
98231567Ssef */
983168569Sdelphijstatic char *
984286331Sjhbget_string(pid_t pid, void *addr, int max)
985181061Sdes{
986240005Szont	struct ptrace_io_desc iorequest;
987286331Sjhb	char *buf, *nbuf;
988286331Sjhb	size_t offset, size, totalsize;
989181061Sdes
990286331Sjhb	offset = 0;
991286331Sjhb	if (max)
992286331Sjhb		size = max + 1;
993286331Sjhb	else {
994286331Sjhb		/* Read up to the end of the current page. */
995286331Sjhb		size = PAGE_SIZE - ((uintptr_t)addr % PAGE_SIZE);
996286331Sjhb		if (size > MAXSIZE)
997286331Sjhb			size = MAXSIZE;
998286331Sjhb	}
999286331Sjhb	totalsize = size;
1000168569Sdelphij	buf = malloc(totalsize);
1001168569Sdelphij	if (buf == NULL)
1002181061Sdes		return (NULL);
1003181061Sdes	for (;;) {
1004168569Sdelphij		iorequest.piod_op = PIOD_READ_D;
1005286331Sjhb		iorequest.piod_offs = (char *)addr + offset;
1006286331Sjhb		iorequest.piod_addr = buf + offset;
1007168569Sdelphij		iorequest.piod_len = size;
1008168569Sdelphij		if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
1009168569Sdelphij			free(buf);
1010181061Sdes			return (NULL);
101131567Ssef		}
1012286331Sjhb		if (memchr(buf + offset, '\0', size) != NULL)
1013286331Sjhb			return (buf);
1014286331Sjhb		offset += size;
1015286331Sjhb		if (totalsize < MAXSIZE && max == 0) {
1016286331Sjhb			size = MAXSIZE - totalsize;
1017286331Sjhb			if (size > PAGE_SIZE)
1018286331Sjhb				size = PAGE_SIZE;
1019286331Sjhb			nbuf = realloc(buf, totalsize + size);
1020286331Sjhb			if (nbuf == NULL) {
1021286331Sjhb				buf[totalsize - 1] = '\0';
1022168569Sdelphij				return (buf);
1023286331Sjhb			}
1024286331Sjhb			buf = nbuf;
1025286331Sjhb			totalsize += size;
1026181061Sdes		} else {
1027216224Sjh			buf[totalsize - 1] = '\0';
1028181061Sdes			return (buf);
1029168569Sdelphij		}
103031567Ssef	}
103131567Ssef}
103231567Ssef
1033255493Sjhbstatic char *
1034255493Sjhbstrsig2(int sig)
1035255493Sjhb{
1036286913Sjhb	static char tmp[sizeof(int) * 3 + 1];
1037286913Sjhb	char *ret;
103831567Ssef
1039286913Sjhb	ret = strsig(sig);
1040286913Sjhb	if (ret == NULL) {
1041286913Sjhb		snprintf(tmp, sizeof(tmp), "%d", sig);
1042286913Sjhb		ret = tmp;
1043286913Sjhb	}
1044286913Sjhb	return (ret);
1045255493Sjhb}
1046255493Sjhb
1047286914Sjhbstatic void
1048286914Sjhbprint_kevent(FILE *fp, struct kevent *ke, int input)
1049286914Sjhb{
1050286914Sjhb
1051286914Sjhb	switch (ke->filter) {
1052286914Sjhb	case EVFILT_READ:
1053286914Sjhb	case EVFILT_WRITE:
1054286914Sjhb	case EVFILT_VNODE:
1055286914Sjhb	case EVFILT_PROC:
1056286914Sjhb	case EVFILT_TIMER:
1057286914Sjhb	case EVFILT_PROCDESC:
1058286914Sjhb		fprintf(fp, "%ju", (uintmax_t)ke->ident);
1059286914Sjhb		break;
1060286914Sjhb	case EVFILT_SIGNAL:
1061286914Sjhb		fputs(strsig2(ke->ident), fp);
1062286914Sjhb		break;
1063286914Sjhb	default:
1064286914Sjhb		fprintf(fp, "%p", (void *)ke->ident);
1065286914Sjhb	}
1066286914Sjhb	fprintf(fp, ",%s,%s,", xlookup(kevent_filters, ke->filter),
1067286914Sjhb	    xlookup_bits(kevent_flags, ke->flags));
1068286914Sjhb	switch (ke->filter) {
1069286914Sjhb	case EVFILT_READ:
1070286914Sjhb	case EVFILT_WRITE:
1071286914Sjhb		fputs(xlookup_bits(kevent_rdwr_fflags, ke->fflags), fp);
1072286914Sjhb		break;
1073286914Sjhb	case EVFILT_VNODE:
1074286914Sjhb		fputs(xlookup_bits(kevent_vnode_fflags, ke->fflags), fp);
1075286914Sjhb		break;
1076286914Sjhb	case EVFILT_PROC:
1077286914Sjhb	case EVFILT_PROCDESC:
1078286914Sjhb		fputs(xlookup_bits(kevent_proc_fflags, ke->fflags), fp);
1079286914Sjhb		break;
1080286914Sjhb	case EVFILT_TIMER:
1081286914Sjhb		fputs(xlookup_bits(kevent_timer_fflags, ke->fflags), fp);
1082286914Sjhb		break;
1083286914Sjhb	case EVFILT_USER: {
1084286914Sjhb		int ctrl, data;
1085286914Sjhb
1086286914Sjhb		ctrl = ke->fflags & NOTE_FFCTRLMASK;
1087288406Sjhb		data = ke->fflags & NOTE_FFLAGSMASK;
1088286914Sjhb		if (input) {
1089286914Sjhb			fputs(xlookup(kevent_user_ffctrl, ctrl), fp);
1090286914Sjhb			if (ke->fflags & NOTE_TRIGGER)
1091286914Sjhb				fputs("|NOTE_TRIGGER", fp);
1092286914Sjhb			if (data != 0)
1093286914Sjhb				fprintf(fp, "|%#x", data);
1094286914Sjhb		} else {
1095286914Sjhb			fprintf(fp, "%#x", data);
1096286914Sjhb		}
1097286914Sjhb		break;
1098286914Sjhb	}
1099286914Sjhb	default:
1100286914Sjhb		fprintf(fp, "%#x", ke->fflags);
1101286914Sjhb	}
1102286914Sjhb	fprintf(fp, ",%p,%p", (void *)ke->data, (void *)ke->udata);
1103286914Sjhb}
1104286914Sjhb
1105288957Sbdrewerystatic void
1106288957Sbdreweryprint_utrace(FILE *fp, void *utrace_addr, size_t len)
1107288957Sbdrewery{
1108288957Sbdrewery	unsigned char *utrace_buffer;
1109288957Sbdrewery
1110288957Sbdrewery	fprintf(fp, "{ ");
1111292236Sjhb	if (sysdecode_utrace(fp, utrace_addr, len)) {
1112288957Sbdrewery		fprintf(fp, " }");
1113288957Sbdrewery		return;
1114288957Sbdrewery	}
1115288957Sbdrewery
1116288957Sbdrewery	utrace_buffer = utrace_addr;
1117288957Sbdrewery	fprintf(fp, "%zu:", len);
1118288957Sbdrewery	while (len--)
1119288957Sbdrewery		fprintf(fp, " %02x", *utrace_buffer++);
1120288957Sbdrewery	fprintf(fp, " }");
1121288957Sbdrewery}
1122288957Sbdrewery
112331567Ssef/*
112431567Ssef * Converts a syscall argument into a string.  Said string is
1125286938Sjhb * allocated via malloc(), so needs to be free()'d.  sc is
112631567Ssef * a pointer to the syscall description (see above); args is
112731567Ssef * an array of all of the system call arguments.
112831567Ssef */
112931567Ssefchar *
1130288424Sjhbprint_arg(struct syscall_args *sc, unsigned long *args, long *retval,
1131240005Szont    struct trussinfo *trussinfo)
1132181061Sdes{
1133286913Sjhb	FILE *fp;
1134240005Szont	char *tmp;
1135286913Sjhb	size_t tmplen;
1136240005Szont	pid_t pid;
1137158630Spav
1138286913Sjhb	fp = open_memstream(&tmp, &tmplen);
1139288424Sjhb	pid = trussinfo->curthread->proc->pid;
1140181061Sdes	switch (sc->type & ARG_MASK) {
1141181061Sdes	case Hex:
1142286913Sjhb		fprintf(fp, "0x%x", (int)args[sc->offset]);
1143181061Sdes		break;
1144181061Sdes	case Octal:
1145286913Sjhb		fprintf(fp, "0%o", (int)args[sc->offset]);
1146181061Sdes		break;
1147181061Sdes	case Int:
1148286913Sjhb		fprintf(fp, "%d", (int)args[sc->offset]);
1149181061Sdes		break;
1150289004Sed	case UInt:
1151289004Sed		fprintf(fp, "%u", (unsigned int)args[sc->offset]);
1152289004Sed		break;
1153273053Sjhb	case LongHex:
1154286913Sjhb		fprintf(fp, "0x%lx", args[sc->offset]);
1155286848Sjhb		break;
1156286848Sjhb	case Long:
1157286913Sjhb		fprintf(fp, "%ld", args[sc->offset]);
1158286848Sjhb		break;
1159181061Sdes	case Name: {
1160181061Sdes		/* NULL-terminated string. */
1161181061Sdes		char *tmp2;
1162286938Sjhb
1163181061Sdes		tmp2 = get_string(pid, (void*)args[sc->offset], 0);
1164286913Sjhb		fprintf(fp, "\"%s\"", tmp2);
1165181061Sdes		free(tmp2);
1166181061Sdes		break;
1167181061Sdes	}
1168181061Sdes	case BinString: {
1169286938Sjhb		/*
1170286938Sjhb		 * Binary block of data that might have printable characters.
1171286938Sjhb		 * XXX If type|OUT, assume that the length is the syscall's
1172286938Sjhb		 * return value.  Otherwise, assume that the length of the block
1173286938Sjhb		 * is in the next syscall argument.
1174286938Sjhb		 */
1175181061Sdes		int max_string = trussinfo->strsize;
1176286938Sjhb		char tmp2[max_string + 1], *tmp3;
1177181061Sdes		int len;
1178181061Sdes		int truncated = 0;
1179158630Spav
1180181061Sdes		if (sc->type & OUT)
1181288424Sjhb			len = retval[0];
1182181061Sdes		else
1183181061Sdes			len = args[sc->offset + 1];
1184101289Smdodd
1185286938Sjhb		/*
1186286938Sjhb		 * Don't print more than max_string characters, to avoid word
1187286938Sjhb		 * wrap.  If we have to truncate put some ... after the string.
1188286938Sjhb		 */
1189181061Sdes		if (len > max_string) {
1190181061Sdes			len = max_string;
1191181061Sdes			truncated = 1;
1192181061Sdes		}
1193240005Szont		if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
1194240005Szont		    != -1) {
1195181061Sdes			tmp3 = malloc(len * 4 + 1);
1196181061Sdes			while (len) {
1197240005Szont				if (strvisx(tmp3, tmp2, len,
1198240005Szont				    VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
1199181061Sdes					break;
1200181061Sdes				len--;
1201181061Sdes				truncated = 1;
1202298089Spfg			}
1203286913Sjhb			fprintf(fp, "\"%s\"%s", tmp3, truncated ?
1204240005Szont			    "..." : "");
1205181061Sdes			free(tmp3);
1206181061Sdes		} else {
1207286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1208181061Sdes		}
1209181061Sdes		break;
1210181061Sdes	}
1211286963Sjhb	case ExecArgs:
1212286963Sjhb	case ExecEnv:
1213181061Sdes	case StringArray: {
1214286962Sjhb		uintptr_t addr;
1215286962Sjhb		union {
1216286962Sjhb			char *strarray[0];
1217286962Sjhb			char buf[PAGE_SIZE];
1218286962Sjhb		} u;
1219181061Sdes		char *string;
1220286962Sjhb		size_t len;
1221288424Sjhb		u_int first, i;
1222101289Smdodd
1223286962Sjhb		/*
1224286963Sjhb		 * Only parse argv[] and environment arrays from exec calls
1225286963Sjhb		 * if requested.
1226286963Sjhb		 */
1227286963Sjhb		if (((sc->type & ARG_MASK) == ExecArgs &&
1228286963Sjhb		    (trussinfo->flags & EXECVEARGS) == 0) ||
1229286963Sjhb		    ((sc->type & ARG_MASK) == ExecEnv &&
1230286963Sjhb		    (trussinfo->flags & EXECVEENVS) == 0)) {
1231286963Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1232286963Sjhb			break;
1233286963Sjhb		}
1234288406Sjhb
1235286963Sjhb		/*
1236286962Sjhb		 * Read a page of pointers at a time.  Punt if the top-level
1237286962Sjhb		 * pointer is not aligned.  Note that the first read is of
1238286962Sjhb		 * a partial page.
1239286962Sjhb		 */
1240286962Sjhb		addr = args[sc->offset];
1241286962Sjhb		if (addr % sizeof(char *) != 0) {
1242286962Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1243286962Sjhb			break;
1244286962Sjhb		}
1245101289Smdodd
1246286962Sjhb		len = PAGE_SIZE - (addr & PAGE_MASK);
1247286962Sjhb		if (get_struct(pid, (void *)addr, u.buf, len) == -1) {
1248286962Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1249286962Sjhb			break;
1250181061Sdes		}
1251181061Sdes
1252286962Sjhb		fputc('[', fp);
1253286962Sjhb		first = 1;
1254286962Sjhb		i = 0;
1255286962Sjhb		while (u.strarray[i] != NULL) {
1256286962Sjhb			string = get_string(pid, u.strarray[i], 0);
1257286962Sjhb			fprintf(fp, "%s \"%s\"", first ? "" : ",", string);
1258181061Sdes			free(string);
1259286962Sjhb			first = 0;
1260286962Sjhb
1261286962Sjhb			i++;
1262286962Sjhb			if (i == len / sizeof(char *)) {
1263286962Sjhb				addr += len;
1264286962Sjhb				len = PAGE_SIZE;
1265286962Sjhb				if (get_struct(pid, (void *)addr, u.buf, len) ==
1266286962Sjhb				    -1) {
1267286962Sjhb					fprintf(fp, ", <inval>");
1268286962Sjhb					break;
1269286962Sjhb				}
1270286962Sjhb				i = 0;
1271286962Sjhb			}
1272181061Sdes		}
1273286962Sjhb		fputs(" ]", fp);
1274181061Sdes		break;
1275181061Sdes	}
1276134799Smarcel#ifdef __LP64__
1277181061Sdes	case Quad:
1278288455Sjhb		fprintf(fp, "%ld", args[sc->offset]);
1279288455Sjhb		break;
1280288455Sjhb	case QuadHex:
1281286913Sjhb		fprintf(fp, "0x%lx", args[sc->offset]);
1282181061Sdes		break;
1283134799Smarcel#else
1284288455Sjhb	case Quad:
1285288455Sjhb	case QuadHex: {
1286181061Sdes		unsigned long long ll;
1287286938Sjhb
1288288424Sjhb#if _BYTE_ORDER == _LITTLE_ENDIAN
1289288424Sjhb		ll = (unsigned long long)args[sc->offset + 1] << 32 |
1290288424Sjhb		    args[sc->offset];
1291288424Sjhb#else
1292288424Sjhb		ll = (unsigned long long)args[sc->offset] << 32 |
1293288424Sjhb		    args[sc->offset + 1];
1294288424Sjhb#endif
1295288455Sjhb		if ((sc->type & ARG_MASK) == Quad)
1296288455Sjhb			fprintf(fp, "%lld", ll);
1297288455Sjhb		else
1298288455Sjhb			fprintf(fp, "0x%llx", ll);
1299181061Sdes		break;
1300181061Sdes	}
1301134799Smarcel#endif
1302181061Sdes	case Ptr:
1303286913Sjhb		fprintf(fp, "0x%lx", args[sc->offset]);
1304181061Sdes		break;
1305181061Sdes	case Readlinkres: {
1306181061Sdes		char *tmp2;
1307286938Sjhb
1308288424Sjhb		if (retval[0] == -1)
1309181061Sdes			break;
1310288424Sjhb		tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
1311286913Sjhb		fprintf(fp, "\"%s\"", tmp2);
1312181061Sdes		free(tmp2);
1313181061Sdes		break;
1314181061Sdes	}
1315181061Sdes	case Ioctl: {
1316286938Sjhb		const char *temp;
1317286938Sjhb		unsigned long cmd;
1318286938Sjhb
1319286938Sjhb		cmd = args[sc->offset];
1320292622Sjhb		temp = sysdecode_ioctlname(cmd);
1321240005Szont		if (temp)
1322286913Sjhb			fputs(temp, fp);
1323240005Szont		else {
1324286913Sjhb			fprintf(fp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
1325286938Sjhb			    cmd, cmd & IOC_OUT ? "R" : "",
1326286938Sjhb			    cmd & IOC_IN ? "W" : "", IOCGROUP(cmd),
1327286938Sjhb			    isprint(IOCGROUP(cmd)) ? (char)IOCGROUP(cmd) : '?',
1328286938Sjhb			    cmd & 0xFF, IOCPARM_LEN(cmd));
1329181061Sdes		}
1330181061Sdes		break;
1331181061Sdes	}
1332181061Sdes	case Timespec: {
1333181061Sdes		struct timespec ts;
1334286938Sjhb
1335240005Szont		if (get_struct(pid, (void *)args[sc->offset], &ts,
1336240005Szont		    sizeof(ts)) != -1)
1337286939Sjhb			fprintf(fp, "{ %jd.%09ld }", (intmax_t)ts.tv_sec,
1338240005Szont			    ts.tv_nsec);
1339181061Sdes		else
1340286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1341181061Sdes		break;
1342181061Sdes	}
1343286381Sjhb	case Timespec2: {
1344286381Sjhb		struct timespec ts[2];
1345286381Sjhb		const char *sep;
1346286381Sjhb		unsigned int i;
1347286381Sjhb
1348286381Sjhb		if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts))
1349286381Sjhb		    != -1) {
1350286388Sjhb			fputs("{ ", fp);
1351286381Sjhb			sep = "";
1352286381Sjhb			for (i = 0; i < nitems(ts); i++) {
1353286381Sjhb				fputs(sep, fp);
1354286381Sjhb				sep = ", ";
1355286381Sjhb				switch (ts[i].tv_nsec) {
1356286381Sjhb				case UTIME_NOW:
1357286381Sjhb					fprintf(fp, "UTIME_NOW");
1358286381Sjhb					break;
1359286381Sjhb				case UTIME_OMIT:
1360286381Sjhb					fprintf(fp, "UTIME_OMIT");
1361286381Sjhb					break;
1362286381Sjhb				default:
1363286939Sjhb					fprintf(fp, "%jd.%09ld",
1364286939Sjhb					    (intmax_t)ts[i].tv_sec,
1365286939Sjhb					    ts[i].tv_nsec);
1366286381Sjhb					break;
1367286381Sjhb				}
1368286381Sjhb			}
1369286388Sjhb			fputs(" }", fp);
1370286381Sjhb		} else
1371286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1372286381Sjhb		break;
1373286381Sjhb	}
1374181061Sdes	case Timeval: {
1375181061Sdes		struct timeval tv;
1376286938Sjhb
1377240005Szont		if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1378240005Szont		    != -1)
1379286939Sjhb			fprintf(fp, "{ %jd.%06ld }", (intmax_t)tv.tv_sec,
1380240005Szont			    tv.tv_usec);
1381181061Sdes		else
1382286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1383181061Sdes		break;
1384181061Sdes	}
1385181061Sdes	case Timeval2: {
1386181061Sdes		struct timeval tv[2];
1387286938Sjhb
1388240005Szont		if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
1389240005Szont		    != -1)
1390286939Sjhb			fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1391286939Sjhb			    (intmax_t)tv[0].tv_sec, tv[0].tv_usec,
1392286939Sjhb			    (intmax_t)tv[1].tv_sec, tv[1].tv_usec);
1393181061Sdes		else
1394286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1395181061Sdes		break;
1396181061Sdes	}
1397181061Sdes	case Itimerval: {
1398181061Sdes		struct itimerval itv;
1399286938Sjhb
1400240005Szont		if (get_struct(pid, (void *)args[sc->offset], &itv,
1401240005Szont		    sizeof(itv)) != -1)
1402286939Sjhb			fprintf(fp, "{ %jd.%06ld, %jd.%06ld }",
1403286939Sjhb			    (intmax_t)itv.it_interval.tv_sec,
1404181061Sdes			    itv.it_interval.tv_usec,
1405286939Sjhb			    (intmax_t)itv.it_value.tv_sec,
1406181061Sdes			    itv.it_value.tv_usec);
1407181061Sdes		else
1408286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1409181061Sdes		break;
1410181061Sdes	}
1411264881Ssmh	case LinuxSockArgs:
1412264881Ssmh	{
1413264881Ssmh		struct linux_socketcall_args largs;
1414286938Sjhb
1415264881Ssmh		if (get_struct(pid, (void *)args[sc->offset], (void *)&largs,
1416286857Sjhb		    sizeof(largs)) != -1)
1417286913Sjhb			fprintf(fp, "{ %s, 0x%lx }",
1418286857Sjhb			    lookup(linux_socketcall_ops, largs.what, 10),
1419286857Sjhb			    (long unsigned int)largs.args);
1420286857Sjhb		else
1421286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1422264881Ssmh		break;
1423264881Ssmh	}
1424181061Sdes	case Pollfd: {
1425181061Sdes		/*
1426240005Szont		 * XXX: A Pollfd argument expects the /next/ syscall argument
1427240005Szont		 * to be the number of fds in the array. This matches the poll
1428240005Szont		 * syscall.
1429181061Sdes		 */
1430181061Sdes		struct pollfd *pfd;
1431286913Sjhb		int numfds = args[sc->offset + 1];
1432286913Sjhb		size_t bytes = sizeof(struct pollfd) * numfds;
1433286913Sjhb		int i;
1434127332Sdwmalone
1435181061Sdes		if ((pfd = malloc(bytes)) == NULL)
1436286913Sjhb			err(1, "Cannot malloc %zu bytes for pollfd array",
1437240005Szont			    bytes);
1438240005Szont		if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
1439240005Szont		    != -1) {
1440286913Sjhb			fputs("{", fp);
1441181061Sdes			for (i = 0; i < numfds; i++) {
1442286913Sjhb				fprintf(fp, " %d/%s", pfd[i].fd,
1443240005Szont				    xlookup_bits(poll_flags, pfd[i].events));
1444181061Sdes			}
1445286913Sjhb			fputs(" }", fp);
1446181061Sdes		} else {
1447286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1448181061Sdes		}
1449181061Sdes		free(pfd);
1450181061Sdes		break;
1451127332Sdwmalone	}
1452181061Sdes	case Fd_set: {
1453181061Sdes		/*
1454240005Szont		 * XXX: A Fd_set argument expects the /first/ syscall argument
1455240005Szont		 * to be the number of fds in the array.  This matches the
1456240005Szont		 * select syscall.
1457181061Sdes		 */
1458181061Sdes		fd_set *fds;
1459181061Sdes		int numfds = args[0];
1460286913Sjhb		size_t bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
1461286913Sjhb		int i;
1462127332Sdwmalone
1463181061Sdes		if ((fds = malloc(bytes)) == NULL)
1464286913Sjhb			err(1, "Cannot malloc %zu bytes for fd_set array",
1465240005Szont			    bytes);
1466240005Szont		if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
1467240005Szont		    != -1) {
1468286913Sjhb			fputs("{", fp);
1469181061Sdes			for (i = 0; i < numfds; i++) {
1470286913Sjhb				if (FD_ISSET(i, fds))
1471286913Sjhb					fprintf(fp, " %d", i);
1472181061Sdes			}
1473286913Sjhb			fputs(" }", fp);
1474240005Szont		} else
1475286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1476181061Sdes		free(fds);
1477181061Sdes		break;
1478127332Sdwmalone	}
1479255493Sjhb	case Signal:
1480286913Sjhb		fputs(strsig2(args[sc->offset]), fp);
1481181061Sdes		break;
1482181061Sdes	case Sigset: {
1483181061Sdes		long sig;
1484181061Sdes		sigset_t ss;
1485286913Sjhb		int i, first;
1486158630Spav
1487181061Sdes		sig = args[sc->offset];
1488240005Szont		if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
1489240005Szont		    sizeof(ss)) == -1) {
1490286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1491181061Sdes			break;
1492181061Sdes		}
1493286913Sjhb		fputs("{ ", fp);
1494286913Sjhb		first = 1;
1495181061Sdes		for (i = 1; i < sys_nsig; i++) {
1496255493Sjhb			if (sigismember(&ss, i)) {
1497286913Sjhb				fprintf(fp, "%s%s", !first ? "|" : "",
1498286913Sjhb				    strsig(i));
1499286913Sjhb				first = 0;
1500255493Sjhb			}
1501181061Sdes		}
1502286913Sjhb		if (!first)
1503286913Sjhb			fputc(' ', fp);
1504286913Sjhb		fputc('}', fp);
1505181061Sdes		break;
1506181061Sdes	}
1507181061Sdes	case Sigprocmask: {
1508286913Sjhb		fputs(xlookup(sigprocmask_ops, args[sc->offset]), fp);
1509181061Sdes		break;
1510127328Salfred	}
1511181061Sdes	case Fcntlflag: {
1512286938Sjhb		/* XXX: Output depends on the value of the previous argument. */
1513286938Sjhb		switch (args[sc->offset - 1]) {
1514181061Sdes		case F_SETFD:
1515286913Sjhb			fputs(xlookup_bits(fcntlfd_arg, args[sc->offset]), fp);
1516181061Sdes			break;
1517181061Sdes		case F_SETFL:
1518286913Sjhb			fputs(xlookup_bits(fcntlfl_arg, args[sc->offset]), fp);
1519181061Sdes			break;
1520181061Sdes		case F_GETFD:
1521181061Sdes		case F_GETFL:
1522181061Sdes		case F_GETOWN:
1523181061Sdes			break;
1524181061Sdes		default:
1525286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1526181061Sdes			break;
1527181061Sdes		}
1528181061Sdes		break;
1529181061Sdes	}
1530181061Sdes	case Open:
1531286913Sjhb		fputs(xlookup_bits(open_flags, args[sc->offset]), fp);
1532181061Sdes		break;
1533181061Sdes	case Fcntl:
1534286913Sjhb		fputs(xlookup(fcntl_arg, args[sc->offset]), fp);
1535181061Sdes		break;
1536181061Sdes	case Mprot:
1537286913Sjhb		fputs(xlookup_bits(mprot_flags, args[sc->offset]), fp);
1538181061Sdes		break;
1539254430Sjhb	case Mmapflags: {
1540254430Sjhb		int align, flags;
1541254430Sjhb
1542254430Sjhb		/*
1543254430Sjhb		 * MAP_ALIGNED can't be handled by xlookup_bits(), so
1544254430Sjhb		 * generate that string manually and prepend it to the
1545254430Sjhb		 * string from xlookup_bits().  Have to be careful to
1546254430Sjhb		 * avoid outputting MAP_ALIGNED|0 if MAP_ALIGNED is
1547254430Sjhb		 * the only flag.
1548254430Sjhb		 */
1549254430Sjhb		flags = args[sc->offset] & ~MAP_ALIGNMENT_MASK;
1550254430Sjhb		align = args[sc->offset] & MAP_ALIGNMENT_MASK;
1551254430Sjhb		if (align != 0) {
1552254430Sjhb			if (align == MAP_ALIGNED_SUPER)
1553286913Sjhb				fputs("MAP_ALIGNED_SUPER", fp);
1554254430Sjhb			else
1555286913Sjhb				fprintf(fp, "MAP_ALIGNED(%d)",
1556254430Sjhb				    align >> MAP_ALIGNMENT_SHIFT);
1557286913Sjhb			if (flags == 0)
1558254430Sjhb				break;
1559286913Sjhb			fputc('|', fp);
1560254430Sjhb		}
1561286913Sjhb		fputs(xlookup_bits(mmap_flags, flags), fp);
1562181061Sdes		break;
1563254430Sjhb	}
1564181061Sdes	case Whence:
1565286913Sjhb		fputs(xlookup(whence_arg, args[sc->offset]), fp);
1566181061Sdes		break;
1567181061Sdes	case Sockdomain:
1568286913Sjhb		fputs(xlookup(sockdomain_arg, args[sc->offset]), fp);
1569181061Sdes		break;
1570286849Sjhb	case Socktype: {
1571286849Sjhb		int type, flags;
1572286849Sjhb
1573286849Sjhb		flags = args[sc->offset] & (SOCK_CLOEXEC | SOCK_NONBLOCK);
1574286849Sjhb		type = args[sc->offset] & ~flags;
1575286849Sjhb		fputs(xlookup(socktype_arg, type), fp);
1576286849Sjhb		if (flags & SOCK_CLOEXEC)
1577286849Sjhb			fprintf(fp, "|SOCK_CLOEXEC");
1578286849Sjhb		if (flags & SOCK_NONBLOCK)
1579286849Sjhb			fprintf(fp, "|SOCK_NONBLOCK");
1580181061Sdes		break;
1581286849Sjhb	}
1582181061Sdes	case Shutdown:
1583286913Sjhb		fputs(xlookup(shutdown_arg, args[sc->offset]), fp);
1584181061Sdes		break;
1585181061Sdes	case Resource:
1586286913Sjhb		fputs(xlookup(resource_arg, args[sc->offset]), fp);
1587181061Sdes		break;
1588181061Sdes	case Pathconf:
1589286913Sjhb		fputs(xlookup(pathconf_arg, args[sc->offset]), fp);
1590181061Sdes		break;
1591253850Smarkj	case Rforkflags:
1592286913Sjhb		fputs(xlookup_bits(rfork_flags, args[sc->offset]), fp);
1593253850Smarkj		break;
1594181061Sdes	case Sockaddr: {
1595181061Sdes		char addr[64];
1596181061Sdes		struct sockaddr_in *lsin;
1597181061Sdes		struct sockaddr_in6 *lsin6;
1598181061Sdes		struct sockaddr_un *sun;
1599181061Sdes		struct sockaddr *sa;
1600288456Sjhb		socklen_t len;
1601181061Sdes		u_char *q;
160285292Sdes
1603181061Sdes		if (args[sc->offset] == 0) {
1604286913Sjhb			fputs("NULL", fp);
1605181061Sdes			break;
1606181061Sdes		}
1607121606Smarcel
1608181061Sdes		/*
1609288456Sjhb		 * Extract the address length from the next argument.  If
1610288456Sjhb		 * this is an output sockaddr (OUT is set), then the
1611288456Sjhb		 * next argument is a pointer to a socklen_t.  Otherwise
1612288456Sjhb		 * the next argument contains a socklen_t by value.
1613181061Sdes		 */
1614288456Sjhb		if (sc->type & OUT) {
1615288456Sjhb			if (get_struct(pid, (void *)args[sc->offset + 1],
1616288456Sjhb			    &len, sizeof(len)) == -1) {
1617288456Sjhb				fprintf(fp, "0x%lx", args[sc->offset]);
1618181061Sdes				break;
1619181061Sdes			}
1620288456Sjhb		} else
1621288456Sjhb			len = args[sc->offset + 1];
1622288456Sjhb
1623288456Sjhb		/* If the length is too small, just bail. */
1624288456Sjhb		if (len < sizeof(*sa)) {
1625288456Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1626288456Sjhb			break;
1627181061Sdes		}
1628288456Sjhb
1629288456Sjhb		sa = calloc(1, len);
1630288456Sjhb		if (get_struct(pid, (void *)args[sc->offset], sa, len) == -1) {
1631288456Sjhb			free(sa);
1632286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1633286913Sjhb			break;
1634181061Sdes		}
163585292Sdes
1636288456Sjhb		switch (sa->sa_family) {
1637181061Sdes		case AF_INET:
1638288456Sjhb			if (len < sizeof(*lsin))
1639288456Sjhb				goto sockaddr_short;
1640288456Sjhb			lsin = (struct sockaddr_in *)(void *)sa;
1641286938Sjhb			inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof(addr));
1642286913Sjhb			fprintf(fp, "{ AF_INET %s:%d }", addr,
1643240005Szont			    htons(lsin->sin_port));
1644181061Sdes			break;
1645181061Sdes		case AF_INET6:
1646288456Sjhb			if (len < sizeof(*lsin6))
1647288456Sjhb				goto sockaddr_short;
1648288456Sjhb			lsin6 = (struct sockaddr_in6 *)(void *)sa;
1649240005Szont			inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
1650286938Sjhb			    sizeof(addr));
1651286913Sjhb			fprintf(fp, "{ AF_INET6 [%s]:%d }", addr,
1652240005Szont			    htons(lsin6->sin6_port));
1653181061Sdes			break;
1654181061Sdes		case AF_UNIX:
1655288456Sjhb			sun = (struct sockaddr_un *)sa;
1656288456Sjhb			fprintf(fp, "{ AF_UNIX \"%.*s\" }",
1657288456Sjhb			    (int)(len - offsetof(struct sockaddr_un, sun_path)),
1658288456Sjhb			    sun->sun_path);
1659181061Sdes			break;
1660181061Sdes		default:
1661288456Sjhb		sockaddr_short:
1662286913Sjhb			fprintf(fp,
1663286913Sjhb			    "{ sa_len = %d, sa_family = %d, sa_data = {",
1664286913Sjhb			    (int)sa->sa_len, (int)sa->sa_family);
1665286913Sjhb			for (q = (u_char *)sa->sa_data;
1666288456Sjhb			     q < (u_char *)sa + len; q++)
1667286913Sjhb				fprintf(fp, "%s 0x%02x",
1668286913Sjhb				    q == (u_char *)sa->sa_data ? "" : ",",
1669286913Sjhb				    *q);
1670286913Sjhb			fputs(" } }", fp);
1671181061Sdes		}
1672288456Sjhb		free(sa);
1673181061Sdes		break;
167486138Sgreen	}
1675181061Sdes	case Sigaction: {
1676181061Sdes		struct sigaction sa;
1677127332Sdwmalone
1678240005Szont		if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
1679240005Szont		    != -1) {
1680286913Sjhb			fputs("{ ", fp);
1681181061Sdes			if (sa.sa_handler == SIG_DFL)
1682286913Sjhb				fputs("SIG_DFL", fp);
1683181061Sdes			else if (sa.sa_handler == SIG_IGN)
1684286913Sjhb				fputs("SIG_IGN", fp);
1685181061Sdes			else
1686286913Sjhb				fprintf(fp, "%p", sa.sa_handler);
1687286913Sjhb			fprintf(fp, " %s ss_t }",
1688181061Sdes			    xlookup_bits(sigaction_flags, sa.sa_flags));
1689240005Szont		} else
1690286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1691181061Sdes		break;
1692181061Sdes	}
1693181061Sdes	case Kevent: {
1694181061Sdes		/*
1695286938Sjhb		 * XXX XXX: The size of the array is determined by either the
1696286938Sjhb		 * next syscall argument, or by the syscall return value,
1697181061Sdes		 * depending on which argument number we are.  This matches the
1698181061Sdes		 * kevent syscall, but luckily that's the only syscall that uses
1699181061Sdes		 * them.
1700181061Sdes		 */
1701181061Sdes		struct kevent *ke;
1702181061Sdes		int numevents = -1;
1703286913Sjhb		size_t bytes;
1704286913Sjhb		int i;
1705158630Spav
1706181061Sdes		if (sc->offset == 1)
1707181061Sdes			numevents = args[sc->offset+1];
1708288424Sjhb		else if (sc->offset == 3 && retval[0] != -1)
1709288424Sjhb			numevents = retval[0];
1710158630Spav
1711286913Sjhb		if (numevents >= 0) {
1712181061Sdes			bytes = sizeof(struct kevent) * numevents;
1713286913Sjhb			if ((ke = malloc(bytes)) == NULL)
1714286913Sjhb				err(1,
1715286913Sjhb				    "Cannot malloc %zu bytes for kevent array",
1716286913Sjhb				    bytes);
1717286913Sjhb		} else
1718286913Sjhb			ke = NULL;
1719240005Szont		if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
1720240005Szont		    ke, bytes) != -1) {
1721286913Sjhb			fputc('{', fp);
1722286914Sjhb			for (i = 0; i < numevents; i++) {
1723286914Sjhb				fputc(' ', fp);
1724286914Sjhb				print_kevent(fp, &ke[i], sc->offset == 1);
1725286914Sjhb			}
1726286913Sjhb			fputs(" }", fp);
1727181061Sdes		} else {
1728286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1729181061Sdes		}
1730181061Sdes		free(ke);
1731181061Sdes		break;
1732158630Spav	}
1733181061Sdes	case Stat: {
1734181061Sdes		struct stat st;
1735286938Sjhb
1736240005Szont		if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
1737240005Szont		    != -1) {
1738181061Sdes			char mode[12];
1739286938Sjhb
1740181061Sdes			strmode(st.st_mode, mode);
1741286913Sjhb			fprintf(fp,
1742286940Sjhb			    "{ mode=%s,inode=%ju,size=%jd,blksize=%ld }", mode,
1743286940Sjhb			    (uintmax_t)st.st_ino, (intmax_t)st.st_size,
1744240005Szont			    (long)st.st_blksize);
1745181061Sdes		} else {
1746286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1747181061Sdes		}
1748181061Sdes		break;
1749181061Sdes	}
1750288625Sbdrewery	case StatFs: {
1751288625Sbdrewery		unsigned int i;
1752288625Sbdrewery		struct statfs buf;
1753288626Sbdrewery
1754288625Sbdrewery		if (get_struct(pid, (void *)args[sc->offset], &buf,
1755288625Sbdrewery		    sizeof(buf)) != -1) {
1756288625Sbdrewery			char fsid[17];
1757288625Sbdrewery
1758288625Sbdrewery			bzero(fsid, sizeof(fsid));
1759288625Sbdrewery			if (buf.f_fsid.val[0] != 0 || buf.f_fsid.val[1] != 0) {
1760288625Sbdrewery			        for (i = 0; i < sizeof(buf.f_fsid); i++)
1761288625Sbdrewery					snprintf(&fsid[i*2],
1762288625Sbdrewery					    sizeof(fsid) - (i*2), "%02x",
1763288625Sbdrewery					    ((u_char *)&buf.f_fsid)[i]);
1764288625Sbdrewery			}
1765288625Sbdrewery			fprintf(fp,
1766288625Sbdrewery			    "{ fstypename=%s,mntonname=%s,mntfromname=%s,"
1767288625Sbdrewery			    "fsid=%s }", buf.f_fstypename, buf.f_mntonname,
1768288625Sbdrewery			    buf.f_mntfromname, fsid);
1769288625Sbdrewery		} else
1770288625Sbdrewery			fprintf(fp, "0x%lx", args[sc->offset]);
1771288625Sbdrewery		break;
1772288625Sbdrewery	}
1773288625Sbdrewery
1774181061Sdes	case Rusage: {
1775181061Sdes		struct rusage ru;
1776286938Sjhb
1777240005Szont		if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
1778240005Szont		    != -1) {
1779286913Sjhb			fprintf(fp,
1780286939Sjhb			    "{ u=%jd.%06ld,s=%jd.%06ld,in=%ld,out=%ld }",
1781286939Sjhb			    (intmax_t)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
1782286939Sjhb			    (intmax_t)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
1783181061Sdes			    ru.ru_inblock, ru.ru_oublock);
1784240005Szont		} else
1785286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1786181061Sdes		break;
1787181061Sdes	}
1788181061Sdes	case Rlimit: {
1789181061Sdes		struct rlimit rl;
1790286938Sjhb
1791240005Szont		if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
1792240005Szont		    != -1) {
1793286913Sjhb			fprintf(fp, "{ cur=%ju,max=%ju }",
1794181061Sdes			    rl.rlim_cur, rl.rlim_max);
1795240005Szont		} else
1796286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1797181061Sdes		break;
1798181061Sdes	}
1799255493Sjhb	case ExitStatus: {
1800255493Sjhb		int status;
1801286913Sjhb
1802255493Sjhb		if (get_struct(pid, (void *)args[sc->offset], &status,
1803255493Sjhb		    sizeof(status)) != -1) {
1804286913Sjhb			fputs("{ ", fp);
1805255493Sjhb			if (WIFCONTINUED(status))
1806286913Sjhb				fputs("CONTINUED", fp);
1807255493Sjhb			else if (WIFEXITED(status))
1808286913Sjhb				fprintf(fp, "EXITED,val=%d",
1809255493Sjhb				    WEXITSTATUS(status));
1810255493Sjhb			else if (WIFSIGNALED(status))
1811286913Sjhb				fprintf(fp, "SIGNALED,sig=%s%s",
1812286913Sjhb				    strsig2(WTERMSIG(status)),
1813255493Sjhb				    WCOREDUMP(status) ? ",cored" : "");
1814255493Sjhb			else
1815286913Sjhb				fprintf(fp, "STOPPED,sig=%s",
1816286913Sjhb				    strsig2(WTERMSIG(status)));
1817286913Sjhb			fputs(" }", fp);
1818255493Sjhb		} else
1819286913Sjhb			fprintf(fp, "0x%lx", args[sc->offset]);
1820255493Sjhb		break;
1821255493Sjhb	}
1822255493Sjhb	case Waitoptions:
1823286913Sjhb		fputs(xlookup_bits(wait_options, args[sc->offset]), fp);
1824255493Sjhb		break;
1825255493Sjhb	case Idtype:
1826286913Sjhb		fputs(xlookup(idtype_arg, args[sc->offset]), fp);
1827255493Sjhb		break;
1828255708Sjhb	case Procctl:
1829286913Sjhb		fputs(xlookup(procctl_arg, args[sc->offset]), fp);
1830255708Sjhb		break;
1831273053Sjhb	case Umtxop:
1832286913Sjhb		fputs(xlookup(umtx_ops, args[sc->offset]), fp);
1833273053Sjhb		break;
1834286381Sjhb	case Atfd:
1835286381Sjhb		if ((int)args[sc->offset] == AT_FDCWD)
1836286913Sjhb			fputs("AT_FDCWD", fp);
1837286381Sjhb		else
1838286913Sjhb			fprintf(fp, "%d", (int)args[sc->offset]);
1839286381Sjhb		break;
1840286381Sjhb	case Atflags:
1841286913Sjhb		fputs(xlookup_bits(at_flags, args[sc->offset]), fp);
1842286381Sjhb		break;
1843286381Sjhb	case Accessmode:
1844286381Sjhb		if (args[sc->offset] == F_OK)
1845286913Sjhb			fputs("F_OK", fp);
1846286381Sjhb		else
1847286913Sjhb			fputs(xlookup_bits(access_modes, args[sc->offset]), fp);
1848286381Sjhb		break;
1849286848Sjhb	case Sysarch:
1850286913Sjhb		fputs(xlookup(sysarch_ops, args[sc->offset]), fp);
1851286848Sjhb		break;
1852288424Sjhb	case PipeFds:
1853288424Sjhb		/*
1854288424Sjhb		 * The pipe() system call in the kernel returns its
1855288424Sjhb		 * two file descriptors via return values.  However,
1856288424Sjhb		 * the interface exposed by libc is that pipe()
1857288424Sjhb		 * accepts a pointer to an array of descriptors.
1858288424Sjhb		 * Format the output to match the libc API by printing
1859288424Sjhb		 * the returned file descriptors as a fake argument.
1860288424Sjhb		 *
1861288424Sjhb		 * Overwrite the first retval to signal a successful
1862288424Sjhb		 * return as well.
1863288424Sjhb		 */
1864288424Sjhb		fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
1865288424Sjhb		retval[0] = 0;
1866288424Sjhb		break;
1867288957Sbdrewery	case Utrace: {
1868288957Sbdrewery		size_t len;
1869288957Sbdrewery		void *utrace_addr;
1870288957Sbdrewery
1871288957Sbdrewery		len = args[sc->offset + 1];
1872288957Sbdrewery		utrace_addr = calloc(1, len);
1873288957Sbdrewery		if (get_struct(pid, (void *)args[sc->offset],
1874288957Sbdrewery		    (void *)utrace_addr, len) != -1)
1875288957Sbdrewery			print_utrace(fp, utrace_addr, len);
1876288957Sbdrewery		else
1877288957Sbdrewery			fprintf(fp, "0x%lx", args[sc->offset]);
1878288957Sbdrewery		free(utrace_addr);
1879288957Sbdrewery		break;
1880288957Sbdrewery	}
1881289004Sed	case IntArray: {
1882289004Sed		int descriptors[16];
1883289004Sed		unsigned long i, ndescriptors;
1884289004Sed		bool truncated;
1885289004Sed
1886289004Sed		ndescriptors = args[sc->offset + 1];
1887289004Sed		truncated = false;
1888289004Sed		if (ndescriptors > nitems(descriptors)) {
1889289004Sed			ndescriptors = nitems(descriptors);
1890289004Sed			truncated = true;
1891289004Sed		}
1892289004Sed		if (get_struct(pid, (void *)args[sc->offset],
1893289004Sed		    descriptors, ndescriptors * sizeof(descriptors[0])) != -1) {
1894289004Sed			fprintf(fp, "{");
1895289004Sed			for (i = 0; i < ndescriptors; i++)
1896289004Sed				fprintf(fp, i == 0 ? " %d" : ", %d",
1897289004Sed				    descriptors[i]);
1898289004Sed			fprintf(fp, truncated ? ", ... }" : " }");
1899289004Sed		} else
1900289004Sed			fprintf(fp, "0x%lx", args[sc->offset]);
1901289004Sed		break;
1902289004Sed	}
1903289004Sed
1904289004Sed	case CloudABIAdvice:
1905289004Sed		fputs(xlookup(cloudabi_advice, args[sc->offset]), fp);
1906289004Sed		break;
1907289004Sed	case CloudABIClockID:
1908289004Sed		fputs(xlookup(cloudabi_clockid, args[sc->offset]), fp);
1909289004Sed		break;
1910289004Sed	case ClouduABIFDSFlags:
1911289004Sed		fputs(xlookup_bits(cloudabi_fdsflags, args[sc->offset]), fp);
1912289004Sed		break;
1913289004Sed	case CloudABIFDStat: {
1914289004Sed		cloudabi_fdstat_t fds;
1915289004Sed		if (get_struct(pid, (void *)args[sc->offset], &fds, sizeof(fds))
1916289004Sed		    != -1) {
1917289004Sed			fprintf(fp, "{ %s, ",
1918289004Sed			    xlookup(cloudabi_filetype, fds.fs_filetype));
1919289004Sed			fprintf(fp, "%s, ... }",
1920289004Sed			    xlookup_bits(cloudabi_fdflags, fds.fs_flags));
1921289004Sed		} else
1922289004Sed			fprintf(fp, "0x%lx", args[sc->offset]);
1923289004Sed		break;
1924289004Sed	}
1925289004Sed	case CloudABIFileStat: {
1926289004Sed		cloudabi_filestat_t fsb;
1927289004Sed		if (get_struct(pid, (void *)args[sc->offset], &fsb, sizeof(fsb))
1928289004Sed		    != -1)
1929289004Sed			fprintf(fp, "{ %s, %lu }",
1930289004Sed			    xlookup(cloudabi_filetype, fsb.st_filetype),
1931289004Sed			    fsb.st_size);
1932289004Sed		else
1933289004Sed			fprintf(fp, "0x%lx", args[sc->offset]);
1934289004Sed		break;
1935289004Sed	}
1936289004Sed	case CloudABIFileType:
1937289004Sed		fputs(xlookup(cloudabi_filetype, args[sc->offset]), fp);
1938289004Sed		break;
1939289004Sed	case CloudABIFSFlags:
1940289004Sed		fputs(xlookup_bits(cloudabi_fsflags, args[sc->offset]), fp);
1941289004Sed		break;
1942289004Sed	case CloudABILookup:
1943289004Sed		if ((args[sc->offset] & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0)
1944289004Sed			fprintf(fp, "%d|LOOKUP_SYMLINK_FOLLOW",
1945289004Sed			    (int)args[sc->offset]);
1946289004Sed		else
1947289004Sed			fprintf(fp, "%d", (int)args[sc->offset]);
1948289004Sed		break;
1949289004Sed	case CloudABIMFlags:
1950289004Sed		fputs(xlookup_bits(cloudabi_mflags, args[sc->offset]), fp);
1951289004Sed		break;
1952289004Sed	case CloudABIMProt:
1953289004Sed		fputs(xlookup_bits(cloudabi_mprot, args[sc->offset]), fp);
1954289004Sed		break;
1955289004Sed	case CloudABIMSFlags:
1956289004Sed		fputs(xlookup_bits(cloudabi_msflags, args[sc->offset]), fp);
1957289004Sed		break;
1958289004Sed	case CloudABIOFlags:
1959289004Sed		fputs(xlookup_bits(cloudabi_oflags, args[sc->offset]), fp);
1960289004Sed		break;
1961289004Sed	case CloudABISDFlags:
1962289004Sed		fputs(xlookup_bits(cloudabi_sdflags, args[sc->offset]), fp);
1963289004Sed		break;
1964289004Sed	case CloudABISignal:
1965289004Sed		fputs(xlookup(cloudabi_signal, args[sc->offset]), fp);
1966289004Sed		break;
1967289004Sed	case CloudABISockStat: {
1968289004Sed		cloudabi_sockstat_t ss;
1969289004Sed		if (get_struct(pid, (void *)args[sc->offset], &ss, sizeof(ss))
1970289004Sed		    != -1) {
1971289004Sed			fprintf(fp, "{ %s, ", xlookup(
1972289004Sed			    cloudabi_sa_family, ss.ss_sockname.sa_family));
1973289004Sed			fprintf(fp, "%s, ", xlookup(
1974289004Sed			    cloudabi_sa_family, ss.ss_peername.sa_family));
1975289004Sed			fprintf(fp, "%s, ", xlookup(
1976289004Sed			    cloudabi_errno, ss.ss_error));
1977289004Sed			fprintf(fp, "%s }", xlookup_bits(
1978289004Sed			    cloudabi_ssstate, ss.ss_state));
1979289004Sed		} else
1980289004Sed			fprintf(fp, "0x%lx", args[sc->offset]);
1981289004Sed		break;
1982289004Sed	}
1983289004Sed	case CloudABISSFlags:
1984289004Sed		fputs(xlookup_bits(cloudabi_ssflags, args[sc->offset]), fp);
1985289004Sed		break;
1986289004Sed	case CloudABITimestamp:
1987289004Sed		fprintf(fp, "%lu.%09lus", args[sc->offset] / 1000000000,
1988289004Sed		    args[sc->offset] % 1000000000);
1989289004Sed		break;
1990289004Sed	case CloudABIULFlags:
1991289004Sed		fputs(xlookup_bits(cloudabi_ulflags, args[sc->offset]), fp);
1992289004Sed		break;
1993289004Sed	case CloudABIWhence:
1994289004Sed		fputs(xlookup(cloudabi_whence, args[sc->offset]), fp);
1995289004Sed		break;
1996289004Sed
1997181061Sdes	default:
1998181061Sdes		errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
1999181061Sdes	}
2000286913Sjhb	fclose(fp);
2001181061Sdes	return (tmp);
200231567Ssef}
200331567Ssef
200431567Ssef/*
2005295677Sjhb * Print (to outfile) the system call and its arguments.
200631567Ssef */
200731567Ssefvoid
2008295677Sjhbprint_syscall(struct trussinfo *trussinfo)
2009181061Sdes{
2010295677Sjhb	struct threadinfo *t;
2011295677Sjhb	const char *name;
2012295677Sjhb	char **s_args;
2013295677Sjhb	int i, len, nargs;
2014101283Smdodd
2015295677Sjhb	t = trussinfo->curthread;
2016101283Smdodd
2017295677Sjhb	name = t->cs.name;
2018295677Sjhb	nargs = t->cs.nargs;
2019295677Sjhb	s_args = t->cs.s_args;
2020101285Smdodd
2021295930Sjhb	len = print_line_prefix(trussinfo);
2022181061Sdes	len += fprintf(trussinfo->outfile, "%s(", name);
2023101283Smdodd
2024181061Sdes	for (i = 0; i < nargs; i++) {
2025295677Sjhb		if (s_args[i] != NULL)
2026181061Sdes			len += fprintf(trussinfo->outfile, "%s", s_args[i]);
2027181061Sdes		else
2028240005Szont			len += fprintf(trussinfo->outfile,
2029240005Szont			    "<missing argument>");
2030240005Szont		len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
2031240005Szont		    "," : "");
2032181061Sdes	}
2033181061Sdes	len += fprintf(trussinfo->outfile, ")");
2034181061Sdes	for (i = 0; i < 6 - (len / 8); i++)
2035181061Sdes		fprintf(trussinfo->outfile, "\t");
203631567Ssef}
203758224Ssef
203858224Ssefvoid
2039295677Sjhbprint_syscall_ret(struct trussinfo *trussinfo, int errorp, long *retval)
2040122348Smarcel{
2041192025Sdds	struct timespec timediff;
2042295677Sjhb	struct threadinfo *t;
2043295677Sjhb	struct syscall *sc;
2044295931Sjhb	int error;
2045181061Sdes
2046295677Sjhb	t = trussinfo->curthread;
2047295677Sjhb	sc = t->cs.sc;
2048192025Sdds	if (trussinfo->flags & COUNTONLY) {
2049295677Sjhb		timespecsubt(&t->after, &t->before, &timediff);
2050247338Sdelphij		timespecadd(&sc->time, &timediff, &sc->time);
2051192025Sdds		sc->ncalls++;
2052192025Sdds		if (errorp)
2053192025Sdds			sc->nerror++;
2054192025Sdds		return;
2055192025Sdds	}
2056192025Sdds
2057295677Sjhb	print_syscall(trussinfo);
2058181061Sdes	fflush(trussinfo->outfile);
2059296571Sjhb
2060296571Sjhb	if (retval == NULL) {
2061296571Sjhb		/*
2062296571Sjhb		 * This system call resulted in the current thread's exit,
2063296571Sjhb		 * so there is no return value or error to display.
2064296571Sjhb		 */
2065296571Sjhb		fprintf(trussinfo->outfile, "\n");
2066296571Sjhb		return;
2067296571Sjhb	}
2068296571Sjhb
2069295931Sjhb	if (errorp) {
2070295931Sjhb		error = sysdecode_abi_to_freebsd_errno(t->proc->abi->abi,
2071295931Sjhb		    retval[0]);
2072288424Sjhb		fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
2073295931Sjhb		    error == INT_MAX ? "Unknown error" : strerror(error));
2074295931Sjhb	}
2075288424Sjhb#ifndef __LP64__
2076288832Sbdrewery	else if (sc->ret_type == 2) {
2077288424Sjhb		off_t off;
2078288424Sjhb
2079288424Sjhb#if _BYTE_ORDER == _LITTLE_ENDIAN
2080288424Sjhb		off = (off_t)retval[1] << 32 | retval[0];
2081288424Sjhb#else
2082288424Sjhb		off = (off_t)retval[0] << 32 | retval[1];
2083288424Sjhb#endif
2084288424Sjhb		fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
2085288424Sjhb		    (intmax_t)off);
2086181061Sdes	}
2087288424Sjhb#endif
2088288424Sjhb	else
2089288424Sjhb		fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
2090288424Sjhb		    retval[0]);
209158224Ssef}
2092192025Sdds
2093192025Sddsvoid
2094192025Sddsprint_summary(struct trussinfo *trussinfo)
2095192025Sdds{
2096240005Szont	struct timespec total = {0, 0};
2097192025Sdds	struct syscall *sc;
2098192025Sdds	int ncall, nerror;
2099192025Sdds
2100192025Sdds	fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
2101240005Szont	    "syscall", "seconds", "calls", "errors");
2102192025Sdds	ncall = nerror = 0;
2103288832Sbdrewery	STAILQ_FOREACH(sc, &syscalls, entries)
2104192025Sdds		if (sc->ncalls) {
2105200781Sjh			fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2106200781Sjh			    sc->name, (intmax_t)sc->time.tv_sec,
2107200781Sjh			    sc->time.tv_nsec, sc->ncalls, sc->nerror);
2108247338Sdelphij			timespecadd(&total, &sc->time, &total);
2109192025Sdds			ncall += sc->ncalls;
2110192025Sdds			nerror += sc->nerror;
2111192025Sdds		}
2112192025Sdds	fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
2113240005Szont	    "", "-------------", "-------", "-------");
2114200781Sjh	fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
2115240005Szont	    "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);
2116192025Sdds}
2117