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