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