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