]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/truss/syscalls.c
This commit was generated by cvs2svn to compensate for changes in r171537,
[FreeBSD/FreeBSD.git] / usr.bin / truss / syscalls.c
1 /*
2  * Copryight 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 #ifndef lint
33 static const char rcsid[] =
34   "$FreeBSD$";
35 #endif /* not lint */
36
37 /*
38  * This file has routines used to print out system calls and their
39  * arguments.
40  */
41
42 #include <sys/mman.h>
43 #include <sys/types.h>
44 #include <sys/ptrace.h>
45 #include <sys/socket.h>
46 #include <sys/time.h>
47 #include <sys/un.h>
48 #include <netinet/in.h>
49 #include <arpa/inet.h>
50 #include <sys/ioccom.h>
51 #include <machine/atomic.h>
52 #include <errno.h>
53 #include <sys/umtx.h>
54 #include <sys/event.h>
55 #include <sys/stat.h>
56 #include <sys/resource.h>
57
58 #include <ctype.h>
59 #include <err.h>
60 #include <fcntl.h>
61 #include <poll.h>
62 #include <signal.h>
63 #include <stdint.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <time.h>
68 #include <unistd.h>
69 #include <vis.h>
70
71 #include "truss.h"
72 #include "extern.h"
73 #include "syscall.h"
74
75 /*
76  * This should probably be in its own file, sorted alphabetically.
77  */
78
79 struct syscall syscalls[] = {
80         { "fcntl", 1, 3,
81           { { Int, 0 } , { Fcntl, 1 }, { Fcntlflag | OUT, 2 }}},
82         { "readlink", 1, 3,
83           { { Name, 0 } , { Readlinkres | OUT, 1 }, { Int, 2 }}},
84         { "lseek", 2, 3,
85 #ifdef __LP64__
86           { { Int, 0 }, {Quad, 2 }, { Whence, 3 }}},
87 #else
88           { { Int, 0 }, {Quad, 2 }, { Whence, 4 }}},
89 #endif
90         { "linux_lseek", 2, 3,
91           { { Int, 0 }, {Int, 1 }, { Whence, 2 }}},
92         { "mmap", 2, 6,
93 #ifdef __LP64__
94           { { Ptr, 0 }, {Int, 1}, {Mprot, 2}, {Mmapflags, 3}, {Int, 4}, {Quad, 5}}},
95 #else
96           { { Ptr, 0 }, {Int, 1}, {Mprot, 2}, {Mmapflags, 3}, {Int, 4}, {Quad, 6}}},
97 #endif
98         { "mprotect", 1, 3,
99           { { Ptr, 0 }, {Int, 1}, {Mprot, 2}}},
100         { "open", 1, 3,
101           { { Name | IN, 0} , { Open, 1}, {Octal, 2}}},
102         { "mkdir", 1, 2,
103           { { Name, 0} , {Octal, 1}}},
104         { "linux_open", 1, 3,
105           { { Name, 0 }, { Hex, 1}, { Octal, 2 }}},
106         { "close", 1, 1,
107           { { Int, 0 } } },
108         { "link", 0, 2,
109           { { Name, 0 }, { Name, 1 }}},
110         { "unlink", 0, 1,
111           { { Name, 0 }}},
112         { "chdir", 0, 1,
113           { { Name, 0 }}},
114         { "chroot", 0, 1,
115           { { Name, 0 }}},
116         { "mknod", 0, 3,
117           { { Name, 0 }, { Octal, 1 }, { Int, 3 }}},
118         { "chmod", 0, 2,
119           { { Name, 0 }, { Octal, 1 }}},
120         { "chown", 0, 3,
121           { { Name, 0 }, { Int, 1 }, { Int, 2 }}},
122         { "mount", 0, 4,
123           { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 }}},
124         { "umount", 0, 2,
125           { { Name, 0 }, { Int, 2 }}},
126         { "fstat", 1, 2,
127           { { Int, 0}, { Stat | OUT , 1 }}},
128         { "stat", 1, 2,
129           { { Name | IN, 0 }, { Stat | OUT, 1 }}},
130         { "lstat", 1, 2,
131           { { Name | IN, 0 }, { Stat | OUT, 1 }}},
132         { "linux_newstat", 1, 2,
133           { { Name | IN, 0 }, { Ptr | OUT, 1 }}},
134         { "linux_newfstat", 1, 2,
135           { { Int, 0 }, { Ptr | OUT, 1 }}},
136         { "write", 1, 3,
137           { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }}},
138         { "ioctl", 1, 3,
139           { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 }}},
140         { "break", 1, 1, { { Hex, 0 }}},
141         { "exit", 0, 1, { { Hex, 0 }}},
142         { "access", 1, 2, { { Name | IN, 0 }, { Int, 1 }}},
143         { "sigaction", 1, 3,
144           { { Signal, 0 }, { Sigaction | IN, 1 }, { Sigaction | OUT, 2 }}},
145         { "accept", 1, 3,
146           { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
147         { "bind", 1, 3,
148           { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
149         { "connect", 1, 3,
150           { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } },
151         { "getpeername", 1, 3,
152           { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
153         { "getsockname", 1, 3,
154           { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } },
155         { "recvfrom", 1, 6,
156           { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } },
157         { "sendto", 1, 6,
158           { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } },
159         { "execve", 1, 3,
160           { { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } },
161         { "linux_execve", 1, 3,
162           { { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } },
163         { "kldload", 0, 1, { { Name | IN, 0 }}},
164         { "kldunload", 0, 1, { { Int, 0 }}},
165         { "kldfind", 0, 1, { { Name | IN, 0 }}},
166         { "kldnext", 0, 1, { { Int, 0 }}},
167         { "kldstat", 0, 2, { { Int, 0 }, { Ptr, 1 }}},
168         { "kldfirstmod", 0, 1, { { Int, 0 }}},
169         { "nanosleep", 0, 1, { { Timespec, 0 }}},
170         { "select", 1, 5, { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, { Timeval, 4 }}},
171         { "poll", 1, 3, { { Pollfd, 0 }, { Int, 1 }, { Int, 2 }}},
172         { "gettimeofday", 1, 2, { { Timeval | OUT, 0 }, { Ptr, 1 }}},
173         { "clock_gettime", 1, 2, { { Int, 0 }, { Timespec | OUT, 1 }}},
174         { "getitimer", 1, 2, { { Int, 0 }, { Itimerval | OUT, 2 }}},
175         { "setitimer", 1, 3, { { Int, 0 }, { Itimerval, 1} , { Itimerval | OUT, 2 }}},
176         { "kse_release", 0, 1, { { Timespec, 0 }}},
177         { "kevent", 0, 6, { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 }, { Int, 4 }, { Timespec, 5 }}},
178         { "_umtx_lock", 0, 1, { { Umtx, 0 }}},
179         { "_umtx_unlock", 0, 1, { { Umtx, 0 }}},
180         { "sigprocmask", 0, 3, { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 }}},
181         { "unmount", 1, 2, { { Name, 0 }, { Int, 1 }}},
182         { "socket", 1, 3, { { Sockdomain, 0}, { Socktype, 1}, {Int, 2 }}},
183         { "getrusage", 1, 2, { { Int, 0 }, { Rusage | OUT, 1 }}},
184         { "__getcwd", 1, 2, { { Name | OUT, 0}, { Int, 1 }}},
185         { "shutdown", 1, 2, { { Int, 0}, { Shutdown, 1}}},
186         { "getrlimit", 1, 2, { { Resource, 0}, {Rlimit | OUT, 1}}},
187         { "setrlimit", 1, 2, { { Resource, 0}, {Rlimit | IN, 1}}},
188         { "utimes", 1, 2,
189                 { { Name | IN, 0 }, { Timeval2 | IN, 1 }}},
190         { "lutimes", 1, 2,
191                 { { Name | IN, 0 }, { Timeval2 | IN, 1 }}},
192         { "futimes", 1, 2,
193                 { { Int, 0 }, { Timeval | IN, 1 }}},
194         { "chflags", 1, 2,
195                 { { Name | IN, 0 }, { Hex, 1 }}},
196         { "lchflags", 1, 2,
197                 { { Name | IN, 0 }, { Hex, 1 }}},
198         { "pathconf", 1, 2,
199                 { { Name | IN, 0 }, { Pathconf, 1 }}},
200         { "truncate", 1, 3,
201                 { { Name | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 }}},
202         { "ftruncate", 1, 3,
203                 { { Int | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 }}},
204         { "kill", 1, 2,
205                 { { Int | IN, 0 }, { Signal | IN, 1}}},
206         { "munmap", 1, 2,
207                 { { Ptr, 0 }, { Int, 1 }}},
208         { "read", 1, 3,
209           { { Int, 0}, { BinString | OUT, 1}, { Int, 2}}},
210         { "rename", 1, 2,
211           { { Name , 0} , { Name, 1}}},
212         { "symlink", 1, 2,
213           { { Name , 0} , { Name, 1}}},
214         { 0, 0, 0, { { 0, 0 }}},
215 };
216
217 /* Xlat idea taken from strace */
218 struct xlat {
219         int val;
220         const char *str;
221 };
222
223 #define X(a) { a, #a },
224 #define XEND { 0, NULL }
225
226 static struct xlat kevent_filters[] = {
227         X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE)
228         X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER)
229         X(EVFILT_NETDEV) X(EVFILT_FS) X(EVFILT_READ) XEND
230 };
231
232 static struct xlat kevent_flags[] = {
233         X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT)
234         X(EV_CLEAR) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND
235 };
236
237 struct xlat poll_flags[] = {
238         X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR)
239         X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND)
240         X(POLLWRBAND) X(POLLINIGNEOF) XEND
241 };
242
243 static struct xlat mmap_flags[] = {
244         X(MAP_SHARED) X(MAP_PRIVATE) X(MAP_FIXED) X(MAP_RENAME)
245         X(MAP_NORESERVE) X(MAP_RESERVED0080) X(MAP_RESERVED0100)
246         X(MAP_HASSEMAPHORE) X(MAP_STACK) X(MAP_NOSYNC) X(MAP_ANON)
247         X(MAP_NOCORE) XEND
248 };
249
250 static struct xlat mprot_flags[] = {
251         X(PROT_NONE) X(PROT_READ) X(PROT_WRITE) X(PROT_EXEC) XEND
252 };
253
254 static struct xlat whence_arg[] = {
255         X(SEEK_SET) X(SEEK_CUR) X(SEEK_END) XEND
256 };
257
258 static struct xlat sigaction_flags[] = {
259         X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP)
260         X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND
261 };
262
263 static struct xlat fcntl_arg[] = {
264         X(F_DUPFD) X(F_GETFD) X(F_SETFD) X(F_GETFL) X(F_SETFL)
265         X(F_GETOWN) X(F_SETOWN) X(F_GETLK) X(F_SETLK) X(F_SETLKW) XEND
266 };
267
268 static struct xlat fcntlfd_arg[] = {
269         X(FD_CLOEXEC) XEND
270 };
271
272 static struct xlat fcntlfl_arg[] = {
273         X(O_APPEND) X(O_ASYNC) X(O_FSYNC) X(O_NONBLOCK) X(O_NOFOLLOW)
274         X(O_DIRECT) XEND
275 };
276
277 static struct xlat sockdomain_arg[] = {
278         X(PF_UNSPEC) X(PF_LOCAL) X(PF_UNIX) X(PF_INET) X(PF_IMPLINK)
279         X(PF_PUP) X(PF_CHAOS) X(PF_NETBIOS) X(PF_ISO) X(PF_OSI)
280         X(PF_ECMA) X(PF_DATAKIT) X(PF_CCITT) X(PF_SNA) X(PF_DECnet)
281         X(PF_DLI) X(PF_LAT) X(PF_HYLINK) X(PF_APPLETALK) X(PF_ROUTE)
282         X(PF_LINK) X(PF_XTP) X(PF_COIP) X(PF_CNT) X(PF_SIP) X(PF_IPX)
283         X(PF_RTIP) X(PF_PIP) X(PF_ISDN) X(PF_KEY) X(PF_INET6)
284         X(PF_NATM) X(PF_ATM) X(PF_NETGRAPH) X(PF_SLOW) X(PF_SCLUSTER)
285         X(PF_ARP) X(PF_BLUETOOTH) XEND
286 };
287
288 static struct xlat socktype_arg[] = {
289         X(SOCK_STREAM) X(SOCK_DGRAM) X(SOCK_RAW) X(SOCK_RDM)
290         X(SOCK_SEQPACKET) XEND
291 };
292
293 static struct xlat open_flags[] = {
294         X(O_RDONLY) X(O_WRONLY) X(O_RDWR) X(O_ACCMODE) X(O_NONBLOCK)
295         X(O_APPEND) X(O_SHLOCK) X(O_EXLOCK) X(O_ASYNC) X(O_FSYNC)
296         X(O_NOFOLLOW) X(O_CREAT) X(O_TRUNC) X(O_EXCL) X(O_NOCTTY)
297         X(O_DIRECT) XEND
298 };
299
300 static struct xlat shutdown_arg[] = {
301         X(SHUT_RD) X(SHUT_WR) X(SHUT_RDWR) XEND
302 };
303
304 static struct xlat resource_arg[] = {
305         X(RLIMIT_CPU) X(RLIMIT_FSIZE) X(RLIMIT_DATA) X(RLIMIT_STACK)
306         X(RLIMIT_CORE) X(RLIMIT_RSS) X(RLIMIT_MEMLOCK) X(RLIMIT_NPROC)
307         X(RLIMIT_NOFILE) X(RLIMIT_SBSIZE) X(RLIMIT_VMEM) XEND
308 };
309
310 static struct xlat pathconf_arg[] = {
311         X(_PC_LINK_MAX)  X(_PC_MAX_CANON)  X(_PC_MAX_INPUT)
312         X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF)
313         X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE)
314         X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO)
315         X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS)
316         X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE)
317         X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN)
318         X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX)
319         X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT)
320         XEND
321 };
322
323 #undef X
324 #undef XEND
325
326 /* Searches an xlat array for a value, and returns it if found.  Otherwise
327    return a string representation. */
328 static const char 
329 *lookup(struct xlat *xlat, int val, int base)
330 {
331         static char tmp[16];
332         for (; xlat->str != NULL; xlat++)
333                 if (xlat->val == val)
334                         return xlat->str;
335         switch (base) {
336                 case 8:
337                         sprintf(tmp, "0%o", val);
338                         break;
339                 case 16:
340                         sprintf(tmp, "0x%x", val);
341                         break;
342                 case 10:
343                         sprintf(tmp, "%u", val);
344                         break;
345                 default:
346                         errx(1,"Unknown lookup base");
347                         break;
348         }
349         return tmp;
350 }
351
352 static const char *
353 xlookup(struct xlat *xlat, int val)
354 {
355         return lookup(xlat, val, 16);
356 }
357
358 /* Searches an xlat array containing bitfield values.  Remaining bits
359    set after removing the known ones are printed at the end:
360    IN|0x400 */
361 static char
362 *xlookup_bits(struct xlat *xlat, int val)
363 {
364         static char str[512];
365         int len = 0;
366         int rem = val;
367
368         for (; xlat->str != NULL; xlat++)
369         {
370                 if ((xlat->val & rem) == xlat->val)
371                 {
372                         /* don't print the "all-bits-zero" string unless all
373                            bits are really zero */
374                         if (xlat->val == 0 && val != 0)
375                                 continue;
376                         len += sprintf(str + len, "%s|", xlat->str);
377                         rem &= ~(xlat->val);
378                 }
379         }
380         /* if we have leftover bits or didn't match anything */
381         if (rem || len == 0)
382                 len += sprintf(str + len, "0x%x", rem);
383         if (len && str[len - 1] == '|')
384                 len--;
385         str[len] = 0;
386         return str;
387 }
388
389 /*
390  * If/when the list gets big, it might be desirable to do it
391  * as a hash table or binary search.
392  */
393
394 struct syscall *
395 get_syscall(const char *name) {
396         struct syscall *sc = syscalls;
397
398         if (name == NULL)
399                 return (NULL);
400         while (sc->name) {
401                 if (!strcmp(name, sc->name))
402                         return sc;
403                 sc++;
404         }
405         return NULL;
406 }
407
408 /*
409  * get_struct
410  *
411  * Copy a fixed amount of bytes from the process.
412  */
413
414 static int
415 get_struct(int pid, void *offset, void *buf, int len) {
416         struct ptrace_io_desc iorequest;
417         
418         iorequest.piod_op = PIOD_READ_D;
419         iorequest.piod_offs = offset;
420         iorequest.piod_addr = buf;
421         iorequest.piod_len = len;
422         if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0)
423                 return -1;      
424         return 0;
425 }
426
427 #define MAXSIZE 4096 
428 #define BLOCKSIZE 1024 
429 /*
430  * get_string
431  * Copy a string from the process.  Note that it is
432  * expected to be a C string, but if max is set, it will
433  * only get that much.
434  */
435
436 static char *
437 get_string(pid_t pid, void *offset, int max) {
438         char *buf;
439         struct ptrace_io_desc iorequest;
440         int totalsize, size;
441         int diff = 0;
442         int i;
443         
444         totalsize = size = max ? (max + 1) : BLOCKSIZE; 
445         buf = malloc(totalsize);
446         if (buf == NULL)
447                 return NULL;
448         for(;;) {
449                 diff = totalsize - size;
450                 iorequest.piod_op = PIOD_READ_D;
451                 iorequest.piod_offs = (char *)offset + diff;
452                 iorequest.piod_addr = buf + diff;
453                 iorequest.piod_len = size;
454                 if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) {
455                         free(buf);
456                         return NULL;
457                 }
458                 for (i = 0 ; i < size; i++) {
459                         if (buf[diff + i] == '\0')
460                                 return (buf);
461                 }
462                 if (totalsize < MAXSIZE - BLOCKSIZE && max == 0) {
463                         totalsize += BLOCKSIZE;
464                         buf = realloc(buf, totalsize);
465                         size = BLOCKSIZE;
466                 }
467                 else {
468                         buf[totalsize] = '\0';
469                         return buf;     
470                 }
471         }
472 }
473
474
475 /*
476  * print_arg
477  * Converts a syscall argument into a string.  Said string is
478  * allocated via malloc(), so needs to be free()'d.  The file
479  * descriptor is for the process' memory (via /proc), and is used
480  * to get any data (where the argument is a pointer).  sc is
481  * a pointer to the syscall description (see above); args is
482  * an array of all of the system call arguments.
483  */
484
485 char *
486 print_arg(struct syscall_args *sc, unsigned long *args, long retval, struct trussinfo *trussinfo) {
487   char *tmp = NULL;
488   int pid = trussinfo->pid;
489   switch (sc->type & ARG_MASK) {
490   case Hex:
491     asprintf(&tmp, "0x%lx", args[sc->offset]);
492     break;
493   case Octal:
494     asprintf(&tmp, "0%lo", args[sc->offset]);
495     break;
496   case Int:
497     asprintf(&tmp, "%ld", args[sc->offset]);
498     break;
499   case Name:
500     {
501       /* NULL-terminated string. */
502       char *tmp2;
503       tmp2 = get_string(pid, (void*)args[sc->offset], 0);
504       asprintf(&tmp, "\"%s\"", tmp2);
505       free(tmp2);
506     }
507   break;
508   case BinString:
509     {
510       /* Binary block of data that might have printable characters.
511          XXX If type|OUT, assume that the length is the syscall's
512          return value.  Otherwise, assume that the length of the block
513          is in the next syscall argument. */
514       int max_string = trussinfo->strsize;
515       char tmp2[max_string+1], *tmp3;
516       int len;
517       int truncated = 0;
518
519       if (sc->type & OUT)
520         len = retval;
521       else
522         len = args[sc->offset + 1];
523
524       /* Don't print more than max_string characters, to avoid word
525          wrap.  If we have to truncate put some ... after the string.
526          */
527       if (len > max_string) {
528         len = max_string;
529         truncated = 1;
530       }
531       if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len) != -1) {
532         tmp3 = malloc(len * 4 + 1);
533         while (len) {
534           if (strvisx(tmp3, tmp2, len, VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string)
535             break;
536           len--;
537           truncated = 1;
538         };
539         asprintf(&tmp, "\"%s\"%s", tmp3, truncated?"...":"");
540         free(tmp3);
541       } else
542         asprintf(&tmp, "0x%lx", args[sc->offset]);
543     }
544   break;
545   case StringArray:
546     {
547       int num, size, i;
548       char *tmp2;
549       char *string;
550       char *strarray[100];      /* XXX This is ugly. */
551
552       if (get_struct(pid, (void *)args[sc->offset], (void *)&strarray,
553                      sizeof(strarray)) == -1) {
554         err(1, "get_struct %p", (void *)args[sc->offset]);
555       }
556       num = 0;
557       size = 0;
558
559       /* Find out how large of a buffer we'll need. */
560       while (strarray[num] != NULL) {
561         string = get_string(pid, (void*)strarray[num], 0);
562         size += strlen(string);
563         free(string);
564         num++;
565       }
566       size += 4 + (num * 4);
567       tmp = (char *)malloc(size);
568       tmp2 = tmp;
569
570       tmp2 += sprintf(tmp2, " [");
571       for (i = 0; i < num; i++) {
572         string = get_string(pid, (void*)strarray[i], 0);
573         tmp2 += sprintf(tmp2, " \"%s\"%c", string, (i+1 == num) ? ' ' : ',');
574         free(string);
575       }
576       tmp2 += sprintf(tmp2, "]");
577     }
578   break;
579 #ifdef __LP64__
580   case Quad:
581     asprintf(&tmp, "0x%lx", args[sc->offset]);
582     break;
583 #else
584   case Quad:
585     {
586       unsigned long long ll;
587       ll = *(unsigned long long *)(args + sc->offset);
588       asprintf(&tmp, "0x%llx", ll);
589       break;
590     }
591 #endif
592   case Ptr:
593     asprintf(&tmp, "0x%lx", args[sc->offset]);
594     break;
595   case Readlinkres:
596     {
597       char *tmp2;
598       if (retval == -1) {
599         tmp = strdup("");
600         break;
601       }
602       tmp2 = get_string(pid, (void*)args[sc->offset], retval);
603       asprintf(&tmp, "\"%s\"", tmp2);
604       free(tmp2);
605     }
606   break;
607   case Ioctl:
608     {
609       const char *temp = ioctlname(args[sc->offset]);
610       if (temp)
611         tmp = strdup(temp);
612       else
613       {
614         unsigned long arg = args[sc->offset];
615         asprintf(&tmp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu}", arg,
616           arg&IOC_OUT?"R":"", arg&IOC_IN?"W":"",
617           IOCGROUP(arg), isprint(IOCGROUP(arg))?(char)IOCGROUP(arg):'?',
618           arg & 0xFF, IOCPARM_LEN(arg));
619       }
620     }
621     break;
622   case Umtx:
623     {
624       struct umtx umtx;
625       if (get_struct(pid, (void *)args[sc->offset], &umtx, sizeof(umtx)) != -1)
626         asprintf(&tmp, "{0x%lx}", (long)umtx.u_owner);
627       else
628         asprintf(&tmp, "0x%lx", args[sc->offset]);
629     }
630     break;
631   case Timespec:
632     {
633       struct timespec ts;
634       if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts)) != -1)
635         asprintf(&tmp, "{%ld.%09ld}", (long)ts.tv_sec, ts.tv_nsec);
636       else
637         asprintf(&tmp, "0x%lx", args[sc->offset]);
638     }
639     break;
640   case Timeval:
641     {
642       struct timeval tv;
643       if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) != -1)
644         asprintf(&tmp, "{%ld.%06ld}", (long)tv.tv_sec, tv.tv_usec);
645       else
646         asprintf(&tmp, "0x%lx", args[sc->offset]);
647     }
648     break;
649   case Timeval2:
650     {
651       struct timeval tv[2];
652       if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) != -1)
653         asprintf(&tmp, "{%ld.%06ld, %ld.%06ld}",
654           (long)tv[0].tv_sec, tv[0].tv_usec,
655           (long)tv[1].tv_sec, tv[1].tv_usec);
656       else
657         asprintf(&tmp, "0x%lx", args[sc->offset]);
658     }
659     break;
660   case Itimerval:
661     {
662       struct itimerval itv;
663       if (get_struct(pid, (void *)args[sc->offset], &itv, sizeof(itv)) != -1)
664         asprintf(&tmp, "{%ld.%06ld, %ld.%06ld}",
665             (long)itv.it_interval.tv_sec,
666             itv.it_interval.tv_usec,
667             (long)itv.it_value.tv_sec,
668             itv.it_value.tv_usec);
669       else
670         asprintf(&tmp, "0x%lx", args[sc->offset]);
671     }
672     break;
673   case Pollfd:
674     {
675       /*
676        * XXX: A Pollfd argument expects the /next/ syscall argument to be
677        * the number of fds in the array. This matches the poll syscall.
678        */
679       struct pollfd *pfd;
680       int numfds = args[sc->offset+1];
681       int bytes = sizeof(struct pollfd) * numfds;
682       int i, tmpsize, u, used;
683       const int per_fd = 100;
684
685       if ((pfd = malloc(bytes)) == NULL)
686         err(1, "Cannot malloc %d bytes for pollfd array", bytes);
687       if (get_struct(pid, (void *)args[sc->offset], pfd, bytes) != -1) {
688
689         used = 0;
690         tmpsize = 1 + per_fd * numfds + 2;
691         if ((tmp = malloc(tmpsize)) == NULL)
692           err(1, "Cannot alloc %d bytes for poll output", tmpsize);
693
694         tmp[used++] = '{';
695         for (i = 0; i < numfds; i++) {
696
697           u = snprintf(tmp + used, per_fd,
698             "%s%d/%s",
699             i > 0 ? " " : "",
700             pfd[i].fd,
701             xlookup_bits(poll_flags, pfd[i].events) );
702           if (u > 0)
703             used += u < per_fd ? u : per_fd;
704         }
705         tmp[used++] = '}';
706         tmp[used++] = '\0';
707       } else
708         asprintf(&tmp, "0x%lx", args[sc->offset]);
709       free(pfd);
710     }
711     break;
712   case Fd_set:
713     {
714       /* 
715        * XXX: A Fd_set argument expects the /first/ syscall argument to be
716        * the number of fds in the array.  This matches the select syscall.
717        */
718       fd_set *fds;
719       int numfds = args[0];
720       int bytes = _howmany(numfds, _NFDBITS) * _NFDBITS;
721       int i, tmpsize, u, used;
722       const int per_fd = 20;
723
724       if ((fds = malloc(bytes)) == NULL)
725         err(1, "Cannot malloc %d bytes for fd_set array", bytes);
726       if (get_struct(pid, (void *)args[sc->offset], fds, bytes) != -1) {
727         used = 0;
728         tmpsize = 1 + numfds * per_fd + 2;
729         if ((tmp = malloc(tmpsize)) == NULL)
730           err(1, "Cannot alloc %d bytes for fd_set output", tmpsize);
731
732         tmp[used++] = '{';
733         for (i = 0; i < numfds; i++) {
734           if (FD_ISSET(i, fds)) {
735             u = snprintf(tmp + used, per_fd, "%d ", i);
736             if (u > 0)
737               used += u < per_fd ? u : per_fd;
738           }
739         }
740         if (tmp[used-1] == ' ')
741                 used--;
742         tmp[used++] = '}';
743         tmp[used++] = '\0';
744       } else
745         asprintf(&tmp, "0x%lx", args[sc->offset]);
746       free(fds);
747     }
748     break;
749   case Signal:
750     {
751       long sig;
752
753       sig = args[sc->offset];
754       tmp = strsig(sig);
755       if (tmp == NULL)
756         asprintf(&tmp, "%ld", sig);
757     }
758     break;
759   case Sigset:
760     {
761       long sig;
762       sigset_t ss;
763       int i, used;
764
765       sig = args[sc->offset];
766       if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
767           sizeof(ss)) == -1)
768       {
769         asprintf(&tmp, "0x%lx", args[sc->offset]);
770         break;
771       }
772       tmp = malloc(sys_nsig * 8); /* 7 bytes avg per signal name */
773       used = 0;
774       for (i = 1; i < sys_nsig; i++)
775       {
776         if (sigismember(&ss, i))
777         {
778           used += sprintf(tmp + used, "%s|", strsig(i));
779         }
780       }
781       if(used)
782               tmp[used-1] = 0;
783           else
784               strcpy(tmp, "0x0");
785     }
786     break;
787   case Sigprocmask:
788     {
789         switch (args[sc->offset]) {
790 #define S(a)    case a: tmp = strdup(#a); break;
791         S(SIG_BLOCK);
792         S(SIG_UNBLOCK);
793         S(SIG_SETMASK);
794 #undef S
795         }
796         if (tmp == NULL)
797                 asprintf(&tmp, "0x%lx", args[sc->offset]);
798     }
799     break;
800     
801   case Fcntlflag:
802     {
803       /* XXX output depends on the value of the previous argument */
804       switch (args[sc->offset-1]) {
805         case F_SETFD:
806           tmp = strdup(xlookup_bits(fcntlfd_arg, args[sc->offset]));
807           break;
808         case F_SETFL:
809           tmp = strdup(xlookup_bits(fcntlfl_arg, args[sc->offset]));
810           break;
811         case F_GETFD:
812         case F_GETFL:
813         case F_GETOWN:
814           tmp = strdup("");
815           break;
816         default:
817           asprintf(&tmp, "0x%lx", args[sc->offset]);
818           break;
819       }
820     }
821     break;
822   case Open:
823     tmp = strdup(xlookup_bits(open_flags, args[sc->offset]));
824     break;
825   case Fcntl:
826     tmp = strdup(xlookup(fcntl_arg, args[sc->offset]));
827     break;
828   case Mprot:
829     tmp = strdup(xlookup_bits(mprot_flags, args[sc->offset]));
830     break;
831   case Mmapflags:
832     tmp = strdup(xlookup_bits(mmap_flags, args[sc->offset]));
833     break;
834   case Whence:
835     tmp = strdup(xlookup(whence_arg, args[sc->offset]));
836     break;
837   case Sockdomain:
838     tmp = strdup(xlookup(sockdomain_arg, args[sc->offset]));
839     break;
840   case Socktype:
841     tmp = strdup(xlookup(socktype_arg, args[sc->offset]));
842     break;
843   case Shutdown:
844     tmp = strdup(xlookup(shutdown_arg, args[sc->offset]));
845     break;
846   case Resource:
847     tmp = strdup(xlookup(resource_arg, args[sc->offset]));
848     break;
849   case Pathconf:
850     tmp = strdup(xlookup(pathconf_arg, args[sc->offset]));
851     break;
852   case Sockaddr:
853     {
854       struct sockaddr_storage ss;
855       char addr[64];
856       struct sockaddr_in *lsin;
857       struct sockaddr_in6 *lsin6;
858       struct sockaddr_un *sun;
859       struct sockaddr *sa;
860       char *p;
861       u_char *q;
862       int i;
863
864       if (args[sc->offset] == 0) {
865               asprintf(&tmp, "NULL");
866               break;
867       }
868
869       /* yuck: get ss_len */
870       if (get_struct(pid, (void *)args[sc->offset], (void *)&ss,
871         sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1)
872         err(1, "get_struct %p", (void *)args[sc->offset]);
873       /*
874        * If ss_len is 0, then try to guess from the sockaddr type.
875        * AF_UNIX may be initialized incorrectly, so always frob
876        * it by using the "right" size.
877        */
878       if (ss.ss_len == 0 || ss.ss_family == AF_UNIX) {
879               switch (ss.ss_family) {
880               case AF_INET:
881                       ss.ss_len = sizeof(*lsin);
882                       break;
883               case AF_UNIX:
884                       ss.ss_len = sizeof(*sun);
885                       break;
886               default:
887                       /* hurrrr */
888                       break;
889               }
890       }
891       if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, ss.ss_len)
892           == -1) {
893           err(2, "get_struct %p", (void *)args[sc->offset]);
894       }
895
896       switch (ss.ss_family) {
897       case AF_INET:
898         lsin = (struct sockaddr_in *)&ss;
899         inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof addr);
900         asprintf(&tmp, "{ AF_INET %s:%d }", addr, htons(lsin->sin_port));
901         break;
902       case AF_INET6:
903         lsin6 = (struct sockaddr_in6 *)&ss;
904         inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, sizeof addr);
905         asprintf(&tmp, "{ AF_INET6 [%s]:%d }", addr, htons(lsin6->sin6_port));
906         break;
907       case AF_UNIX:
908         sun = (struct sockaddr_un *)&ss;
909         asprintf(&tmp, "{ AF_UNIX \"%s\" }", sun->sun_path);
910         break;
911       default:
912         sa = (struct sockaddr *)&ss;
913         asprintf(&tmp, "{ sa_len = %d, sa_family = %d, sa_data = {%n%*s } }",
914           (int)sa->sa_len, (int)sa->sa_family, &i,
915           6 * (int)(sa->sa_len - ((char *)&sa->sa_data - (char *)sa)), "");
916         if (tmp != NULL) {
917           p = tmp + i;
918           for (q = (u_char *)&sa->sa_data; q < (u_char *)sa + sa->sa_len; q++)
919             p += sprintf(p, " %#02x,", *q);
920         }
921       }
922     }
923     break;
924   case Sigaction:
925     {
926       struct sigaction sa;
927       char *hand;
928       const char *h;
929
930       if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa)) != -1) {
931
932         asprintf(&hand, "%p", sa.sa_handler);
933         if (sa.sa_handler == SIG_DFL)
934           h = "SIG_DFL";
935         else if (sa.sa_handler == SIG_IGN)
936           h = "SIG_IGN";
937         else
938           h = hand;
939
940         asprintf(&tmp, "{ %s %s ss_t }",
941             h,
942             xlookup_bits(sigaction_flags, sa.sa_flags));
943         free(hand);
944       } else
945         asprintf(&tmp, "0x%lx", args[sc->offset]);
946       
947     }
948     break;
949   case Kevent:
950     {
951       /*
952        * XXX XXX: the size of the array is determined by either the
953        * next syscall argument, or by the syscall returnvalue,
954        * depending on which argument number we are.  This matches the
955        * kevent syscall, but luckily that's the only syscall that uses
956        * them.
957        */
958       struct kevent *ke;
959       int numevents = -1;
960       int bytes = 0;
961       int i, tmpsize, u, used;
962       const int per_ke = 100;
963
964       if (sc->offset == 1)
965         numevents = args[sc->offset+1];
966       else if (sc->offset == 3 && retval != -1)
967         numevents = retval;
968
969       if (numevents >= 0)
970         bytes = sizeof(struct kevent) * numevents;
971       if ((ke = malloc(bytes)) == NULL)
972         err(1, "Cannot malloc %d bytes for kevent array", bytes);
973       if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset], ke, bytes) != -1) {
974         used = 0;
975         tmpsize = 1 + per_ke * numevents + 2;
976         if ((tmp = malloc(tmpsize)) == NULL)
977           err(1, "Cannot alloc %d bytes for kevent output", tmpsize);
978
979         tmp[used++] = '{';
980         for (i = 0; i < numevents; i++) {
981           u = snprintf(tmp + used, per_ke,
982             "%s%p,%s,%s,%d,%p,%p",
983             i > 0 ? " " : "",
984             (void *)ke[i].ident,
985             xlookup(kevent_filters, ke[i].filter),
986             xlookup_bits(kevent_flags, ke[i].flags),
987             ke[i].fflags,
988             (void *)ke[i].data,
989             (void *)ke[i].udata);
990           if (u > 0)
991             used += u < per_ke ? u : per_ke;
992         }
993         tmp[used++] = '}';
994         tmp[used++] = '\0';
995       } else
996         asprintf(&tmp, "0x%lx", args[sc->offset]);
997       free(ke);
998     }
999     break;
1000   case Stat:
1001     {
1002       struct stat st;
1003       if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st)) != -1) {
1004         char mode[12];
1005         strmode(st.st_mode, mode);
1006         asprintf(&tmp, "{mode=%s,inode=%jd,size=%jd,blksize=%ld}",
1007           mode,
1008           (intmax_t)st.st_ino,(intmax_t)st.st_size,(long)st.st_blksize);
1009       } else
1010         asprintf(&tmp, "0x%lx", args[sc->offset]);
1011     }
1012     break;
1013   case Rusage:
1014     {
1015       struct rusage ru;
1016       if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru)) != -1)
1017         asprintf(&tmp, "{u=%ld.%06ld,s=%ld.%06ld,in=%ld,out=%ld}",
1018           (long)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec,
1019           (long)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec,
1020           ru.ru_inblock, ru.ru_oublock);
1021       else
1022         asprintf(&tmp, "0x%lx", args[sc->offset]);
1023     }
1024     break;
1025   case Rlimit:
1026     {
1027       struct rlimit rl;
1028       if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl)) != -1)
1029         asprintf(&tmp, "{cur=%ju,max=%ju}",
1030           rl.rlim_cur, rl.rlim_max);
1031       else
1032         asprintf(&tmp, "0x%lx", args[sc->offset]);
1033     }
1034     break;
1035     default:
1036      errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
1037   }
1038   return tmp;
1039 }
1040
1041
1042 /*
1043  * print_syscall
1044  * Print (to outfile) the system call and its arguments.  Note that
1045  * nargs is the number of arguments (not the number of words; this is
1046  * potentially confusing, I know).
1047  */
1048
1049 void
1050 print_syscall(struct trussinfo *trussinfo, const char *name, int nargs, char **s_args) {
1051   int i;
1052   int len = 0;
1053   struct timespec timediff;
1054
1055   if (trussinfo->flags & FOLLOWFORKS)
1056     len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid);
1057
1058   if (name != NULL && (!strcmp(name, "execve") || !strcmp(name, "exit"))) {
1059     clock_gettime(CLOCK_REALTIME, &trussinfo->after);
1060   }
1061
1062   if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
1063     timespecsubt(&trussinfo->after, &trussinfo->start_time, &timediff);
1064     len += fprintf(trussinfo->outfile, "%ld.%09ld ",
1065                    (long)timediff.tv_sec, timediff.tv_nsec);
1066   }
1067
1068   if (trussinfo->flags & RELATIVETIMESTAMPS) {
1069     timespecsubt(&trussinfo->after, &trussinfo->before, &timediff);
1070     len += fprintf(trussinfo->outfile, "%ld.%09ld ",
1071                    (long)timediff.tv_sec, timediff.tv_nsec);
1072   }
1073
1074   len += fprintf(trussinfo->outfile, "%s(", name);
1075
1076   for (i = 0; i < nargs; i++) {
1077     if (s_args[i])
1078       len += fprintf(trussinfo->outfile, "%s", s_args[i]);
1079     else
1080       len += fprintf(trussinfo->outfile, "<missing argument>");
1081     len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? "," : "");
1082   }
1083   len += fprintf(trussinfo->outfile, ")");
1084   for (i = 0; i < 6 - (len / 8); i++)
1085         fprintf(trussinfo->outfile, "\t");
1086 }
1087
1088 void
1089 print_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs,
1090     char **s_args, int errorp, long retval)
1091 {
1092   print_syscall(trussinfo, name, nargs, s_args);
1093   fflush(trussinfo->outfile);
1094   if (errorp) {
1095     fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval, strerror(retval));
1096   } else {
1097     fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval, retval);
1098   }
1099 }