xref: /freebsd/usr.bin/truss/syscalls.c (revision d9dcc46365cf52a5902fde488e57e662ce715786)
1bbeaf6c0SSean Eric Fagan /*
20a6c71f8SWarner Losh  * Copyright 1997 Sean Eric Fagan
309d64da3SSean Eric Fagan  *
409d64da3SSean Eric Fagan  * Redistribution and use in source and binary forms, with or without
509d64da3SSean Eric Fagan  * modification, are permitted provided that the following conditions
609d64da3SSean Eric Fagan  * are met:
709d64da3SSean Eric Fagan  * 1. Redistributions of source code must retain the above copyright
809d64da3SSean Eric Fagan  *    notice, this list of conditions and the following disclaimer.
909d64da3SSean Eric Fagan  * 2. Redistributions in binary form must reproduce the above copyright
1009d64da3SSean Eric Fagan  *    notice, this list of conditions and the following disclaimer in the
1109d64da3SSean Eric Fagan  *    documentation and/or other materials provided with the distribution.
1209d64da3SSean Eric Fagan  * 3. All advertising materials mentioning features or use of this software
1309d64da3SSean Eric Fagan  *    must display the following acknowledgement:
1409d64da3SSean Eric Fagan  *	This product includes software developed by Sean Eric Fagan
1509d64da3SSean Eric Fagan  * 4. Neither the name of the author may be used to endorse or promote
1609d64da3SSean Eric Fagan  *    products derived from this software without specific prior written
1709d64da3SSean Eric Fagan  *    permission.
1809d64da3SSean Eric Fagan  *
1909d64da3SSean Eric Fagan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2009d64da3SSean Eric Fagan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2109d64da3SSean Eric Fagan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2209d64da3SSean Eric Fagan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2309d64da3SSean Eric Fagan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2409d64da3SSean Eric Fagan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2509d64da3SSean Eric Fagan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2609d64da3SSean Eric Fagan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2709d64da3SSean Eric Fagan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2809d64da3SSean Eric Fagan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2909d64da3SSean Eric Fagan  * SUCH DAMAGE.
3009d64da3SSean Eric Fagan  */
3109d64da3SSean Eric Fagan 
323cf51049SPhilippe Charnier #ifndef lint
333cf51049SPhilippe Charnier static const char rcsid[] =
34c3aac50fSPeter Wemm   "$FreeBSD$";
353cf51049SPhilippe Charnier #endif /* not lint */
363cf51049SPhilippe Charnier 
3709d64da3SSean Eric Fagan /*
38bbeaf6c0SSean Eric Fagan  * This file has routines used to print out system calls and their
39bbeaf6c0SSean Eric Fagan  * arguments.
40bbeaf6c0SSean Eric Fagan  */
41bbeaf6c0SSean Eric Fagan 
42894b8f7aSAlfred Perlstein #include <sys/mman.h>
439ddd1412SDag-Erling Smørgrav #include <sys/types.h>
445d2d083cSXin LI #include <sys/ptrace.h>
459ddd1412SDag-Erling Smørgrav #include <sys/socket.h>
461d631f7eSMike Barcroft #include <sys/time.h>
479ddd1412SDag-Erling Smørgrav #include <sys/un.h>
489ddd1412SDag-Erling Smørgrav #include <netinet/in.h>
499ddd1412SDag-Erling Smørgrav #include <arpa/inet.h>
50081e5c48SPav Lucistnik #include <sys/ioccom.h>
51081e5c48SPav Lucistnik #include <machine/atomic.h>
52081e5c48SPav Lucistnik #include <errno.h>
53081e5c48SPav Lucistnik #include <sys/umtx.h>
54081e5c48SPav Lucistnik #include <sys/event.h>
55081e5c48SPav Lucistnik #include <sys/stat.h>
56081e5c48SPav Lucistnik #include <sys/resource.h>
579ddd1412SDag-Erling Smørgrav 
58dec17687SBrian Feldman #include <ctype.h>
593cf51049SPhilippe Charnier #include <err.h>
60894b8f7aSAlfred Perlstein #include <fcntl.h>
61e45a5a0dSDavid Malone #include <poll.h>
629ddd1412SDag-Erling Smørgrav #include <signal.h>
63e45a5a0dSDavid Malone #include <stdint.h>
64bbeaf6c0SSean Eric Fagan #include <stdio.h>
65bbeaf6c0SSean Eric Fagan #include <stdlib.h>
66bbeaf6c0SSean Eric Fagan #include <string.h>
6737169f94SMatthew N. Dodd #include <time.h>
68bbeaf6c0SSean Eric Fagan #include <unistd.h>
69081e5c48SPav Lucistnik #include <vis.h>
709ddd1412SDag-Erling Smørgrav 
71ec0bed25SMatthew N. Dodd #include "truss.h"
721be5d704SMark Murray #include "extern.h"
73bbeaf6c0SSean Eric Fagan #include "syscall.h"
74bbeaf6c0SSean Eric Fagan 
752c02627fSMarcel Moolenaar /* 64-bit alignment on 32-bit platforms. */
762c02627fSMarcel Moolenaar #ifdef __powerpc__
772c02627fSMarcel Moolenaar #define	QUAD_ALIGN	1
782c02627fSMarcel Moolenaar #else
792c02627fSMarcel Moolenaar #define	QUAD_ALIGN	0
802c02627fSMarcel Moolenaar #endif
812c02627fSMarcel Moolenaar 
822c02627fSMarcel Moolenaar /* Number of slots needed for a 64-bit argument. */
832c02627fSMarcel Moolenaar #ifdef __LP64__
842c02627fSMarcel Moolenaar #define	QUAD_SLOTS	1
852c02627fSMarcel Moolenaar #else
862c02627fSMarcel Moolenaar #define	QUAD_SLOTS	2
872c02627fSMarcel Moolenaar #endif
882c02627fSMarcel Moolenaar 
89bbeaf6c0SSean Eric Fagan /*
90081e5c48SPav Lucistnik  * This should probably be in its own file, sorted alphabetically.
91bbeaf6c0SSean Eric Fagan  */
92a02c83afSEd Schouten static struct syscall syscalls[] = {
93ee3b0f6eSDiomidis Spinellis 	{ .name = "fcntl", .ret_type = 1, .nargs = 3,
94ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 } , { Fcntl, 1 }, { Fcntlflag | OUT, 2 } } },
9576de696dSJaakko Heinonen 	{ .name = "fork", .ret_type = 1, .nargs = 0 },
9676de696dSJaakko Heinonen 	{ .name = "getegid", .ret_type = 1, .nargs = 0 },
9776de696dSJaakko Heinonen 	{ .name = "geteuid", .ret_type = 1, .nargs = 0 },
9876de696dSJaakko Heinonen 	{ .name = "getgid", .ret_type = 1, .nargs = 0 },
9976de696dSJaakko Heinonen 	{ .name = "getpid", .ret_type = 1, .nargs = 0 },
10076de696dSJaakko Heinonen 	{ .name = "getpgid", .ret_type = 1, .nargs = 1,
10176de696dSJaakko Heinonen 	  .args = { { Int, 0 } } },
10276de696dSJaakko Heinonen 	{ .name = "getpgrp", .ret_type = 1, .nargs = 0 },
10376de696dSJaakko Heinonen 	{ .name = "getppid", .ret_type = 1, .nargs = 0 },
10476de696dSJaakko Heinonen 	{ .name = "getsid", .ret_type = 1, .nargs = 1,
10576de696dSJaakko Heinonen 	  .args = { { Int, 0 } } },
10676de696dSJaakko Heinonen 	{ .name = "getuid", .ret_type = 1, .nargs = 0 },
107ee3b0f6eSDiomidis Spinellis 	{ .name = "readlink", .ret_type = 1, .nargs = 3,
108ee3b0f6eSDiomidis Spinellis 	  .args = { { Name, 0 } , { Readlinkres | OUT, 1 }, { Int, 2 } } },
109ee3b0f6eSDiomidis Spinellis 	{ .name = "lseek", .ret_type = 2, .nargs = 3,
110ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Quad, 1 + QUAD_ALIGN }, { Whence, 1 + QUAD_SLOTS + QUAD_ALIGN } } },
111ee3b0f6eSDiomidis Spinellis 	{ .name = "linux_lseek", .ret_type = 2, .nargs = 3,
112ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
113ee3b0f6eSDiomidis Spinellis 	{ .name = "mmap", .ret_type = 2, .nargs = 6,
114ee3b0f6eSDiomidis Spinellis 	  .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 }, { Mmapflags, 3 }, { Int, 4 }, { Quad, 5 + QUAD_ALIGN } } },
115ee3b0f6eSDiomidis Spinellis 	{ .name = "mprotect", .ret_type = 1, .nargs = 3,
116ee3b0f6eSDiomidis Spinellis 	  .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 } } },
117ee3b0f6eSDiomidis Spinellis 	{ .name = "open", .ret_type = 1, .nargs = 3,
118ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | IN, 0 } , { Open, 1 }, { Octal, 2 } } },
119ee3b0f6eSDiomidis Spinellis 	{ .name = "mkdir", .ret_type = 1, .nargs = 2,
120ee3b0f6eSDiomidis Spinellis 	  .args = { { Name, 0 } , { Octal, 1 } } },
121ee3b0f6eSDiomidis Spinellis 	{ .name = "linux_open", .ret_type = 1, .nargs = 3,
122ee3b0f6eSDiomidis Spinellis 	  .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
123ee3b0f6eSDiomidis Spinellis 	{ .name = "close", .ret_type = 1, .nargs = 1,
124ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 } } },
125ee3b0f6eSDiomidis Spinellis 	{ .name = "link", .ret_type = 0, .nargs = 2,
126ee3b0f6eSDiomidis Spinellis 	  .args = { { Name, 0 }, { Name, 1 } } },
127ee3b0f6eSDiomidis Spinellis 	{ .name = "unlink", .ret_type = 0, .nargs = 1,
128ee3b0f6eSDiomidis Spinellis 	  .args = { { Name, 0 } } },
129ee3b0f6eSDiomidis Spinellis 	{ .name = "chdir", .ret_type = 0, .nargs = 1,
130ee3b0f6eSDiomidis Spinellis 	  .args = { { Name, 0 } } },
131ee3b0f6eSDiomidis Spinellis 	{ .name = "chroot", .ret_type = 0, .nargs = 1,
132ee3b0f6eSDiomidis Spinellis 	  .args = { { Name, 0 } } },
133ee3b0f6eSDiomidis Spinellis 	{ .name = "mknod", .ret_type = 0, .nargs = 3,
134ee3b0f6eSDiomidis Spinellis 	  .args = { { Name, 0 }, { Octal, 1 }, { Int, 3 } } },
135ee3b0f6eSDiomidis Spinellis 	{ .name = "chmod", .ret_type = 0, .nargs = 2,
136ee3b0f6eSDiomidis Spinellis 	  .args = { { Name, 0 }, { Octal, 1 } } },
137ee3b0f6eSDiomidis Spinellis 	{ .name = "chown", .ret_type = 0, .nargs = 3,
138ee3b0f6eSDiomidis Spinellis 	  .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
139ee3b0f6eSDiomidis Spinellis 	{ .name = "mount", .ret_type = 0, .nargs = 4,
140ee3b0f6eSDiomidis Spinellis 	  .args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } },
141ee3b0f6eSDiomidis Spinellis 	{ .name = "umount", .ret_type = 0, .nargs = 2,
142ee3b0f6eSDiomidis Spinellis 	  .args = { { Name, 0 }, { Int, 2 } } },
143ee3b0f6eSDiomidis Spinellis 	{ .name = "fstat", .ret_type = 1, .nargs = 2,
144ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Stat | OUT , 1 } } },
145ee3b0f6eSDiomidis Spinellis 	{ .name = "stat", .ret_type = 1, .nargs = 2,
146ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
147ee3b0f6eSDiomidis Spinellis 	{ .name = "lstat", .ret_type = 1, .nargs = 2,
148ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } },
149ee3b0f6eSDiomidis Spinellis 	{ .name = "linux_newstat", .ret_type = 1, .nargs = 2,
150ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } },
151ee3b0f6eSDiomidis Spinellis 	{ .name = "linux_newfstat", .ret_type = 1, .nargs = 2,
152ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Ptr | OUT, 1 } } },
153ee3b0f6eSDiomidis Spinellis 	{ .name = "write", .ret_type = 1, .nargs = 3,
154ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 } } },
155ee3b0f6eSDiomidis Spinellis 	{ .name = "ioctl", .ret_type = 1, .nargs = 3,
156ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 } } },
157ee3b0f6eSDiomidis Spinellis 	{ .name = "break", .ret_type = 1, .nargs = 1,
158ee3b0f6eSDiomidis Spinellis 	  .args = { { Ptr, 0 } } },
159ee3b0f6eSDiomidis Spinellis 	{ .name = "exit", .ret_type = 0, .nargs = 1,
160ee3b0f6eSDiomidis Spinellis 	  .args = { { Hex, 0 } } },
161ee3b0f6eSDiomidis Spinellis 	{ .name = "access", .ret_type = 1, .nargs = 2,
162ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | IN, 0 }, { Int, 1 } } },
163ee3b0f6eSDiomidis Spinellis 	{ .name = "sigaction", .ret_type = 1, .nargs = 3,
164ee3b0f6eSDiomidis Spinellis 	  .args = { { Signal, 0 }, { Sigaction | IN, 1 }, { Sigaction | OUT, 2 } } },
165ee3b0f6eSDiomidis Spinellis 	{ .name = "accept", .ret_type = 1, .nargs = 3,
166ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
167ee3b0f6eSDiomidis Spinellis 	{ .name = "bind", .ret_type = 1, .nargs = 3,
168ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
169ee3b0f6eSDiomidis Spinellis 	{ .name = "connect", .ret_type = 1, .nargs = 3,
170ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
171ee3b0f6eSDiomidis Spinellis 	{ .name = "getpeername", .ret_type = 1, .nargs = 3,
172ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
173ee3b0f6eSDiomidis Spinellis 	{ .name = "getsockname", .ret_type = 1, .nargs = 3,
174ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
175ee3b0f6eSDiomidis Spinellis 	{ .name = "recvfrom", .ret_type = 1, .nargs = 6,
176ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } },
177ee3b0f6eSDiomidis Spinellis 	{ .name = "sendto", .ret_type = 1, .nargs = 6,
178ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } },
179ee3b0f6eSDiomidis Spinellis 	{ .name = "execve", .ret_type = 1, .nargs = 3,
180ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } },
181ee3b0f6eSDiomidis Spinellis 	{ .name = "linux_execve", .ret_type = 1, .nargs = 3,
182ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } },
183ee3b0f6eSDiomidis Spinellis 	{ .name = "kldload", .ret_type = 0, .nargs = 1,
184ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | IN, 0 } } },
185ee3b0f6eSDiomidis Spinellis 	{ .name = "kldunload", .ret_type = 0, .nargs = 1,
186ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 } } },
187ee3b0f6eSDiomidis Spinellis 	{ .name = "kldfind", .ret_type = 0, .nargs = 1,
188ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | IN, 0 } } },
189ee3b0f6eSDiomidis Spinellis 	{ .name = "kldnext", .ret_type = 0, .nargs = 1,
190ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 } } },
191ee3b0f6eSDiomidis Spinellis 	{ .name = "kldstat", .ret_type = 0, .nargs = 2,
192ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Ptr, 1 } } },
193ee3b0f6eSDiomidis Spinellis 	{ .name = "kldfirstmod", .ret_type = 0, .nargs = 1,
194ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 } } },
195ee3b0f6eSDiomidis Spinellis 	{ .name = "nanosleep", .ret_type = 0, .nargs = 1,
196ee3b0f6eSDiomidis Spinellis 	  .args = { { Timespec, 0 } } },
197ee3b0f6eSDiomidis Spinellis 	{ .name = "select", .ret_type = 1, .nargs = 5,
198ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, { Timeval, 4 } } },
199ee3b0f6eSDiomidis Spinellis 	{ .name = "poll", .ret_type = 1, .nargs = 3,
200ee3b0f6eSDiomidis Spinellis 	  .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } },
201ee3b0f6eSDiomidis Spinellis 	{ .name = "gettimeofday", .ret_type = 1, .nargs = 2,
202ee3b0f6eSDiomidis Spinellis 	  .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } },
203ee3b0f6eSDiomidis Spinellis 	{ .name = "clock_gettime", .ret_type = 1, .nargs = 2,
204ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Timespec | OUT, 1 } } },
205ee3b0f6eSDiomidis Spinellis 	{ .name = "getitimer", .ret_type = 1, .nargs = 2,
206ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Itimerval | OUT, 2 } } },
207ee3b0f6eSDiomidis Spinellis 	{ .name = "setitimer", .ret_type = 1, .nargs = 3,
208ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Itimerval, 1 } , { Itimerval | OUT, 2 } } },
209ee3b0f6eSDiomidis Spinellis 	{ .name = "kse_release", .ret_type = 0, .nargs = 1,
210ee3b0f6eSDiomidis Spinellis 	  .args = { { Timespec, 0 } } },
211ee3b0f6eSDiomidis Spinellis 	{ .name = "kevent", .ret_type = 0, .nargs = 6,
212ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 }, { Int, 4 }, { Timespec, 5 } } },
213ee3b0f6eSDiomidis Spinellis 	{ .name = "_umtx_lock", .ret_type = 0, .nargs = 1,
214ee3b0f6eSDiomidis Spinellis 	  .args = { { Umtx, 0 } } },
215ee3b0f6eSDiomidis Spinellis 	{ .name = "_umtx_unlock", .ret_type = 0, .nargs = 1,
216ee3b0f6eSDiomidis Spinellis 	  .args = { { Umtx, 0 } } },
217ee3b0f6eSDiomidis Spinellis 	{ .name = "sigprocmask", .ret_type = 0, .nargs = 3,
218ee3b0f6eSDiomidis Spinellis 	  .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
219ee3b0f6eSDiomidis Spinellis 	{ .name = "unmount", .ret_type = 1, .nargs = 2,
220ee3b0f6eSDiomidis Spinellis 	  .args = { { Name, 0 }, { Int, 1 } } },
221ee3b0f6eSDiomidis Spinellis 	{ .name = "socket", .ret_type = 1, .nargs = 3,
222ee3b0f6eSDiomidis Spinellis 	  .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Int, 2 } } },
223ee3b0f6eSDiomidis Spinellis 	{ .name = "getrusage", .ret_type = 1, .nargs = 2,
224ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Rusage | OUT, 1 } } },
225ee3b0f6eSDiomidis Spinellis 	{ .name = "__getcwd", .ret_type = 1, .nargs = 2,
226ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | OUT, 0 }, { Int, 1 } } },
227ee3b0f6eSDiomidis Spinellis 	{ .name = "shutdown", .ret_type = 1, .nargs = 2,
228ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Shutdown, 1 } } },
229ee3b0f6eSDiomidis Spinellis 	{ .name = "getrlimit", .ret_type = 1, .nargs = 2,
230ee3b0f6eSDiomidis Spinellis 	  .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } },
231ee3b0f6eSDiomidis Spinellis 	{ .name = "setrlimit", .ret_type = 1, .nargs = 2,
232ee3b0f6eSDiomidis Spinellis 	  .args = { { Resource, 0 }, { Rlimit | IN, 1 } } },
233ee3b0f6eSDiomidis Spinellis 	{ .name = "utimes", .ret_type = 1, .nargs = 2,
234ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
235ee3b0f6eSDiomidis Spinellis 	{ .name = "lutimes", .ret_type = 1, .nargs = 2,
236ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } },
237ee3b0f6eSDiomidis Spinellis 	{ .name = "futimes", .ret_type = 1, .nargs = 2,
238ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { Timeval | IN, 1 } } },
239ee3b0f6eSDiomidis Spinellis 	{ .name = "chflags", .ret_type = 1, .nargs = 2,
240ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | IN, 0 }, { Hex, 1 } } },
241ee3b0f6eSDiomidis Spinellis 	{ .name = "lchflags", .ret_type = 1, .nargs = 2,
242ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | IN, 0 }, { Hex, 1 } } },
243ee3b0f6eSDiomidis Spinellis 	{ .name = "pathconf", .ret_type = 1, .nargs = 2,
244ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | IN, 0 }, { Pathconf, 1 } } },
245c059fa2eSJaakko Heinonen 	{ .name = "pipe", .ret_type = 1, .nargs = 1,
246c059fa2eSJaakko Heinonen 	  .args = { { Ptr, 0 } } },
247ee3b0f6eSDiomidis Spinellis 	{ .name = "truncate", .ret_type = 1, .nargs = 3,
248ee3b0f6eSDiomidis Spinellis 	  .args = { { Name | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 } } },
249ee3b0f6eSDiomidis Spinellis 	{ .name = "ftruncate", .ret_type = 1, .nargs = 3,
250ee3b0f6eSDiomidis Spinellis 	  .args = { { Int | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 } } },
251ee3b0f6eSDiomidis Spinellis 	{ .name = "kill", .ret_type = 1, .nargs = 2,
252ee3b0f6eSDiomidis Spinellis 	  .args = { { Int | IN, 0 }, { Signal | IN, 1 } } },
253ee3b0f6eSDiomidis Spinellis 	{ .name = "munmap", .ret_type = 1, .nargs = 2,
254ee3b0f6eSDiomidis Spinellis 	  .args = { { Ptr, 0 }, { Int, 1 } } },
255ee3b0f6eSDiomidis Spinellis 	{ .name = "read", .ret_type = 1, .nargs = 3,
256ee3b0f6eSDiomidis Spinellis 	  .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 } } },
257ee3b0f6eSDiomidis Spinellis 	{ .name = "rename", .ret_type = 1, .nargs = 2,
258ee3b0f6eSDiomidis Spinellis 	  .args = { { Name , 0 } , { Name, 1 } } },
259ee3b0f6eSDiomidis Spinellis 	{ .name = "symlink", .ret_type = 1, .nargs = 2,
260ee3b0f6eSDiomidis Spinellis 	  .args = { { Name , 0 } , { Name, 1 } } },
2612b6d81c1SEd Schouten 	{ .name = "posix_openpt", .ret_type = 1, .nargs = 1,
2622b6d81c1SEd Schouten 	  .args = { { Open, 0 } } },
263ee3b0f6eSDiomidis Spinellis 	{ .name = 0 },
264bbeaf6c0SSean Eric Fagan };
265bbeaf6c0SSean Eric Fagan 
266081e5c48SPav Lucistnik /* Xlat idea taken from strace */
267081e5c48SPav Lucistnik struct xlat {
268081e5c48SPav Lucistnik 	int val;
2695d2d083cSXin LI 	const char *str;
270081e5c48SPav Lucistnik };
271081e5c48SPav Lucistnik 
272081e5c48SPav Lucistnik #define	X(a)	{ a, #a },
273081e5c48SPav Lucistnik #define	XEND	{ 0, NULL }
274081e5c48SPav Lucistnik 
275081e5c48SPav Lucistnik static struct xlat kevent_filters[] = {
276081e5c48SPav Lucistnik 	X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
277081e5c48SPav Lucistnik 	X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
278a6fffd6cSBrooks Davis 	X(EVFILT_FS) X(EVFILT_READ) XEND
279081e5c48SPav Lucistnik };
280081e5c48SPav Lucistnik 
281081e5c48SPav Lucistnik static struct xlat kevent_flags[] = {
282081e5c48SPav Lucistnik 	X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
283081e5c48SPav Lucistnik 	X(EV_CLEAR) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
284081e5c48SPav Lucistnik };
285081e5c48SPav Lucistnik 
286a02c83afSEd Schouten static struct xlat poll_flags[] = {
287081e5c48SPav Lucistnik 	X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
288081e5c48SPav Lucistnik 	X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
289081e5c48SPav Lucistnik 	X(POLLWRBAND) X(POLLINIGNEOF) XEND
290081e5c48SPav Lucistnik };
291081e5c48SPav Lucistnik 
292081e5c48SPav Lucistnik static struct xlat mmap_flags[] = {
293081e5c48SPav Lucistnik 	X(MAP_SHARED) X(MAP_PRIVATE) X(MAP_FIXED) X(MAP_RENAME)
294081e5c48SPav Lucistnik 	X(MAP_NORESERVE) X(MAP_RESERVED0080) X(MAP_RESERVED0100)
295081e5c48SPav Lucistnik 	X(MAP_HASSEMAPHORE) X(MAP_STACK) X(MAP_NOSYNC) X(MAP_ANON)
296081e5c48SPav Lucistnik 	X(MAP_NOCORE) XEND
297081e5c48SPav Lucistnik };
298081e5c48SPav Lucistnik 
299081e5c48SPav Lucistnik static struct xlat mprot_flags[] = {
300081e5c48SPav Lucistnik 	X(PROT_NONE) X(PROT_READ) X(PROT_WRITE) X(PROT_EXEC) XEND
301081e5c48SPav Lucistnik };
302081e5c48SPav Lucistnik 
303081e5c48SPav Lucistnik static struct xlat whence_arg[] = {
304081e5c48SPav Lucistnik 	X(SEEK_SET) X(SEEK_CUR) X(SEEK_END) XEND
305081e5c48SPav Lucistnik };
306081e5c48SPav Lucistnik 
307081e5c48SPav Lucistnik static struct xlat sigaction_flags[] = {
308081e5c48SPav Lucistnik 	X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
309081e5c48SPav Lucistnik 	X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
310081e5c48SPav Lucistnik };
311081e5c48SPav Lucistnik 
312081e5c48SPav Lucistnik static struct xlat fcntl_arg[] = {
313081e5c48SPav Lucistnik 	X(F_DUPFD) X(F_GETFD) X(F_SETFD) X(F_GETFL) X(F_SETFL)
314081e5c48SPav Lucistnik 	X(F_GETOWN) X(F_SETOWN) X(F_GETLK) X(F_SETLK) X(F_SETLKW) XEND
315081e5c48SPav Lucistnik };
316081e5c48SPav Lucistnik 
317081e5c48SPav Lucistnik static struct xlat fcntlfd_arg[] = {
318081e5c48SPav Lucistnik 	X(FD_CLOEXEC) XEND
319081e5c48SPav Lucistnik };
320081e5c48SPav Lucistnik 
321081e5c48SPav Lucistnik static struct xlat fcntlfl_arg[] = {
322081e5c48SPav Lucistnik 	X(O_APPEND) X(O_ASYNC) X(O_FSYNC) X(O_NONBLOCK) X(O_NOFOLLOW)
323081e5c48SPav Lucistnik 	X(O_DIRECT) XEND
324081e5c48SPav Lucistnik };
325081e5c48SPav Lucistnik 
326081e5c48SPav Lucistnik static struct xlat sockdomain_arg[] = {
327081e5c48SPav Lucistnik 	X(PF_UNSPEC) X(PF_LOCAL) X(PF_UNIX) X(PF_INET) X(PF_IMPLINK)
328081e5c48SPav Lucistnik 	X(PF_PUP) X(PF_CHAOS) X(PF_NETBIOS) X(PF_ISO) X(PF_OSI)
329081e5c48SPav Lucistnik 	X(PF_ECMA) X(PF_DATAKIT) X(PF_CCITT) X(PF_SNA) X(PF_DECnet)
330081e5c48SPav Lucistnik 	X(PF_DLI) X(PF_LAT) X(PF_HYLINK) X(PF_APPLETALK) X(PF_ROUTE)
331081e5c48SPav Lucistnik 	X(PF_LINK) X(PF_XTP) X(PF_COIP) X(PF_CNT) X(PF_SIP) X(PF_IPX)
332081e5c48SPav Lucistnik 	X(PF_RTIP) X(PF_PIP) X(PF_ISDN) X(PF_KEY) X(PF_INET6)
333081e5c48SPav Lucistnik 	X(PF_NATM) X(PF_ATM) X(PF_NETGRAPH) X(PF_SLOW) X(PF_SCLUSTER)
334081e5c48SPav Lucistnik 	X(PF_ARP) X(PF_BLUETOOTH) XEND
335081e5c48SPav Lucistnik };
336081e5c48SPav Lucistnik 
337081e5c48SPav Lucistnik static struct xlat socktype_arg[] = {
338081e5c48SPav Lucistnik 	X(SOCK_STREAM) X(SOCK_DGRAM) X(SOCK_RAW) X(SOCK_RDM)
339081e5c48SPav Lucistnik 	X(SOCK_SEQPACKET) XEND
340081e5c48SPav Lucistnik };
341081e5c48SPav Lucistnik 
342081e5c48SPav Lucistnik static struct xlat open_flags[] = {
343081e5c48SPav Lucistnik 	X(O_RDONLY) X(O_WRONLY) X(O_RDWR) X(O_ACCMODE) X(O_NONBLOCK)
344081e5c48SPav Lucistnik 	X(O_APPEND) X(O_SHLOCK) X(O_EXLOCK) X(O_ASYNC) X(O_FSYNC)
345081e5c48SPav Lucistnik 	X(O_NOFOLLOW) X(O_CREAT) X(O_TRUNC) X(O_EXCL) X(O_NOCTTY)
346081e5c48SPav Lucistnik 	X(O_DIRECT) XEND
347081e5c48SPav Lucistnik };
348081e5c48SPav Lucistnik 
349081e5c48SPav Lucistnik static struct xlat shutdown_arg[] = {
350081e5c48SPav Lucistnik 	X(SHUT_RD) X(SHUT_WR) X(SHUT_RDWR) XEND
351081e5c48SPav Lucistnik };
352081e5c48SPav Lucistnik 
353081e5c48SPav Lucistnik static struct xlat resource_arg[] = {
354081e5c48SPav Lucistnik 	X(RLIMIT_CPU) X(RLIMIT_FSIZE) X(RLIMIT_DATA) X(RLIMIT_STACK)
355081e5c48SPav Lucistnik 	X(RLIMIT_CORE) X(RLIMIT_RSS) X(RLIMIT_MEMLOCK) X(RLIMIT_NPROC)
356081e5c48SPav Lucistnik 	X(RLIMIT_NOFILE) X(RLIMIT_SBSIZE) X(RLIMIT_VMEM) XEND
357081e5c48SPav Lucistnik };
358081e5c48SPav Lucistnik 
359081e5c48SPav Lucistnik static struct xlat pathconf_arg[] = {
360081e5c48SPav Lucistnik 	X(_PC_LINK_MAX)  X(_PC_MAX_CANON)  X(_PC_MAX_INPUT)
361081e5c48SPav Lucistnik 	X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF)
362081e5c48SPav Lucistnik 	X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE)
363081e5c48SPav Lucistnik 	X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO)
364081e5c48SPav Lucistnik 	X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS)
365081e5c48SPav Lucistnik 	X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE)
366081e5c48SPav Lucistnik 	X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
367081e5c48SPav Lucistnik 	X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
368081e5c48SPav Lucistnik 	X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
369081e5c48SPav Lucistnik 	XEND
370081e5c48SPav Lucistnik };
371081e5c48SPav Lucistnik 
372081e5c48SPav Lucistnik #undef X
373081e5c48SPav Lucistnik #undef XEND
374081e5c48SPav Lucistnik 
375d8984f48SDag-Erling Smørgrav /*
376d8984f48SDag-Erling Smørgrav  * Searches an xlat array for a value, and returns it if found.  Otherwise
377d8984f48SDag-Erling Smørgrav  * return a string representation.
378d8984f48SDag-Erling Smørgrav  */
379d8984f48SDag-Erling Smørgrav static const char *
380d8984f48SDag-Erling Smørgrav lookup(struct xlat *xlat, int val, int base)
381081e5c48SPav Lucistnik {
382081e5c48SPav Lucistnik 	static char tmp[16];
383d8984f48SDag-Erling Smørgrav 
384081e5c48SPav Lucistnik 	for (; xlat->str != NULL; xlat++)
385081e5c48SPav Lucistnik 		if (xlat->val == val)
386d8984f48SDag-Erling Smørgrav 			return (xlat->str);
387081e5c48SPav Lucistnik 	switch (base) {
388081e5c48SPav Lucistnik 		case 8:
389081e5c48SPav Lucistnik 			sprintf(tmp, "0%o", val);
390081e5c48SPav Lucistnik 			break;
391081e5c48SPav Lucistnik 		case 16:
392081e5c48SPav Lucistnik 			sprintf(tmp, "0x%x", val);
393081e5c48SPav Lucistnik 			break;
394081e5c48SPav Lucistnik 		case 10:
395081e5c48SPav Lucistnik 			sprintf(tmp, "%u", val);
396081e5c48SPav Lucistnik 			break;
397081e5c48SPav Lucistnik 		default:
398081e5c48SPav Lucistnik 			errx(1,"Unknown lookup base");
399081e5c48SPav Lucistnik 			break;
400081e5c48SPav Lucistnik 	}
401d8984f48SDag-Erling Smørgrav 	return (tmp);
402081e5c48SPav Lucistnik }
403081e5c48SPav Lucistnik 
4045d2d083cSXin LI static const char *
4055d2d083cSXin LI xlookup(struct xlat *xlat, int val)
406081e5c48SPav Lucistnik {
407d8984f48SDag-Erling Smørgrav 
408d8984f48SDag-Erling Smørgrav 	return (lookup(xlat, val, 16));
409081e5c48SPav Lucistnik }
410081e5c48SPav Lucistnik 
411081e5c48SPav Lucistnik /* Searches an xlat array containing bitfield values.  Remaining bits
412081e5c48SPav Lucistnik    set after removing the known ones are printed at the end:
413081e5c48SPav Lucistnik    IN|0x400 */
414d8984f48SDag-Erling Smørgrav static char *
415d8984f48SDag-Erling Smørgrav xlookup_bits(struct xlat *xlat, int val)
416081e5c48SPav Lucistnik {
41794355cfdSAndrey Zonov 	int len, rem;
418081e5c48SPav Lucistnik 	static char str[512];
419081e5c48SPav Lucistnik 
42094355cfdSAndrey Zonov 	len = 0;
42194355cfdSAndrey Zonov 	rem = val;
422d8984f48SDag-Erling Smørgrav 	for (; xlat->str != NULL; xlat++) {
423d8984f48SDag-Erling Smørgrav 		if ((xlat->val & rem) == xlat->val) {
424081e5c48SPav Lucistnik 			/* don't print the "all-bits-zero" string unless all
425081e5c48SPav Lucistnik 			   bits are really zero */
426081e5c48SPav Lucistnik 			if (xlat->val == 0 && val != 0)
427081e5c48SPav Lucistnik 				continue;
428081e5c48SPav Lucistnik 			len += sprintf(str + len, "%s|", xlat->str);
429081e5c48SPav Lucistnik 			rem &= ~(xlat->val);
430081e5c48SPav Lucistnik 		}
431081e5c48SPav Lucistnik 	}
432081e5c48SPav Lucistnik 	/* if we have leftover bits or didn't match anything */
433081e5c48SPav Lucistnik 	if (rem || len == 0)
434081e5c48SPav Lucistnik 		len += sprintf(str + len, "0x%x", rem);
435081e5c48SPav Lucistnik 	if (len && str[len - 1] == '|')
436081e5c48SPav Lucistnik 		len--;
437081e5c48SPav Lucistnik 	str[len] = 0;
438d8984f48SDag-Erling Smørgrav 	return (str);
439081e5c48SPav Lucistnik }
440081e5c48SPav Lucistnik 
441bbeaf6c0SSean Eric Fagan /*
442bbeaf6c0SSean Eric Fagan  * If/when the list gets big, it might be desirable to do it
443bbeaf6c0SSean Eric Fagan  * as a hash table or binary search.
444bbeaf6c0SSean Eric Fagan  */
445bbeaf6c0SSean Eric Fagan 
446bbeaf6c0SSean Eric Fagan struct syscall *
447d8984f48SDag-Erling Smørgrav get_syscall(const char *name)
448d8984f48SDag-Erling Smørgrav {
44994355cfdSAndrey Zonov 	struct syscall *sc;
450bbeaf6c0SSean Eric Fagan 
45194355cfdSAndrey Zonov 	sc = syscalls;
452d10f73b3SAlfred Perlstein 	if (name == NULL)
453d10f73b3SAlfred Perlstein 		return (NULL);
454bbeaf6c0SSean Eric Fagan 	while (sc->name) {
45594355cfdSAndrey Zonov 		if (strcmp(name, sc->name) == 0)
456d8984f48SDag-Erling Smørgrav 			return (sc);
457bbeaf6c0SSean Eric Fagan 		sc++;
458bbeaf6c0SSean Eric Fagan 	}
459d8984f48SDag-Erling Smørgrav 	return (NULL);
460bbeaf6c0SSean Eric Fagan }
461bbeaf6c0SSean Eric Fagan 
462bbeaf6c0SSean Eric Fagan /*
4639ddd1412SDag-Erling Smørgrav  * get_struct
4649ddd1412SDag-Erling Smørgrav  *
4659ddd1412SDag-Erling Smørgrav  * Copy a fixed amount of bytes from the process.
4669ddd1412SDag-Erling Smørgrav  */
4679ddd1412SDag-Erling Smørgrav 
4681be5d704SMark Murray static int
469be305c9cSAndrey Zonov get_struct(pid_t pid, void *offset, void *buf, int len)
470d8984f48SDag-Erling Smørgrav {
4715d2d083cSXin LI 	struct ptrace_io_desc iorequest;
4729ddd1412SDag-Erling Smørgrav 
4735d2d083cSXin LI 	iorequest.piod_op = PIOD_READ_D;
4745d2d083cSXin LI 	iorequest.piod_offs = offset;
4755d2d083cSXin LI 	iorequest.piod_addr = buf;
4765d2d083cSXin LI 	iorequest.piod_len = len;
4775d2d083cSXin LI 	if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
478d8984f48SDag-Erling Smørgrav 		return (-1);
479d8984f48SDag-Erling Smørgrav 	return (0);
4809ddd1412SDag-Erling Smørgrav }
4819ddd1412SDag-Erling Smørgrav 
4825d2d083cSXin LI #define	MAXSIZE		4096
4835d2d083cSXin LI #define	BLOCKSIZE	1024
4849ddd1412SDag-Erling Smørgrav /*
485bbeaf6c0SSean Eric Fagan  * get_string
486bbeaf6c0SSean Eric Fagan  * Copy a string from the process.  Note that it is
487bbeaf6c0SSean Eric Fagan  * expected to be a C string, but if max is set, it will
488bbeaf6c0SSean Eric Fagan  * only get that much.
489bbeaf6c0SSean Eric Fagan  */
490bbeaf6c0SSean Eric Fagan 
4915d2d083cSXin LI static char *
492d8984f48SDag-Erling Smørgrav get_string(pid_t pid, void *offset, int max)
493d8984f48SDag-Erling Smørgrav {
4945d2d083cSXin LI 	struct ptrace_io_desc iorequest;
49594355cfdSAndrey Zonov 	char *buf;
49694355cfdSAndrey Zonov 	int diff, i, size, totalsize;
497bbeaf6c0SSean Eric Fagan 
49894355cfdSAndrey Zonov 	diff = 0;
4995d2d083cSXin LI 	totalsize = size = max ? (max + 1) : BLOCKSIZE;
5005d2d083cSXin LI 	buf = malloc(totalsize);
5015d2d083cSXin LI 	if (buf == NULL)
502d8984f48SDag-Erling Smørgrav 		return (NULL);
5035d2d083cSXin LI 	for (;;) {
5045d2d083cSXin LI 		diff = totalsize - size;
5055d2d083cSXin LI 		iorequest.piod_op = PIOD_READ_D;
5065d2d083cSXin LI 		iorequest.piod_offs = (char *)offset + diff;
5075d2d083cSXin LI 		iorequest.piod_addr = buf + diff;
5085d2d083cSXin LI 		iorequest.piod_len = size;
5095d2d083cSXin LI 		if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
5105d2d083cSXin LI 			free(buf);
511d8984f48SDag-Erling Smørgrav 			return (NULL);
512bbeaf6c0SSean Eric Fagan 		}
5135d2d083cSXin LI 		for (i = 0 ; i < size; i++) {
5145d2d083cSXin LI 			if (buf[diff + i] == '\0')
5154e92419dSMarcel Moolenaar 				return (buf);
516bbeaf6c0SSean Eric Fagan 		}
5175d2d083cSXin LI 		if (totalsize < MAXSIZE - BLOCKSIZE && max == 0) {
5185d2d083cSXin LI 			totalsize += BLOCKSIZE;
5195d2d083cSXin LI 			buf = realloc(buf, totalsize);
5205d2d083cSXin LI 			size = BLOCKSIZE;
521d8984f48SDag-Erling Smørgrav 		} else {
522cdfc719cSJaakko Heinonen 			buf[totalsize - 1] = '\0';
523d8984f48SDag-Erling Smørgrav 			return (buf);
5245d2d083cSXin LI 		}
5255d2d083cSXin LI 	}
5265d2d083cSXin LI }
527bbeaf6c0SSean Eric Fagan 
528bbeaf6c0SSean Eric Fagan 
529bbeaf6c0SSean Eric Fagan /*
530bbeaf6c0SSean Eric Fagan  * print_arg
531bbeaf6c0SSean Eric Fagan  * Converts a syscall argument into a string.  Said string is
532bbeaf6c0SSean Eric Fagan  * allocated via malloc(), so needs to be free()'d.  The file
533bbeaf6c0SSean Eric Fagan  * descriptor is for the process' memory (via /proc), and is used
534bbeaf6c0SSean Eric Fagan  * to get any data (where the argument is a pointer).  sc is
535bbeaf6c0SSean Eric Fagan  * a pointer to the syscall description (see above); args is
536bbeaf6c0SSean Eric Fagan  * an array of all of the system call arguments.
537bbeaf6c0SSean Eric Fagan  */
538bbeaf6c0SSean Eric Fagan 
539bbeaf6c0SSean Eric Fagan char *
54094355cfdSAndrey Zonov print_arg(struct syscall_args *sc, unsigned long *args, long retval,
54194355cfdSAndrey Zonov     struct trussinfo *trussinfo)
542d8984f48SDag-Erling Smørgrav {
54394355cfdSAndrey Zonov 	char *tmp;
54494355cfdSAndrey Zonov 	pid_t pid;
545d8984f48SDag-Erling Smørgrav 
54694355cfdSAndrey Zonov 	tmp = NULL;
54794355cfdSAndrey Zonov 	pid = trussinfo->pid;
548bbeaf6c0SSean Eric Fagan 	switch (sc->type & ARG_MASK) {
549bbeaf6c0SSean Eric Fagan 	case Hex:
550f2359950SMarcel Moolenaar 		asprintf(&tmp, "0x%x", (int)args[sc->offset]);
551bbeaf6c0SSean Eric Fagan 		break;
552bbeaf6c0SSean Eric Fagan 	case Octal:
553f2359950SMarcel Moolenaar 		asprintf(&tmp, "0%o", (int)args[sc->offset]);
554bbeaf6c0SSean Eric Fagan 		break;
555bbeaf6c0SSean Eric Fagan 	case Int:
556f2359950SMarcel Moolenaar 		asprintf(&tmp, "%d", (int)args[sc->offset]);
557bbeaf6c0SSean Eric Fagan 		break;
558d8984f48SDag-Erling Smørgrav 	case Name: {
559081e5c48SPav Lucistnik 		/* NULL-terminated string. */
560bbeaf6c0SSean Eric Fagan 		char *tmp2;
5615d2d083cSXin LI 		tmp2 = get_string(pid, (void*)args[sc->offset], 0);
5621bcb5f5aSMarcel Moolenaar 		asprintf(&tmp, "\"%s\"", tmp2);
563bbeaf6c0SSean Eric Fagan 		free(tmp2);
564bbeaf6c0SSean Eric Fagan 		break;
565d8984f48SDag-Erling Smørgrav 	}
566d8984f48SDag-Erling Smørgrav 	case BinString: {
567081e5c48SPav Lucistnik 		/* Binary block of data that might have printable characters.
568081e5c48SPav Lucistnik 		   XXX If type|OUT, assume that the length is the syscall's
569081e5c48SPav Lucistnik 		   return value.  Otherwise, assume that the length of the block
570081e5c48SPav Lucistnik 		   is in the next syscall argument. */
571081e5c48SPav Lucistnik 		int max_string = trussinfo->strsize;
572081e5c48SPav Lucistnik 		char tmp2[max_string+1], *tmp3;
573081e5c48SPav Lucistnik 		int len;
574081e5c48SPav Lucistnik 		int truncated = 0;
575081e5c48SPav Lucistnik 
576081e5c48SPav Lucistnik 		if (sc->type & OUT)
577081e5c48SPav Lucistnik 			len = retval;
578081e5c48SPav Lucistnik 		else
579081e5c48SPav Lucistnik 			len = args[sc->offset + 1];
580081e5c48SPav Lucistnik 
581081e5c48SPav Lucistnik 		/* Don't print more than max_string characters, to avoid word
582081e5c48SPav Lucistnik 		   wrap.  If we have to truncate put some ... after the string.
583081e5c48SPav Lucistnik 		*/
584081e5c48SPav Lucistnik 		if (len > max_string) {
585081e5c48SPav Lucistnik 			len = max_string;
586081e5c48SPav Lucistnik 			truncated = 1;
587081e5c48SPav Lucistnik 		}
58894355cfdSAndrey Zonov 		if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len)
58994355cfdSAndrey Zonov 		    != -1) {
590081e5c48SPav Lucistnik 			tmp3 = malloc(len * 4 + 1);
591081e5c48SPav Lucistnik 			while (len) {
59294355cfdSAndrey Zonov 				if (strvisx(tmp3, tmp2, len,
59394355cfdSAndrey Zonov 				    VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
594081e5c48SPav Lucistnik 					break;
595081e5c48SPav Lucistnik 				len--;
596081e5c48SPav Lucistnik 				truncated = 1;
597081e5c48SPav Lucistnik 			};
59894355cfdSAndrey Zonov 			asprintf(&tmp, "\"%s\"%s", tmp3, truncated ?
59994355cfdSAndrey Zonov 			    "..." : "");
600081e5c48SPav Lucistnik 			free(tmp3);
601d8984f48SDag-Erling Smørgrav 		} else {
602081e5c48SPav Lucistnik 			asprintf(&tmp, "0x%lx", args[sc->offset]);
603081e5c48SPav Lucistnik 		}
604081e5c48SPav Lucistnik 		break;
605d8984f48SDag-Erling Smørgrav 	}
606d8984f48SDag-Erling Smørgrav 	case StringArray: {
6079897b203SMatthew N. Dodd 		int num, size, i;
6089897b203SMatthew N. Dodd 		char *tmp2;
6099897b203SMatthew N. Dodd 		char *string;
6109897b203SMatthew N. Dodd 		char *strarray[100];	/* XXX This is ugly. */
6119897b203SMatthew N. Dodd 
61294355cfdSAndrey Zonov 		if (get_struct(pid, (void *)args[sc->offset],
61394355cfdSAndrey Zonov 		    (void *)&strarray, sizeof(strarray)) == -1)
6149897b203SMatthew N. Dodd 			err(1, "get_struct %p", (void *)args[sc->offset]);
6159897b203SMatthew N. Dodd 		num = 0;
6169897b203SMatthew N. Dodd 		size = 0;
6179897b203SMatthew N. Dodd 
6189897b203SMatthew N. Dodd 		/* Find out how large of a buffer we'll need. */
6199897b203SMatthew N. Dodd 		while (strarray[num] != NULL) {
6205d2d083cSXin LI 			string = get_string(pid, (void*)strarray[num], 0);
6219897b203SMatthew N. Dodd 			size += strlen(string);
6229897b203SMatthew N. Dodd 			free(string);
6239897b203SMatthew N. Dodd 			num++;
6249897b203SMatthew N. Dodd 		}
6259897b203SMatthew N. Dodd 		size += 4 + (num * 4);
6269897b203SMatthew N. Dodd 		tmp = (char *)malloc(size);
6279897b203SMatthew N. Dodd 		tmp2 = tmp;
6289897b203SMatthew N. Dodd 
6299897b203SMatthew N. Dodd 		tmp2 += sprintf(tmp2, " [");
6309897b203SMatthew N. Dodd 		for (i = 0; i < num; i++) {
6315d2d083cSXin LI 			string = get_string(pid, (void*)strarray[i], 0);
63294355cfdSAndrey Zonov 			tmp2 += sprintf(tmp2, " \"%s\"%c", string,
63394355cfdSAndrey Zonov 			    (i + 1 == num) ? ' ' : ',');
6349897b203SMatthew N. Dodd 			free(string);
6359897b203SMatthew N. Dodd 		}
6369897b203SMatthew N. Dodd 		tmp2 += sprintf(tmp2, "]");
6379897b203SMatthew N. Dodd 		break;
638d8984f48SDag-Erling Smørgrav 	}
63910aeefc9SMarcel Moolenaar #ifdef __LP64__
64010aeefc9SMarcel Moolenaar 	case Quad:
64110aeefc9SMarcel Moolenaar 		asprintf(&tmp, "0x%lx", args[sc->offset]);
64210aeefc9SMarcel Moolenaar 		break;
64310aeefc9SMarcel Moolenaar #else
644d8984f48SDag-Erling Smørgrav 	case Quad: {
64510aeefc9SMarcel Moolenaar 		unsigned long long ll;
64610aeefc9SMarcel Moolenaar 		ll = *(unsigned long long *)(args + sc->offset);
64710aeefc9SMarcel Moolenaar 		asprintf(&tmp, "0x%llx", ll);
648bbeaf6c0SSean Eric Fagan 		break;
649bbeaf6c0SSean Eric Fagan 	}
65010aeefc9SMarcel Moolenaar #endif
651bbeaf6c0SSean Eric Fagan 	case Ptr:
6521bcb5f5aSMarcel Moolenaar 		asprintf(&tmp, "0x%lx", args[sc->offset]);
653bbeaf6c0SSean Eric Fagan 		break;
654d8984f48SDag-Erling Smørgrav 	case Readlinkres: {
6552bae4eb3SAlfred Perlstein 		char *tmp2;
6562bae4eb3SAlfred Perlstein 		if (retval == -1) {
6572bae4eb3SAlfred Perlstein 			tmp = strdup("");
6582bae4eb3SAlfred Perlstein 			break;
6592bae4eb3SAlfred Perlstein 		}
6605d2d083cSXin LI 		tmp2 = get_string(pid, (void*)args[sc->offset], retval);
6612bae4eb3SAlfred Perlstein 		asprintf(&tmp, "\"%s\"", tmp2);
6622bae4eb3SAlfred Perlstein 		free(tmp2);
6632bae4eb3SAlfred Perlstein 		break;
664d8984f48SDag-Erling Smørgrav 	}
665d8984f48SDag-Erling Smørgrav 	case Ioctl: {
6661be5d704SMark Murray 		const char *temp = ioctlname(args[sc->offset]);
66794355cfdSAndrey Zonov 		if (temp)
668970649f9SSean Eric Fagan 			tmp = strdup(temp);
66994355cfdSAndrey Zonov 		else {
670081e5c48SPav Lucistnik 			unsigned long arg = args[sc->offset];
67194355cfdSAndrey Zonov 			asprintf(&tmp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }",
67294355cfdSAndrey Zonov 			    arg, arg & IOC_OUT ? "R" : "",
67394355cfdSAndrey Zonov 			    arg & IOC_IN ? "W" : "", IOCGROUP(arg),
67494355cfdSAndrey Zonov 			    isprint(IOCGROUP(arg)) ? (char)IOCGROUP(arg) : '?',
675081e5c48SPav Lucistnik 			    arg & 0xFF, IOCPARM_LEN(arg));
676081e5c48SPav Lucistnik 		}
677081e5c48SPav Lucistnik 		break;
678d8984f48SDag-Erling Smørgrav 	}
679d8984f48SDag-Erling Smørgrav 	case Umtx: {
680081e5c48SPav Lucistnik 		struct umtx umtx;
68194355cfdSAndrey Zonov 		if (get_struct(pid, (void *)args[sc->offset], &umtx,
68294355cfdSAndrey Zonov 		    sizeof(umtx)) != -1)
683081e5c48SPav Lucistnik 			asprintf(&tmp, "{ 0x%lx }", (long)umtx.u_owner);
684081e5c48SPav Lucistnik 		else
6851bcb5f5aSMarcel Moolenaar 			asprintf(&tmp, "0x%lx", args[sc->offset]);
686f0ebbc29SDag-Erling Smørgrav 		break;
687d8984f48SDag-Erling Smørgrav 	}
688d8984f48SDag-Erling Smørgrav 	case Timespec: {
689e45a5a0dSDavid Malone 		struct timespec ts;
69094355cfdSAndrey Zonov 		if (get_struct(pid, (void *)args[sc->offset], &ts,
69194355cfdSAndrey Zonov 		    sizeof(ts)) != -1)
69294355cfdSAndrey Zonov 			asprintf(&tmp, "{%ld.%09ld }", (long)ts.tv_sec,
69394355cfdSAndrey Zonov 			    ts.tv_nsec);
694e45a5a0dSDavid Malone 		else
695e45a5a0dSDavid Malone 			asprintf(&tmp, "0x%lx", args[sc->offset]);
696e45a5a0dSDavid Malone 		break;
697d8984f48SDag-Erling Smørgrav 	}
698d8984f48SDag-Erling Smørgrav 	case Timeval: {
699e45a5a0dSDavid Malone 		struct timeval tv;
70094355cfdSAndrey Zonov 		if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
70194355cfdSAndrey Zonov 		    != -1)
70294355cfdSAndrey Zonov 			asprintf(&tmp, "{%ld.%06ld }", (long)tv.tv_sec,
70394355cfdSAndrey Zonov 			    tv.tv_usec);
704081e5c48SPav Lucistnik 		else
705081e5c48SPav Lucistnik 			asprintf(&tmp, "0x%lx", args[sc->offset]);
706081e5c48SPav Lucistnik 		break;
707d8984f48SDag-Erling Smørgrav 	}
708d8984f48SDag-Erling Smørgrav 	case Timeval2: {
709081e5c48SPav Lucistnik 		struct timeval tv[2];
71094355cfdSAndrey Zonov 		if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv))
71194355cfdSAndrey Zonov 		    != -1)
712081e5c48SPav Lucistnik 			asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }",
713081e5c48SPav Lucistnik 			    (long)tv[0].tv_sec, tv[0].tv_usec,
714081e5c48SPav Lucistnik 			    (long)tv[1].tv_sec, tv[1].tv_usec);
715e45a5a0dSDavid Malone 		else
716e45a5a0dSDavid Malone 			asprintf(&tmp, "0x%lx", args[sc->offset]);
717e45a5a0dSDavid Malone 		break;
718d8984f48SDag-Erling Smørgrav 	}
719d8984f48SDag-Erling Smørgrav 	case Itimerval: {
720e45a5a0dSDavid Malone 		struct itimerval itv;
72194355cfdSAndrey Zonov 		if (get_struct(pid, (void *)args[sc->offset], &itv,
72294355cfdSAndrey Zonov 		    sizeof(itv)) != -1)
723081e5c48SPav Lucistnik 			asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }",
724081e5c48SPav Lucistnik 			    (long)itv.it_interval.tv_sec,
725081e5c48SPav Lucistnik 			    itv.it_interval.tv_usec,
726081e5c48SPav Lucistnik 			    (long)itv.it_value.tv_sec,
727081e5c48SPav Lucistnik 			    itv.it_value.tv_usec);
728e45a5a0dSDavid Malone 		else
729e45a5a0dSDavid Malone 			asprintf(&tmp, "0x%lx", args[sc->offset]);
730e45a5a0dSDavid Malone 		break;
731d8984f48SDag-Erling Smørgrav 	}
732d8984f48SDag-Erling Smørgrav 	case Pollfd: {
733e45a5a0dSDavid Malone 		/*
73494355cfdSAndrey Zonov 		 * XXX: A Pollfd argument expects the /next/ syscall argument
73594355cfdSAndrey Zonov 		 * to be the number of fds in the array. This matches the poll
73694355cfdSAndrey Zonov 		 * syscall.
737e45a5a0dSDavid Malone 		 */
738e45a5a0dSDavid Malone 		struct pollfd *pfd;
739e45a5a0dSDavid Malone 		int numfds = args[sc->offset+1];
740e45a5a0dSDavid Malone 		int bytes = sizeof(struct pollfd) * numfds;
741e45a5a0dSDavid Malone 		int i, tmpsize, u, used;
742e45a5a0dSDavid Malone 		const int per_fd = 100;
743e45a5a0dSDavid Malone 
744e45a5a0dSDavid Malone 		if ((pfd = malloc(bytes)) == NULL)
74594355cfdSAndrey Zonov 			err(1, "Cannot malloc %d bytes for pollfd array",
74694355cfdSAndrey Zonov 			    bytes);
74794355cfdSAndrey Zonov 		if (get_struct(pid, (void *)args[sc->offset], pfd, bytes)
74894355cfdSAndrey Zonov 		    != -1) {
749e45a5a0dSDavid Malone 			used = 0;
750e45a5a0dSDavid Malone 			tmpsize = 1 + per_fd * numfds + 2;
751e45a5a0dSDavid Malone 			if ((tmp = malloc(tmpsize)) == NULL)
75294355cfdSAndrey Zonov 				err(1, "Cannot alloc %d bytes for poll output",
75394355cfdSAndrey Zonov 				    tmpsize);
754e45a5a0dSDavid Malone 
755e45a5a0dSDavid Malone 			tmp[used++] = '{';
756e45a5a0dSDavid Malone 			for (i = 0; i < numfds; i++) {
757e45a5a0dSDavid Malone 
75894355cfdSAndrey Zonov 				u = snprintf(tmp + used, per_fd, "%s%d/%s",
75994355cfdSAndrey Zonov 				    i > 0 ? " " : "", pfd[i].fd,
760081e5c48SPav Lucistnik 				    xlookup_bits(poll_flags, pfd[i].events));
761e45a5a0dSDavid Malone 				if (u > 0)
762e45a5a0dSDavid Malone 					used += u < per_fd ? u : per_fd;
763e45a5a0dSDavid Malone 			}
764e45a5a0dSDavid Malone 			tmp[used++] = '}';
765e45a5a0dSDavid Malone 			tmp[used++] = '\0';
766d8984f48SDag-Erling Smørgrav 		} else {
767e45a5a0dSDavid Malone 			asprintf(&tmp, "0x%lx", args[sc->offset]);
768e45a5a0dSDavid Malone 		}
769d8984f48SDag-Erling Smørgrav 		free(pfd);
770e45a5a0dSDavid Malone 		break;
771d8984f48SDag-Erling Smørgrav 	}
772d8984f48SDag-Erling Smørgrav 	case Fd_set: {
773e45a5a0dSDavid Malone 		/*
77494355cfdSAndrey Zonov 		 * XXX: A Fd_set argument expects the /first/ syscall argument
77594355cfdSAndrey Zonov 		 * to be the number of fds in the array.  This matches the
77694355cfdSAndrey Zonov 		 * select syscall.
777e45a5a0dSDavid Malone 		 */
778e45a5a0dSDavid Malone 		fd_set *fds;
779e45a5a0dSDavid Malone 		int numfds = args[0];
780e45a5a0dSDavid Malone 		int bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
781e45a5a0dSDavid Malone 		int i, tmpsize, u, used;
782e45a5a0dSDavid Malone 		const int per_fd = 20;
783e45a5a0dSDavid Malone 
784e45a5a0dSDavid Malone 		if ((fds = malloc(bytes)) == NULL)
78594355cfdSAndrey Zonov 			err(1, "Cannot malloc %d bytes for fd_set array",
78694355cfdSAndrey Zonov 			    bytes);
78794355cfdSAndrey Zonov 		if (get_struct(pid, (void *)args[sc->offset], fds, bytes)
78894355cfdSAndrey Zonov 		    != -1) {
789e45a5a0dSDavid Malone 			used = 0;
790e45a5a0dSDavid Malone 			tmpsize = 1 + numfds * per_fd + 2;
791e45a5a0dSDavid Malone 			if ((tmp = malloc(tmpsize)) == NULL)
79294355cfdSAndrey Zonov 				err(1, "Cannot alloc %d bytes for fd_set "
79394355cfdSAndrey Zonov 				    "output", tmpsize);
794e45a5a0dSDavid Malone 
795e45a5a0dSDavid Malone 			tmp[used++] = '{';
796e45a5a0dSDavid Malone 			for (i = 0; i < numfds; i++) {
797e45a5a0dSDavid Malone 				if (FD_ISSET(i, fds)) {
79894355cfdSAndrey Zonov 					u = snprintf(tmp + used, per_fd, "%d ",
79994355cfdSAndrey Zonov 					    i);
800e45a5a0dSDavid Malone 					if (u > 0)
801e45a5a0dSDavid Malone 						used += u < per_fd ? u : per_fd;
802e45a5a0dSDavid Malone 				}
803e45a5a0dSDavid Malone 			}
804e45a5a0dSDavid Malone 			if (tmp[used-1] == ' ')
805e45a5a0dSDavid Malone 				used--;
806e45a5a0dSDavid Malone 			tmp[used++] = '}';
807e45a5a0dSDavid Malone 			tmp[used++] = '\0';
80894355cfdSAndrey Zonov 		} else
809e45a5a0dSDavid Malone 			asprintf(&tmp, "0x%lx", args[sc->offset]);
810d8984f48SDag-Erling Smørgrav 		free(fds);
811e45a5a0dSDavid Malone 		break;
812d8984f48SDag-Erling Smørgrav 	}
813d8984f48SDag-Erling Smørgrav 	case Signal: {
814f0ebbc29SDag-Erling Smørgrav 		long sig;
815f0ebbc29SDag-Erling Smørgrav 
816f0ebbc29SDag-Erling Smørgrav 		sig = args[sc->offset];
817d75300bfSAlfred Perlstein 		tmp = strsig(sig);
818d75300bfSAlfred Perlstein 		if (tmp == NULL)
8191bcb5f5aSMarcel Moolenaar 			asprintf(&tmp, "%ld", sig);
820f0ebbc29SDag-Erling Smørgrav 		break;
821d8984f48SDag-Erling Smørgrav 	}
822d8984f48SDag-Erling Smørgrav 	case Sigset: {
823081e5c48SPav Lucistnik 		long sig;
824081e5c48SPav Lucistnik 		sigset_t ss;
825081e5c48SPav Lucistnik 		int i, used;
826081e5c48SPav Lucistnik 
827081e5c48SPav Lucistnik 		sig = args[sc->offset];
82894355cfdSAndrey Zonov 		if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
82994355cfdSAndrey Zonov 		    sizeof(ss)) == -1) {
830081e5c48SPav Lucistnik 			asprintf(&tmp, "0x%lx", args[sc->offset]);
831081e5c48SPav Lucistnik 			break;
832081e5c48SPav Lucistnik 		}
833081e5c48SPav Lucistnik 		tmp = malloc(sys_nsig * 8); /* 7 bytes avg per signal name */
834081e5c48SPav Lucistnik 		used = 0;
835d8984f48SDag-Erling Smørgrav 		for (i = 1; i < sys_nsig; i++) {
83694355cfdSAndrey Zonov 			if (sigismember(&ss, i))
837081e5c48SPav Lucistnik 				used += sprintf(tmp + used, "%s|", strsig(i));
838081e5c48SPav Lucistnik 		}
839081e5c48SPav Lucistnik 		if (used)
840081e5c48SPav Lucistnik 			tmp[used-1] = 0;
841081e5c48SPav Lucistnik 		else
842081e5c48SPav Lucistnik 			strcpy(tmp, "0x0");
843081e5c48SPav Lucistnik 		break;
844d8984f48SDag-Erling Smørgrav 	}
845d8984f48SDag-Erling Smørgrav 	case Sigprocmask: {
846894b8f7aSAlfred Perlstein 		switch (args[sc->offset]) {
847894b8f7aSAlfred Perlstein #define	S(a)	case a: tmp = strdup(#a); break;
848081e5c48SPav Lucistnik 			S(SIG_BLOCK);
849081e5c48SPav Lucistnik 			S(SIG_UNBLOCK);
850081e5c48SPav Lucistnik 			S(SIG_SETMASK);
851894b8f7aSAlfred Perlstein #undef S
852894b8f7aSAlfred Perlstein 		}
853894b8f7aSAlfred Perlstein 		if (tmp == NULL)
854894b8f7aSAlfred Perlstein 			asprintf(&tmp, "0x%lx", args[sc->offset]);
855894b8f7aSAlfred Perlstein 		break;
856d8984f48SDag-Erling Smørgrav 	}
857d8984f48SDag-Erling Smørgrav 	case Fcntlflag: {
858081e5c48SPav Lucistnik 		/* XXX output depends on the value of the previous argument */
859081e5c48SPav Lucistnik 		switch (args[sc->offset-1]) {
860081e5c48SPav Lucistnik 		case F_SETFD:
86194355cfdSAndrey Zonov 			tmp = strdup(xlookup_bits(fcntlfd_arg,
86294355cfdSAndrey Zonov 			    args[sc->offset]));
863081e5c48SPav Lucistnik 			break;
864081e5c48SPav Lucistnik 		case F_SETFL:
86594355cfdSAndrey Zonov 			tmp = strdup(xlookup_bits(fcntlfl_arg,
86694355cfdSAndrey Zonov 			    args[sc->offset]));
867081e5c48SPav Lucistnik 			break;
868081e5c48SPav Lucistnik 		case F_GETFD:
869081e5c48SPav Lucistnik 		case F_GETFL:
870081e5c48SPav Lucistnik 		case F_GETOWN:
871081e5c48SPav Lucistnik 			tmp = strdup("");
872081e5c48SPav Lucistnik 			break;
873081e5c48SPav Lucistnik 		default:
874081e5c48SPav Lucistnik 			asprintf(&tmp, "0x%lx", args[sc->offset]);
875081e5c48SPav Lucistnik 			break;
876081e5c48SPav Lucistnik 		}
877081e5c48SPav Lucistnik 		break;
878d8984f48SDag-Erling Smørgrav 	}
879081e5c48SPav Lucistnik 	case Open:
880081e5c48SPav Lucistnik 		tmp = strdup(xlookup_bits(open_flags, args[sc->offset]));
881081e5c48SPav Lucistnik 		break;
882081e5c48SPav Lucistnik 	case Fcntl:
883081e5c48SPav Lucistnik 		tmp = strdup(xlookup(fcntl_arg, args[sc->offset]));
884081e5c48SPav Lucistnik 		break;
885894b8f7aSAlfred Perlstein 	case Mprot:
886081e5c48SPav Lucistnik 		tmp = strdup(xlookup_bits(mprot_flags, args[sc->offset]));
887894b8f7aSAlfred Perlstein 		break;
888894b8f7aSAlfred Perlstein 	case Mmapflags:
889081e5c48SPav Lucistnik 		tmp = strdup(xlookup_bits(mmap_flags, args[sc->offset]));
890894b8f7aSAlfred Perlstein 		break;
891fde3a7d1SAlfred Perlstein 	case Whence:
892081e5c48SPav Lucistnik 		tmp = strdup(xlookup(whence_arg, args[sc->offset]));
893081e5c48SPav Lucistnik 		break;
894081e5c48SPav Lucistnik 	case Sockdomain:
895081e5c48SPav Lucistnik 		tmp = strdup(xlookup(sockdomain_arg, args[sc->offset]));
896081e5c48SPav Lucistnik 		break;
897081e5c48SPav Lucistnik 	case Socktype:
898081e5c48SPav Lucistnik 		tmp = strdup(xlookup(socktype_arg, args[sc->offset]));
899081e5c48SPav Lucistnik 		break;
900081e5c48SPav Lucistnik 	case Shutdown:
901081e5c48SPav Lucistnik 		tmp = strdup(xlookup(shutdown_arg, args[sc->offset]));
902081e5c48SPav Lucistnik 		break;
903081e5c48SPav Lucistnik 	case Resource:
904081e5c48SPav Lucistnik 		tmp = strdup(xlookup(resource_arg, args[sc->offset]));
905081e5c48SPav Lucistnik 		break;
906081e5c48SPav Lucistnik 	case Pathconf:
907081e5c48SPav Lucistnik 		tmp = strdup(xlookup(pathconf_arg, args[sc->offset]));
908fde3a7d1SAlfred Perlstein 		break;
909d8984f48SDag-Erling Smørgrav 	case Sockaddr: {
910dec17687SBrian Feldman 		struct sockaddr_storage ss;
9119ddd1412SDag-Erling Smørgrav 		char addr[64];
9121be5d704SMark Murray 		struct sockaddr_in *lsin;
9131be5d704SMark Murray 		struct sockaddr_in6 *lsin6;
914dec17687SBrian Feldman 		struct sockaddr_un *sun;
915dec17687SBrian Feldman 		struct sockaddr *sa;
916dec17687SBrian Feldman 		char *p;
917dec17687SBrian Feldman 		u_char *q;
918dec17687SBrian Feldman 		int i;
9199ddd1412SDag-Erling Smørgrav 
920a7a08c7eSMarcel Moolenaar 		if (args[sc->offset] == 0) {
921a7a08c7eSMarcel Moolenaar 			asprintf(&tmp, "NULL");
922a7a08c7eSMarcel Moolenaar 			break;
923a7a08c7eSMarcel Moolenaar 		}
924a7a08c7eSMarcel Moolenaar 
925dec17687SBrian Feldman 		/* yuck: get ss_len */
9265d2d083cSXin LI 		if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
927dec17687SBrian Feldman 		    sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1)
928dec17687SBrian Feldman 			err(1, "get_struct %p", (void *)args[sc->offset]);
9296a656761SAlfred Perlstein 		/*
9306a656761SAlfred Perlstein 		 * If ss_len is 0, then try to guess from the sockaddr type.
9316a656761SAlfred Perlstein 		 * AF_UNIX may be initialized incorrectly, so always frob
9326a656761SAlfred Perlstein 		 * it by using the "right" size.
9336a656761SAlfred Perlstein 		 */
9346a656761SAlfred Perlstein 		if (ss.ss_len == 0 || ss.ss_family == AF_UNIX) {
9356a656761SAlfred Perlstein 			switch (ss.ss_family) {
9366a656761SAlfred Perlstein 			case AF_INET:
9376a656761SAlfred Perlstein 				ss.ss_len = sizeof(*lsin);
9386a656761SAlfred Perlstein 				break;
9396a656761SAlfred Perlstein 			case AF_UNIX:
9406a656761SAlfred Perlstein 				ss.ss_len = sizeof(*sun);
9416a656761SAlfred Perlstein 				break;
9426a656761SAlfred Perlstein 			default:
9436a656761SAlfred Perlstein 				/* hurrrr */
9446a656761SAlfred Perlstein 				break;
9456a656761SAlfred Perlstein 			}
9466a656761SAlfred Perlstein 		}
94794355cfdSAndrey Zonov 		if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
94894355cfdSAndrey Zonov 		    ss.ss_len) == -1) {
949dec17687SBrian Feldman 			err(2, "get_struct %p", (void *)args[sc->offset]);
9509ddd1412SDag-Erling Smørgrav 		}
951dec17687SBrian Feldman 
952dec17687SBrian Feldman 		switch (ss.ss_family) {
953dec17687SBrian Feldman 		case AF_INET:
9541be5d704SMark Murray 			lsin = (struct sockaddr_in *)&ss;
9551be5d704SMark Murray 			inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof addr);
95694355cfdSAndrey Zonov 			asprintf(&tmp, "{ AF_INET %s:%d }", addr,
95794355cfdSAndrey Zonov 			    htons(lsin->sin_port));
958dec17687SBrian Feldman 			break;
959dec17687SBrian Feldman 		case AF_INET6:
9601be5d704SMark Murray 			lsin6 = (struct sockaddr_in6 *)&ss;
96194355cfdSAndrey Zonov 			inet_ntop(AF_INET6, &lsin6->sin6_addr, addr,
96294355cfdSAndrey Zonov 			    sizeof addr);
96394355cfdSAndrey Zonov 			asprintf(&tmp, "{ AF_INET6 [%s]:%d }", addr,
96494355cfdSAndrey Zonov 			    htons(lsin6->sin6_port));
965dec17687SBrian Feldman 			break;
966dec17687SBrian Feldman 		case AF_UNIX:
967dec17687SBrian Feldman 			sun = (struct sockaddr_un *)&ss;
968dec17687SBrian Feldman 			asprintf(&tmp, "{ AF_UNIX \"%s\" }", sun->sun_path);
969dec17687SBrian Feldman 			break;
970dec17687SBrian Feldman 		default:
971dec17687SBrian Feldman 			sa = (struct sockaddr *)&ss;
97294355cfdSAndrey Zonov 			asprintf(&tmp, "{ sa_len = %d, sa_family = %d, sa_data "
97394355cfdSAndrey Zonov 			    "= {%n%*s } }", (int)sa->sa_len, (int)sa->sa_family,
97494355cfdSAndrey Zonov 			    &i, 6 * (int)(sa->sa_len - ((char *)&sa->sa_data -
97594355cfdSAndrey Zonov 			    (char *)sa)), "");
976dec17687SBrian Feldman 			if (tmp != NULL) {
977dec17687SBrian Feldman 				p = tmp + i;
97894355cfdSAndrey Zonov 				for (q = (u_char *)&sa->sa_data;
97994355cfdSAndrey Zonov 				    q < (u_char *)sa + sa->sa_len; q++)
980dec17687SBrian Feldman 					p += sprintf(p, " %#02x,", *q);
981dec17687SBrian Feldman 			}
982dec17687SBrian Feldman 		}
9839ddd1412SDag-Erling Smørgrav 		break;
984d8984f48SDag-Erling Smørgrav 	}
985d8984f48SDag-Erling Smørgrav 	case Sigaction: {
986e45a5a0dSDavid Malone 		struct sigaction sa;
987e45a5a0dSDavid Malone 		char *hand;
988e45a5a0dSDavid Malone 		const char *h;
989e45a5a0dSDavid Malone 
99094355cfdSAndrey Zonov 		if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa))
99194355cfdSAndrey Zonov 		    != -1) {
992e45a5a0dSDavid Malone 			asprintf(&hand, "%p", sa.sa_handler);
993e45a5a0dSDavid Malone 			if (sa.sa_handler == SIG_DFL)
994e45a5a0dSDavid Malone 				h = "SIG_DFL";
995e45a5a0dSDavid Malone 			else if (sa.sa_handler == SIG_IGN)
996e45a5a0dSDavid Malone 				h = "SIG_IGN";
997e45a5a0dSDavid Malone 			else
998e45a5a0dSDavid Malone 				h = hand;
999081e5c48SPav Lucistnik 
100094355cfdSAndrey Zonov 			asprintf(&tmp, "{ %s %s ss_t }", h,
1001081e5c48SPav Lucistnik 			    xlookup_bits(sigaction_flags, sa.sa_flags));
1002e45a5a0dSDavid Malone 			free(hand);
100394355cfdSAndrey Zonov 		} else
1004e45a5a0dSDavid Malone 			asprintf(&tmp, "0x%lx", args[sc->offset]);
1005e45a5a0dSDavid Malone 		break;
1006d8984f48SDag-Erling Smørgrav 	}
1007d8984f48SDag-Erling Smørgrav 	case Kevent: {
1008081e5c48SPav Lucistnik 		/*
1009081e5c48SPav Lucistnik 		 * XXX XXX: the size of the array is determined by either the
1010081e5c48SPav Lucistnik 		 * next syscall argument, or by the syscall returnvalue,
1011081e5c48SPav Lucistnik 		 * depending on which argument number we are.  This matches the
1012081e5c48SPav Lucistnik 		 * kevent syscall, but luckily that's the only syscall that uses
1013081e5c48SPav Lucistnik 		 * them.
1014081e5c48SPav Lucistnik 		 */
1015081e5c48SPav Lucistnik 		struct kevent *ke;
1016081e5c48SPav Lucistnik 		int numevents = -1;
1017081e5c48SPav Lucistnik 		int bytes = 0;
1018081e5c48SPav Lucistnik 		int i, tmpsize, u, used;
1019081e5c48SPav Lucistnik 		const int per_ke = 100;
1020081e5c48SPav Lucistnik 
1021081e5c48SPav Lucistnik 		if (sc->offset == 1)
1022081e5c48SPav Lucistnik 			numevents = args[sc->offset+1];
1023081e5c48SPav Lucistnik 		else if (sc->offset == 3 && retval != -1)
1024081e5c48SPav Lucistnik 			numevents = retval;
1025081e5c48SPav Lucistnik 
1026081e5c48SPav Lucistnik 		if (numevents >= 0)
1027081e5c48SPav Lucistnik 			bytes = sizeof(struct kevent) * numevents;
1028081e5c48SPav Lucistnik 		if ((ke = malloc(bytes)) == NULL)
102994355cfdSAndrey Zonov 			err(1, "Cannot malloc %d bytes for kevent array",
103094355cfdSAndrey Zonov 			    bytes);
103194355cfdSAndrey Zonov 		if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset],
103294355cfdSAndrey Zonov 		    ke, bytes) != -1) {
1033081e5c48SPav Lucistnik 			used = 0;
1034081e5c48SPav Lucistnik 			tmpsize = 1 + per_ke * numevents + 2;
1035081e5c48SPav Lucistnik 			if ((tmp = malloc(tmpsize)) == NULL)
103694355cfdSAndrey Zonov 				err(1, "Cannot alloc %d bytes for kevent "
103794355cfdSAndrey Zonov 				    "output", tmpsize);
1038081e5c48SPav Lucistnik 
1039081e5c48SPav Lucistnik 			tmp[used++] = '{';
1040081e5c48SPav Lucistnik 			for (i = 0; i < numevents; i++) {
1041081e5c48SPav Lucistnik 				u = snprintf(tmp + used, per_ke,
1042081e5c48SPav Lucistnik 				    "%s%p,%s,%s,%d,%p,%p",
1043081e5c48SPav Lucistnik 				    i > 0 ? " " : "",
1044081e5c48SPav Lucistnik 				    (void *)ke[i].ident,
1045081e5c48SPav Lucistnik 				    xlookup(kevent_filters, ke[i].filter),
1046081e5c48SPav Lucistnik 				    xlookup_bits(kevent_flags, ke[i].flags),
1047081e5c48SPav Lucistnik 				    ke[i].fflags,
1048081e5c48SPav Lucistnik 				    (void *)ke[i].data,
1049081e5c48SPav Lucistnik 				    (void *)ke[i].udata);
1050081e5c48SPav Lucistnik 				if (u > 0)
1051081e5c48SPav Lucistnik 					used += u < per_ke ? u : per_ke;
1052081e5c48SPav Lucistnik 			}
1053081e5c48SPav Lucistnik 			tmp[used++] = '}';
1054081e5c48SPav Lucistnik 			tmp[used++] = '\0';
1055d8984f48SDag-Erling Smørgrav 		} else {
1056081e5c48SPav Lucistnik 			asprintf(&tmp, "0x%lx", args[sc->offset]);
1057081e5c48SPav Lucistnik 		}
1058d8984f48SDag-Erling Smørgrav 		free(ke);
1059081e5c48SPav Lucistnik 		break;
1060d8984f48SDag-Erling Smørgrav 	}
1061d8984f48SDag-Erling Smørgrav 	case Stat: {
1062081e5c48SPav Lucistnik 		struct stat st;
106394355cfdSAndrey Zonov 		if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st))
106494355cfdSAndrey Zonov 		    != -1) {
1065081e5c48SPav Lucistnik 			char mode[12];
1066081e5c48SPav Lucistnik 			strmode(st.st_mode, mode);
106794355cfdSAndrey Zonov 			asprintf(&tmp,
106894355cfdSAndrey Zonov 			    "{ mode=%s,inode=%jd,size=%jd,blksize=%ld }", mode,
106994355cfdSAndrey Zonov 			    (intmax_t)st.st_ino, (intmax_t)st.st_size,
107094355cfdSAndrey Zonov 			    (long)st.st_blksize);
1071d8984f48SDag-Erling Smørgrav 		} else {
1072081e5c48SPav Lucistnik 			asprintf(&tmp, "0x%lx", args[sc->offset]);
1073081e5c48SPav Lucistnik 		}
1074081e5c48SPav Lucistnik 		break;
1075d8984f48SDag-Erling Smørgrav 	}
1076d8984f48SDag-Erling Smørgrav 	case Rusage: {
1077081e5c48SPav Lucistnik 		struct rusage ru;
107894355cfdSAndrey Zonov 		if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru))
107994355cfdSAndrey Zonov 		    != -1) {
108094355cfdSAndrey Zonov 			asprintf(&tmp,
108194355cfdSAndrey Zonov 			    "{ u=%ld.%06ld,s=%ld.%06ld,in=%ld,out=%ld }",
1082081e5c48SPav Lucistnik 			    (long)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
1083081e5c48SPav Lucistnik 			    (long)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
1084081e5c48SPav Lucistnik 			    ru.ru_inblock, ru.ru_oublock);
108594355cfdSAndrey Zonov 		} else
1086081e5c48SPav Lucistnik 			asprintf(&tmp, "0x%lx", args[sc->offset]);
1087081e5c48SPav Lucistnik 		break;
1088d8984f48SDag-Erling Smørgrav 	}
1089d8984f48SDag-Erling Smørgrav 	case Rlimit: {
1090081e5c48SPav Lucistnik 		struct rlimit rl;
109194355cfdSAndrey Zonov 		if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl))
109294355cfdSAndrey Zonov 		    != -1) {
1093081e5c48SPav Lucistnik 			asprintf(&tmp, "{ cur=%ju,max=%ju }",
1094081e5c48SPav Lucistnik 			    rl.rlim_cur, rl.rlim_max);
109594355cfdSAndrey Zonov 		} else
1096081e5c48SPav Lucistnik 			asprintf(&tmp, "0x%lx", args[sc->offset]);
1097081e5c48SPav Lucistnik 		break;
1098d8984f48SDag-Erling Smørgrav 	}
1099081e5c48SPav Lucistnik 	default:
1100081e5c48SPav Lucistnik 		errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
1101bbeaf6c0SSean Eric Fagan 	}
1102d8984f48SDag-Erling Smørgrav 	return (tmp);
1103bbeaf6c0SSean Eric Fagan }
1104bbeaf6c0SSean Eric Fagan 
1105bbeaf6c0SSean Eric Fagan /*
1106bbeaf6c0SSean Eric Fagan  * print_syscall
1107bbeaf6c0SSean Eric Fagan  * Print (to outfile) the system call and its arguments.  Note that
1108bbeaf6c0SSean Eric Fagan  * nargs is the number of arguments (not the number of words; this is
1109bbeaf6c0SSean Eric Fagan  * potentially confusing, I know).
1110bbeaf6c0SSean Eric Fagan  */
1111bbeaf6c0SSean Eric Fagan 
1112bbeaf6c0SSean Eric Fagan void
111394355cfdSAndrey Zonov print_syscall(struct trussinfo *trussinfo, const char *name, int nargs,
111494355cfdSAndrey Zonov     char **s_args)
1115d8984f48SDag-Erling Smørgrav {
1116203098d8SMatthew N. Dodd 	struct timespec timediff;
111794355cfdSAndrey Zonov 	int i, len;
11180d0bd00eSMatthew N. Dodd 
111994355cfdSAndrey Zonov 	len = 0;
1120c03bfcc8SMatthew N. Dodd 	if (trussinfo->flags & FOLLOWFORKS)
1121c03bfcc8SMatthew N. Dodd 		len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid);
1122c03bfcc8SMatthew N. Dodd 
112394355cfdSAndrey Zonov 	if (name != NULL && (strcmp(name, "execve") == 0 ||
112494355cfdSAndrey Zonov 	    strcmp(name, "exit") == 0)) {
11255695afdeSAndrey Zonov 		clock_gettime(CLOCK_REALTIME, &trussinfo->curthread->after);
11260d0bd00eSMatthew N. Dodd 	}
11270d0bd00eSMatthew N. Dodd 
11280d0bd00eSMatthew N. Dodd 	if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
1129*d9dcc463SXin LI 		timespecsubt(&trussinfo->curthread->after,
11305695afdeSAndrey Zonov 		    &trussinfo->start_time, &timediff);
113137169f94SMatthew N. Dodd 		len += fprintf(trussinfo->outfile, "%ld.%09ld ",
1132fb034d05SMatthew N. Dodd 		    (long)timediff.tv_sec, timediff.tv_nsec);
11330d0bd00eSMatthew N. Dodd 	}
11340d0bd00eSMatthew N. Dodd 
11350d0bd00eSMatthew N. Dodd 	if (trussinfo->flags & RELATIVETIMESTAMPS) {
1136*d9dcc463SXin LI 		timespecsubt(&trussinfo->curthread->after,
11375695afdeSAndrey Zonov 		    &trussinfo->curthread->before, &timediff);
113837169f94SMatthew N. Dodd 		len += fprintf(trussinfo->outfile, "%ld.%09ld ",
1139fb034d05SMatthew N. Dodd 		    (long)timediff.tv_sec, timediff.tv_nsec);
11400d0bd00eSMatthew N. Dodd 	}
11410d0bd00eSMatthew N. Dodd 
1142ec0bed25SMatthew N. Dodd 	len += fprintf(trussinfo->outfile, "%s(", name);
1143c03bfcc8SMatthew N. Dodd 
1144bbeaf6c0SSean Eric Fagan 	for (i = 0; i < nargs; i++) {
1145bbeaf6c0SSean Eric Fagan 		if (s_args[i])
1146ec0bed25SMatthew N. Dodd 			len += fprintf(trussinfo->outfile, "%s", s_args[i]);
1147bbeaf6c0SSean Eric Fagan 		else
114894355cfdSAndrey Zonov 			len += fprintf(trussinfo->outfile,
114994355cfdSAndrey Zonov 			    "<missing argument>");
115094355cfdSAndrey Zonov 		len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ?
115194355cfdSAndrey Zonov 		    "," : "");
1152bbeaf6c0SSean Eric Fagan 	}
1153ec0bed25SMatthew N. Dodd 	len += fprintf(trussinfo->outfile, ")");
11546cb533feSSean Eric Fagan 	for (i = 0; i < 6 - (len / 8); i++)
1155ec0bed25SMatthew N. Dodd 		fprintf(trussinfo->outfile, "\t");
11566cb533feSSean Eric Fagan }
11576cb533feSSean Eric Fagan 
11586cb533feSSean Eric Fagan void
11591bcb5f5aSMarcel Moolenaar print_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs,
1160ee3b0f6eSDiomidis Spinellis     char **s_args, int errorp, long retval, struct syscall *sc)
11611bcb5f5aSMarcel Moolenaar {
1162ee3b0f6eSDiomidis Spinellis 	struct timespec timediff;
1163ee3b0f6eSDiomidis Spinellis 
1164ee3b0f6eSDiomidis Spinellis 	if (trussinfo->flags & COUNTONLY) {
1165ee3b0f6eSDiomidis Spinellis 		if (!sc)
1166ee3b0f6eSDiomidis Spinellis 			return;
11675695afdeSAndrey Zonov 		clock_gettime(CLOCK_REALTIME, &trussinfo->curthread->after);
1168*d9dcc463SXin LI 		timespecsubt(&trussinfo->curthread->after,
11695695afdeSAndrey Zonov 		    &trussinfo->curthread->before, &timediff);
1170*d9dcc463SXin LI 		timespecadd(&sc->time, &timediff, &sc->time);
1171ee3b0f6eSDiomidis Spinellis 		sc->ncalls++;
1172ee3b0f6eSDiomidis Spinellis 		if (errorp)
1173ee3b0f6eSDiomidis Spinellis 			sc->nerror++;
1174ee3b0f6eSDiomidis Spinellis 		return;
1175ee3b0f6eSDiomidis Spinellis 	}
1176d8984f48SDag-Erling Smørgrav 
1177ec0bed25SMatthew N. Dodd 	print_syscall(trussinfo, name, nargs, s_args);
11780cf21b4fSBrian Somers 	fflush(trussinfo->outfile);
117994355cfdSAndrey Zonov 	if (errorp)
118094355cfdSAndrey Zonov 		fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval,
118194355cfdSAndrey Zonov 		    strerror(retval));
118294355cfdSAndrey Zonov 	else {
1183c059fa2eSJaakko Heinonen 		/*
1184c059fa2eSJaakko Heinonen 		 * Because pipe(2) has a special assembly glue to provide the
1185c059fa2eSJaakko Heinonen 		 * libc API, we have to adjust retval.
1186c059fa2eSJaakko Heinonen 		 */
118794355cfdSAndrey Zonov 		if (name != NULL && strcmp(name, "pipe") == 0)
1188c059fa2eSJaakko Heinonen 			retval = 0;
11891bcb5f5aSMarcel Moolenaar 		fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval, retval);
11906cb533feSSean Eric Fagan 	}
1191bbeaf6c0SSean Eric Fagan }
1192ee3b0f6eSDiomidis Spinellis 
1193ee3b0f6eSDiomidis Spinellis void
1194ee3b0f6eSDiomidis Spinellis print_summary(struct trussinfo *trussinfo)
1195ee3b0f6eSDiomidis Spinellis {
1196ee3b0f6eSDiomidis Spinellis 	struct timespec total = {0, 0};
119794355cfdSAndrey Zonov 	struct syscall *sc;
1198ee3b0f6eSDiomidis Spinellis 	int ncall, nerror;
1199ee3b0f6eSDiomidis Spinellis 
1200ee3b0f6eSDiomidis Spinellis 	fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n",
1201ee3b0f6eSDiomidis Spinellis 	    "syscall", "seconds", "calls", "errors");
1202ee3b0f6eSDiomidis Spinellis 	ncall = nerror = 0;
1203ee3b0f6eSDiomidis Spinellis 	for (sc = syscalls; sc->name != NULL; sc++)
1204ee3b0f6eSDiomidis Spinellis 		if (sc->ncalls) {
120555a8d2bbSJaakko Heinonen 			fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
120655a8d2bbSJaakko Heinonen 			    sc->name, (intmax_t)sc->time.tv_sec,
120755a8d2bbSJaakko Heinonen 			    sc->time.tv_nsec, sc->ncalls, sc->nerror);
1208*d9dcc463SXin LI 			timespecadd(&total, &sc->time, &total);
1209ee3b0f6eSDiomidis Spinellis 			ncall += sc->ncalls;
1210ee3b0f6eSDiomidis Spinellis 			nerror += sc->nerror;
1211ee3b0f6eSDiomidis Spinellis 		}
1212ee3b0f6eSDiomidis Spinellis 	fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n",
1213ee3b0f6eSDiomidis Spinellis 	    "", "-------------", "-------", "-------");
121455a8d2bbSJaakko Heinonen 	fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n",
121555a8d2bbSJaakko Heinonen 	    "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror);
1216ee3b0f6eSDiomidis Spinellis }
1217