syscalls.c revision 240562
131567Ssef/* 2204977Simp * Copyright 1997 Sean Eric Fagan 331899Ssef * 431899Ssef * Redistribution and use in source and binary forms, with or without 531899Ssef * modification, are permitted provided that the following conditions 631899Ssef * are met: 731899Ssef * 1. Redistributions of source code must retain the above copyright 831899Ssef * notice, this list of conditions and the following disclaimer. 931899Ssef * 2. Redistributions in binary form must reproduce the above copyright 1031899Ssef * notice, this list of conditions and the following disclaimer in the 1131899Ssef * documentation and/or other materials provided with the distribution. 1231899Ssef * 3. All advertising materials mentioning features or use of this software 1331899Ssef * must display the following acknowledgement: 1431899Ssef * This product includes software developed by Sean Eric Fagan 1531899Ssef * 4. Neither the name of the author may be used to endorse or promote 1631899Ssef * products derived from this software without specific prior written 1731899Ssef * permission. 1831899Ssef * 1931899Ssef * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2031899Ssef * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2131899Ssef * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2231899Ssef * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2331899Ssef * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2431899Ssef * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2531899Ssef * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2631899Ssef * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2731899Ssef * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2831899Ssef * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2931899Ssef * SUCH DAMAGE. 3031899Ssef */ 3131899Ssef 3232275Scharnier#ifndef lint 3332275Scharnierstatic const char rcsid[] = 3450477Speter "$FreeBSD: head/usr.bin/truss/syscalls.c 240562 2012-09-16 14:38:01Z zont $"; 3532275Scharnier#endif /* not lint */ 3632275Scharnier 3731899Ssef/* 3831567Ssef * This file has routines used to print out system calls and their 3931567Ssef * arguments. 4031567Ssef */ 4131567Ssef 42127328Salfred#include <sys/mman.h> 4385292Sdes#include <sys/types.h> 44168569Sdelphij#include <sys/ptrace.h> 4585292Sdes#include <sys/socket.h> 46104581Smike#include <sys/time.h> 4785292Sdes#include <sys/un.h> 4885292Sdes#include <netinet/in.h> 4985292Sdes#include <arpa/inet.h> 50158630Spav#include <sys/ioccom.h> 51158630Spav#include <machine/atomic.h> 52158630Spav#include <errno.h> 53158630Spav#include <sys/umtx.h> 54158630Spav#include <sys/event.h> 55158630Spav#include <sys/stat.h> 56158630Spav#include <sys/resource.h> 5785292Sdes 5886138Sgreen#include <ctype.h> 5932275Scharnier#include <err.h> 60127328Salfred#include <fcntl.h> 61127332Sdwmalone#include <poll.h> 6285292Sdes#include <signal.h> 63127332Sdwmalone#include <stdint.h> 6431567Ssef#include <stdio.h> 6531567Ssef#include <stdlib.h> 6631567Ssef#include <string.h> 67101423Smdodd#include <time.h> 6831567Ssef#include <unistd.h> 69158630Spav#include <vis.h> 7085292Sdes 71101282Smdodd#include "truss.h" 7287703Smarkm#include "extern.h" 7331567Ssef#include "syscall.h" 7431567Ssef 75171646Smarcel/* 64-bit alignment on 32-bit platforms. */ 76171646Smarcel#ifdef __powerpc__ 77171646Smarcel#define QUAD_ALIGN 1 78171646Smarcel#else 79171646Smarcel#define QUAD_ALIGN 0 80171646Smarcel#endif 81171646Smarcel 82171646Smarcel/* Number of slots needed for a 64-bit argument. */ 83171646Smarcel#ifdef __LP64__ 84171646Smarcel#define QUAD_SLOTS 1 85171646Smarcel#else 86171646Smarcel#define QUAD_SLOTS 2 87171646Smarcel#endif 88171646Smarcel 8931567Ssef/* 90158630Spav * This should probably be in its own file, sorted alphabetically. 9131567Ssef */ 92228396Sedstatic struct syscall syscalls[] = { 93192025Sdds { .name = "fcntl", .ret_type = 1, .nargs = 3, 94192025Sdds .args = { { Int, 0 } , { Fcntl, 1 }, { Fcntlflag | OUT, 2 } } }, 95200751Sjh { .name = "fork", .ret_type = 1, .nargs = 0 }, 96200751Sjh { .name = "getegid", .ret_type = 1, .nargs = 0 }, 97200751Sjh { .name = "geteuid", .ret_type = 1, .nargs = 0 }, 98200751Sjh { .name = "getgid", .ret_type = 1, .nargs = 0 }, 99200751Sjh { .name = "getpid", .ret_type = 1, .nargs = 0 }, 100200751Sjh { .name = "getpgid", .ret_type = 1, .nargs = 1, 101200751Sjh .args = { { Int, 0 } } }, 102200751Sjh { .name = "getpgrp", .ret_type = 1, .nargs = 0 }, 103200751Sjh { .name = "getppid", .ret_type = 1, .nargs = 0 }, 104200751Sjh { .name = "getsid", .ret_type = 1, .nargs = 1, 105200751Sjh .args = { { Int, 0 } } }, 106200751Sjh { .name = "getuid", .ret_type = 1, .nargs = 0 }, 107192025Sdds { .name = "readlink", .ret_type = 1, .nargs = 3, 108192025Sdds .args = { { Name, 0 } , { Readlinkres | OUT, 1 }, { Int, 2 } } }, 109192025Sdds { .name = "lseek", .ret_type = 2, .nargs = 3, 110192025Sdds .args = { { Int, 0 }, { Quad, 1 + QUAD_ALIGN }, { Whence, 1 + QUAD_SLOTS + QUAD_ALIGN } } }, 111192025Sdds { .name = "linux_lseek", .ret_type = 2, .nargs = 3, 112192025Sdds .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } }, 113192025Sdds { .name = "mmap", .ret_type = 2, .nargs = 6, 114192025Sdds .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 }, { Mmapflags, 3 }, { Int, 4 }, { Quad, 5 + QUAD_ALIGN } } }, 115192025Sdds { .name = "mprotect", .ret_type = 1, .nargs = 3, 116192025Sdds .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 } } }, 117192025Sdds { .name = "open", .ret_type = 1, .nargs = 3, 118192025Sdds .args = { { Name | IN, 0 } , { Open, 1 }, { Octal, 2 } } }, 119192025Sdds { .name = "mkdir", .ret_type = 1, .nargs = 2, 120192025Sdds .args = { { Name, 0 } , { Octal, 1 } } }, 121192025Sdds { .name = "linux_open", .ret_type = 1, .nargs = 3, 122192025Sdds .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } }, 123192025Sdds { .name = "close", .ret_type = 1, .nargs = 1, 124192025Sdds .args = { { Int, 0 } } }, 125192025Sdds { .name = "link", .ret_type = 0, .nargs = 2, 126192025Sdds .args = { { Name, 0 }, { Name, 1 } } }, 127192025Sdds { .name = "unlink", .ret_type = 0, .nargs = 1, 128192025Sdds .args = { { Name, 0 } } }, 129192025Sdds { .name = "chdir", .ret_type = 0, .nargs = 1, 130192025Sdds .args = { { Name, 0 } } }, 131192025Sdds { .name = "chroot", .ret_type = 0, .nargs = 1, 132192025Sdds .args = { { Name, 0 } } }, 133192025Sdds { .name = "mknod", .ret_type = 0, .nargs = 3, 134192025Sdds .args = { { Name, 0 }, { Octal, 1 }, { Int, 3 } } }, 135192025Sdds { .name = "chmod", .ret_type = 0, .nargs = 2, 136192025Sdds .args = { { Name, 0 }, { Octal, 1 } } }, 137192025Sdds { .name = "chown", .ret_type = 0, .nargs = 3, 138192025Sdds .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } }, 139192025Sdds { .name = "mount", .ret_type = 0, .nargs = 4, 140192025Sdds .args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } }, 141192025Sdds { .name = "umount", .ret_type = 0, .nargs = 2, 142192025Sdds .args = { { Name, 0 }, { Int, 2 } } }, 143192025Sdds { .name = "fstat", .ret_type = 1, .nargs = 2, 144192025Sdds .args = { { Int, 0 }, { Stat | OUT , 1 } } }, 145192025Sdds { .name = "stat", .ret_type = 1, .nargs = 2, 146192025Sdds .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } }, 147192025Sdds { .name = "lstat", .ret_type = 1, .nargs = 2, 148192025Sdds .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } }, 149192025Sdds { .name = "linux_newstat", .ret_type = 1, .nargs = 2, 150192025Sdds .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } }, 151192025Sdds { .name = "linux_newfstat", .ret_type = 1, .nargs = 2, 152192025Sdds .args = { { Int, 0 }, { Ptr | OUT, 1 } } }, 153192025Sdds { .name = "write", .ret_type = 1, .nargs = 3, 154192025Sdds .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 } } }, 155192025Sdds { .name = "ioctl", .ret_type = 1, .nargs = 3, 156192025Sdds .args = { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 } } }, 157192025Sdds { .name = "break", .ret_type = 1, .nargs = 1, 158192025Sdds .args = { { Ptr, 0 } } }, 159192025Sdds { .name = "exit", .ret_type = 0, .nargs = 1, 160192025Sdds .args = { { Hex, 0 } } }, 161192025Sdds { .name = "access", .ret_type = 1, .nargs = 2, 162192025Sdds .args = { { Name | IN, 0 }, { Int, 1 } } }, 163192025Sdds { .name = "sigaction", .ret_type = 1, .nargs = 3, 164192025Sdds .args = { { Signal, 0 }, { Sigaction | IN, 1 }, { Sigaction | OUT, 2 } } }, 165192025Sdds { .name = "accept", .ret_type = 1, .nargs = 3, 166192025Sdds .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 167192025Sdds { .name = "bind", .ret_type = 1, .nargs = 3, 168192025Sdds .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, 169192025Sdds { .name = "connect", .ret_type = 1, .nargs = 3, 170192025Sdds .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, 171192025Sdds { .name = "getpeername", .ret_type = 1, .nargs = 3, 172192025Sdds .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 173192025Sdds { .name = "getsockname", .ret_type = 1, .nargs = 3, 174192025Sdds .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 175192025Sdds { .name = "recvfrom", .ret_type = 1, .nargs = 6, 176192025Sdds .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } }, 177192025Sdds { .name = "sendto", .ret_type = 1, .nargs = 6, 178192025Sdds .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } }, 179192025Sdds { .name = "execve", .ret_type = 1, .nargs = 3, 180192025Sdds .args = { { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } }, 181192025Sdds { .name = "linux_execve", .ret_type = 1, .nargs = 3, 182192025Sdds .args = { { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } }, 183192025Sdds { .name = "kldload", .ret_type = 0, .nargs = 1, 184192025Sdds .args = { { Name | IN, 0 } } }, 185192025Sdds { .name = "kldunload", .ret_type = 0, .nargs = 1, 186192025Sdds .args = { { Int, 0 } } }, 187192025Sdds { .name = "kldfind", .ret_type = 0, .nargs = 1, 188192025Sdds .args = { { Name | IN, 0 } } }, 189192025Sdds { .name = "kldnext", .ret_type = 0, .nargs = 1, 190192025Sdds .args = { { Int, 0 } } }, 191192025Sdds { .name = "kldstat", .ret_type = 0, .nargs = 2, 192192025Sdds .args = { { Int, 0 }, { Ptr, 1 } } }, 193192025Sdds { .name = "kldfirstmod", .ret_type = 0, .nargs = 1, 194192025Sdds .args = { { Int, 0 } } }, 195192025Sdds { .name = "nanosleep", .ret_type = 0, .nargs = 1, 196192025Sdds .args = { { Timespec, 0 } } }, 197192025Sdds { .name = "select", .ret_type = 1, .nargs = 5, 198192025Sdds .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, { Timeval, 4 } } }, 199192025Sdds { .name = "poll", .ret_type = 1, .nargs = 3, 200192025Sdds .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } }, 201192025Sdds { .name = "gettimeofday", .ret_type = 1, .nargs = 2, 202192025Sdds .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } }, 203192025Sdds { .name = "clock_gettime", .ret_type = 1, .nargs = 2, 204192025Sdds .args = { { Int, 0 }, { Timespec | OUT, 1 } } }, 205192025Sdds { .name = "getitimer", .ret_type = 1, .nargs = 2, 206192025Sdds .args = { { Int, 0 }, { Itimerval | OUT, 2 } } }, 207192025Sdds { .name = "setitimer", .ret_type = 1, .nargs = 3, 208192025Sdds .args = { { Int, 0 }, { Itimerval, 1 } , { Itimerval | OUT, 2 } } }, 209192025Sdds { .name = "kse_release", .ret_type = 0, .nargs = 1, 210192025Sdds .args = { { Timespec, 0 } } }, 211192025Sdds { .name = "kevent", .ret_type = 0, .nargs = 6, 212192025Sdds .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 }, { Int, 4 }, { Timespec, 5 } } }, 213192025Sdds { .name = "_umtx_lock", .ret_type = 0, .nargs = 1, 214192025Sdds .args = { { Umtx, 0 } } }, 215192025Sdds { .name = "_umtx_unlock", .ret_type = 0, .nargs = 1, 216192025Sdds .args = { { Umtx, 0 } } }, 217192025Sdds { .name = "sigprocmask", .ret_type = 0, .nargs = 3, 218192025Sdds .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } }, 219192025Sdds { .name = "unmount", .ret_type = 1, .nargs = 2, 220192025Sdds .args = { { Name, 0 }, { Int, 1 } } }, 221192025Sdds { .name = "socket", .ret_type = 1, .nargs = 3, 222192025Sdds .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Int, 2 } } }, 223192025Sdds { .name = "getrusage", .ret_type = 1, .nargs = 2, 224192025Sdds .args = { { Int, 0 }, { Rusage | OUT, 1 } } }, 225192025Sdds { .name = "__getcwd", .ret_type = 1, .nargs = 2, 226192025Sdds .args = { { Name | OUT, 0 }, { Int, 1 } } }, 227192025Sdds { .name = "shutdown", .ret_type = 1, .nargs = 2, 228192025Sdds .args = { { Int, 0 }, { Shutdown, 1 } } }, 229192025Sdds { .name = "getrlimit", .ret_type = 1, .nargs = 2, 230192025Sdds .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } }, 231192025Sdds { .name = "setrlimit", .ret_type = 1, .nargs = 2, 232192025Sdds .args = { { Resource, 0 }, { Rlimit | IN, 1 } } }, 233192025Sdds { .name = "utimes", .ret_type = 1, .nargs = 2, 234192025Sdds .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } }, 235192025Sdds { .name = "lutimes", .ret_type = 1, .nargs = 2, 236192025Sdds .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } }, 237192025Sdds { .name = "futimes", .ret_type = 1, .nargs = 2, 238192025Sdds .args = { { Int, 0 }, { Timeval | IN, 1 } } }, 239192025Sdds { .name = "chflags", .ret_type = 1, .nargs = 2, 240192025Sdds .args = { { Name | IN, 0 }, { Hex, 1 } } }, 241192025Sdds { .name = "lchflags", .ret_type = 1, .nargs = 2, 242192025Sdds .args = { { Name | IN, 0 }, { Hex, 1 } } }, 243192025Sdds { .name = "pathconf", .ret_type = 1, .nargs = 2, 244192025Sdds .args = { { Name | IN, 0 }, { Pathconf, 1 } } }, 245200780Sjh { .name = "pipe", .ret_type = 1, .nargs = 1, 246200780Sjh .args = { { Ptr, 0 } } }, 247192025Sdds { .name = "truncate", .ret_type = 1, .nargs = 3, 248192025Sdds .args = { { Name | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 } } }, 249192025Sdds { .name = "ftruncate", .ret_type = 1, .nargs = 3, 250192025Sdds .args = { { Int | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 } } }, 251192025Sdds { .name = "kill", .ret_type = 1, .nargs = 2, 252192025Sdds .args = { { Int | IN, 0 }, { Signal | IN, 1 } } }, 253192025Sdds { .name = "munmap", .ret_type = 1, .nargs = 2, 254192025Sdds .args = { { Ptr, 0 }, { Int, 1 } } }, 255192025Sdds { .name = "read", .ret_type = 1, .nargs = 3, 256192025Sdds .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 } } }, 257192025Sdds { .name = "rename", .ret_type = 1, .nargs = 2, 258192025Sdds .args = { { Name , 0 } , { Name, 1 } } }, 259192025Sdds { .name = "symlink", .ret_type = 1, .nargs = 2, 260192025Sdds .args = { { Name , 0 } , { Name, 1 } } }, 261200902Sed { .name = "posix_openpt", .ret_type = 1, .nargs = 1, 262200902Sed .args = { { Open, 0 } } }, 263192025Sdds { .name = 0 }, 26431567Ssef}; 26531567Ssef 266158630Spav/* Xlat idea taken from strace */ 267158630Spavstruct xlat { 268158630Spav int val; 269168569Sdelphij const char *str; 270158630Spav}; 271158630Spav 272240005Szont#define X(a) { a, #a }, 273240005Szont#define XEND { 0, NULL } 274158630Spav 275158630Spavstatic struct xlat kevent_filters[] = { 276158630Spav X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE) 277158630Spav X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER) 278201350Sbrooks X(EVFILT_FS) X(EVFILT_READ) XEND 279158630Spav}; 280158630Spav 281158630Spavstatic struct xlat kevent_flags[] = { 282158630Spav X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT) 283158630Spav X(EV_CLEAR) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND 284158630Spav}; 285158630Spav 286228396Sedstatic struct xlat poll_flags[] = { 287158630Spav X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR) 288158630Spav X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND) 289158630Spav X(POLLWRBAND) X(POLLINIGNEOF) XEND 290158630Spav}; 291158630Spav 292158630Spavstatic struct xlat mmap_flags[] = { 293158630Spav X(MAP_SHARED) X(MAP_PRIVATE) X(MAP_FIXED) X(MAP_RENAME) 294158630Spav X(MAP_NORESERVE) X(MAP_RESERVED0080) X(MAP_RESERVED0100) 295158630Spav X(MAP_HASSEMAPHORE) X(MAP_STACK) X(MAP_NOSYNC) X(MAP_ANON) 296158630Spav X(MAP_NOCORE) XEND 297158630Spav}; 298158630Spav 299158630Spavstatic struct xlat mprot_flags[] = { 300158630Spav X(PROT_NONE) X(PROT_READ) X(PROT_WRITE) X(PROT_EXEC) XEND 301158630Spav}; 302158630Spav 303158630Spavstatic struct xlat whence_arg[] = { 304158630Spav X(SEEK_SET) X(SEEK_CUR) X(SEEK_END) XEND 305158630Spav}; 306158630Spav 307158630Spavstatic struct xlat sigaction_flags[] = { 308158630Spav X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP) 309158630Spav X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND 310158630Spav}; 311158630Spav 312158630Spavstatic struct xlat fcntl_arg[] = { 313158630Spav X(F_DUPFD) X(F_GETFD) X(F_SETFD) X(F_GETFL) X(F_SETFL) 314158630Spav X(F_GETOWN) X(F_SETOWN) X(F_GETLK) X(F_SETLK) X(F_SETLKW) XEND 315158630Spav}; 316158630Spav 317158630Spavstatic struct xlat fcntlfd_arg[] = { 318158630Spav X(FD_CLOEXEC) XEND 319158630Spav}; 320158630Spav 321158630Spavstatic struct xlat fcntlfl_arg[] = { 322158630Spav X(O_APPEND) X(O_ASYNC) X(O_FSYNC) X(O_NONBLOCK) X(O_NOFOLLOW) 323158630Spav X(O_DIRECT) XEND 324158630Spav}; 325158630Spav 326158630Spavstatic struct xlat sockdomain_arg[] = { 327158630Spav X(PF_UNSPEC) X(PF_LOCAL) X(PF_UNIX) X(PF_INET) X(PF_IMPLINK) 328158630Spav X(PF_PUP) X(PF_CHAOS) X(PF_NETBIOS) X(PF_ISO) X(PF_OSI) 329158630Spav X(PF_ECMA) X(PF_DATAKIT) X(PF_CCITT) X(PF_SNA) X(PF_DECnet) 330158630Spav X(PF_DLI) X(PF_LAT) X(PF_HYLINK) X(PF_APPLETALK) X(PF_ROUTE) 331158630Spav X(PF_LINK) X(PF_XTP) X(PF_COIP) X(PF_CNT) X(PF_SIP) X(PF_IPX) 332158630Spav X(PF_RTIP) X(PF_PIP) X(PF_ISDN) X(PF_KEY) X(PF_INET6) 333158630Spav X(PF_NATM) X(PF_ATM) X(PF_NETGRAPH) X(PF_SLOW) X(PF_SCLUSTER) 334158630Spav X(PF_ARP) X(PF_BLUETOOTH) XEND 335158630Spav}; 336158630Spav 337158630Spavstatic struct xlat socktype_arg[] = { 338158630Spav X(SOCK_STREAM) X(SOCK_DGRAM) X(SOCK_RAW) X(SOCK_RDM) 339158630Spav X(SOCK_SEQPACKET) XEND 340158630Spav}; 341158630Spav 342158630Spavstatic struct xlat open_flags[] = { 343158630Spav X(O_RDONLY) X(O_WRONLY) X(O_RDWR) X(O_ACCMODE) X(O_NONBLOCK) 344158630Spav X(O_APPEND) X(O_SHLOCK) X(O_EXLOCK) X(O_ASYNC) X(O_FSYNC) 345158630Spav X(O_NOFOLLOW) X(O_CREAT) X(O_TRUNC) X(O_EXCL) X(O_NOCTTY) 346158630Spav X(O_DIRECT) XEND 347158630Spav}; 348158630Spav 349158630Spavstatic struct xlat shutdown_arg[] = { 350158630Spav X(SHUT_RD) X(SHUT_WR) X(SHUT_RDWR) XEND 351158630Spav}; 352158630Spav 353158630Spavstatic struct xlat resource_arg[] = { 354158630Spav X(RLIMIT_CPU) X(RLIMIT_FSIZE) X(RLIMIT_DATA) X(RLIMIT_STACK) 355158630Spav X(RLIMIT_CORE) X(RLIMIT_RSS) X(RLIMIT_MEMLOCK) X(RLIMIT_NPROC) 356158630Spav X(RLIMIT_NOFILE) X(RLIMIT_SBSIZE) X(RLIMIT_VMEM) XEND 357158630Spav}; 358158630Spav 359158630Spavstatic struct xlat pathconf_arg[] = { 360158630Spav X(_PC_LINK_MAX) X(_PC_MAX_CANON) X(_PC_MAX_INPUT) 361158630Spav X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF) 362158630Spav X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE) 363158630Spav X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO) 364158630Spav X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS) 365158630Spav X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE) 366158630Spav X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN) 367158630Spav X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX) 368158630Spav X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT) 369158630Spav XEND 370158630Spav}; 371158630Spav 372158630Spav#undef X 373158630Spav#undef XEND 374158630Spav 375181061Sdes/* 376181061Sdes * Searches an xlat array for a value, and returns it if found. Otherwise 377181061Sdes * return a string representation. 378181061Sdes */ 379181061Sdesstatic const char * 380181061Sdeslookup(struct xlat *xlat, int val, int base) 381158630Spav{ 382158630Spav static char tmp[16]; 383181061Sdes 384158630Spav for (; xlat->str != NULL; xlat++) 385158630Spav if (xlat->val == val) 386181061Sdes return (xlat->str); 387158630Spav switch (base) { 388158630Spav case 8: 389158630Spav sprintf(tmp, "0%o", val); 390158630Spav break; 391158630Spav case 16: 392158630Spav sprintf(tmp, "0x%x", val); 393158630Spav break; 394158630Spav case 10: 395158630Spav sprintf(tmp, "%u", val); 396158630Spav break; 397158630Spav default: 398158630Spav errx(1,"Unknown lookup base"); 399158630Spav break; 400158630Spav } 401181061Sdes return (tmp); 402158630Spav} 403158630Spav 404168569Sdelphijstatic const char * 405168569Sdelphijxlookup(struct xlat *xlat, int val) 406158630Spav{ 407181061Sdes 408181061Sdes return (lookup(xlat, val, 16)); 409158630Spav} 410158630Spav 411158630Spav/* Searches an xlat array containing bitfield values. Remaining bits 412158630Spav set after removing the known ones are printed at the end: 413158630Spav IN|0x400 */ 414181061Sdesstatic char * 415181061Sdesxlookup_bits(struct xlat *xlat, int val) 416158630Spav{ 417240005Szont int len, rem; 418158630Spav static char str[512]; 419158630Spav 420240005Szont len = 0; 421240005Szont rem = val; 422181061Sdes for (; xlat->str != NULL; xlat++) { 423181061Sdes if ((xlat->val & rem) == xlat->val) { 424158630Spav /* don't print the "all-bits-zero" string unless all 425158630Spav bits are really zero */ 426158630Spav if (xlat->val == 0 && val != 0) 427158630Spav continue; 428158630Spav len += sprintf(str + len, "%s|", xlat->str); 429158630Spav rem &= ~(xlat->val); 430158630Spav } 431158630Spav } 432158630Spav /* if we have leftover bits or didn't match anything */ 433158630Spav if (rem || len == 0) 434158630Spav len += sprintf(str + len, "0x%x", rem); 435158630Spav if (len && str[len - 1] == '|') 436158630Spav len--; 437158630Spav str[len] = 0; 438181061Sdes return (str); 439158630Spav} 440158630Spav 44131567Ssef/* 44231567Ssef * If/when the list gets big, it might be desirable to do it 44331567Ssef * as a hash table or binary search. 44431567Ssef */ 44531567Ssef 44631567Ssefstruct syscall * 447181061Sdesget_syscall(const char *name) 448181061Sdes{ 449240005Szont struct syscall *sc; 45031567Ssef 451240005Szont sc = syscalls; 452133349Salfred if (name == NULL) 453133349Salfred return (NULL); 45431567Ssef while (sc->name) { 455240005Szont if (strcmp(name, sc->name) == 0) 456181061Sdes return (sc); 45731567Ssef sc++; 45831567Ssef } 459181061Sdes return (NULL); 46031567Ssef} 46131567Ssef 46231567Ssef/* 46385292Sdes * get_struct 46485292Sdes * 46585292Sdes * Copy a fixed amount of bytes from the process. 46685292Sdes */ 46785292Sdes 46887703Smarkmstatic int 469239501Szontget_struct(pid_t pid, void *offset, void *buf, int len) 470181061Sdes{ 471168569Sdelphij struct ptrace_io_desc iorequest; 472181061Sdes 473168569Sdelphij iorequest.piod_op = PIOD_READ_D; 474168569Sdelphij iorequest.piod_offs = offset; 475168569Sdelphij iorequest.piod_addr = buf; 476168569Sdelphij iorequest.piod_len = len; 477168569Sdelphij if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) 478181061Sdes return (-1); 479181061Sdes return (0); 48085292Sdes} 48185292Sdes 482240005Szont#define MAXSIZE 4096 483240005Szont#define BLOCKSIZE 1024 48485292Sdes/* 48531567Ssef * get_string 48631567Ssef * Copy a string from the process. Note that it is 48731567Ssef * expected to be a C string, but if max is set, it will 48831567Ssef * only get that much. 48931567Ssef */ 49031567Ssef 491168569Sdelphijstatic char * 492181061Sdesget_string(pid_t pid, void *offset, int max) 493181061Sdes{ 494240005Szont struct ptrace_io_desc iorequest; 49532275Scharnier char *buf; 496240005Szont int diff, i, size, totalsize; 497181061Sdes 498240005Szont diff = 0; 499181061Sdes totalsize = size = max ? (max + 1) : BLOCKSIZE; 500168569Sdelphij buf = malloc(totalsize); 501168569Sdelphij if (buf == NULL) 502181061Sdes return (NULL); 503181061Sdes for (;;) { 504168569Sdelphij diff = totalsize - size; 505168569Sdelphij iorequest.piod_op = PIOD_READ_D; 506168569Sdelphij iorequest.piod_offs = (char *)offset + diff; 507168569Sdelphij iorequest.piod_addr = buf + diff; 508168569Sdelphij iorequest.piod_len = size; 509168569Sdelphij if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) { 510168569Sdelphij free(buf); 511181061Sdes return (NULL); 51231567Ssef } 513168569Sdelphij for (i = 0 ; i < size; i++) { 514168569Sdelphij if (buf[diff + i] == '\0') 515168569Sdelphij return (buf); 516168569Sdelphij } 517168569Sdelphij if (totalsize < MAXSIZE - BLOCKSIZE && max == 0) { 518168569Sdelphij totalsize += BLOCKSIZE; 519168569Sdelphij buf = realloc(buf, totalsize); 520168569Sdelphij size = BLOCKSIZE; 521181061Sdes } else { 522216224Sjh buf[totalsize - 1] = '\0'; 523181061Sdes return (buf); 524168569Sdelphij } 52531567Ssef } 52631567Ssef} 52731567Ssef 52831567Ssef 52931567Ssef/* 53031567Ssef * print_arg 53131567Ssef * Converts a syscall argument into a string. Said string is 53231567Ssef * allocated via malloc(), so needs to be free()'d. The file 53331567Ssef * descriptor is for the process' memory (via /proc), and is used 53431567Ssef * to get any data (where the argument is a pointer). sc is 53531567Ssef * a pointer to the syscall description (see above); args is 53631567Ssef * an array of all of the system call arguments. 53731567Ssef */ 53831567Ssef 53931567Ssefchar * 540240005Szontprint_arg(struct syscall_args *sc, unsigned long *args, long retval, 541240005Szont struct trussinfo *trussinfo) 542181061Sdes{ 543240005Szont char *tmp; 544240005Szont pid_t pid; 545158630Spav 546240005Szont tmp = NULL; 547240005Szont pid = trussinfo->pid; 548181061Sdes switch (sc->type & ARG_MASK) { 549181061Sdes case Hex: 550181061Sdes asprintf(&tmp, "0x%x", (int)args[sc->offset]); 551181061Sdes break; 552181061Sdes case Octal: 553181061Sdes asprintf(&tmp, "0%o", (int)args[sc->offset]); 554181061Sdes break; 555181061Sdes case Int: 556181061Sdes asprintf(&tmp, "%d", (int)args[sc->offset]); 557181061Sdes break; 558181061Sdes case Name: { 559181061Sdes /* NULL-terminated string. */ 560181061Sdes char *tmp2; 561181061Sdes tmp2 = get_string(pid, (void*)args[sc->offset], 0); 562181061Sdes asprintf(&tmp, "\"%s\"", tmp2); 563181061Sdes free(tmp2); 564181061Sdes break; 565181061Sdes } 566181061Sdes case BinString: { 567181061Sdes /* Binary block of data that might have printable characters. 568181061Sdes XXX If type|OUT, assume that the length is the syscall's 569181061Sdes return value. Otherwise, assume that the length of the block 570181061Sdes is in the next syscall argument. */ 571181061Sdes int max_string = trussinfo->strsize; 572181061Sdes char tmp2[max_string+1], *tmp3; 573181061Sdes int len; 574181061Sdes int truncated = 0; 575158630Spav 576181061Sdes if (sc->type & OUT) 577181061Sdes len = retval; 578181061Sdes else 579181061Sdes len = args[sc->offset + 1]; 580101289Smdodd 581181061Sdes /* Don't print more than max_string characters, to avoid word 582181061Sdes wrap. If we have to truncate put some ... after the string. 583181061Sdes */ 584181061Sdes if (len > max_string) { 585181061Sdes len = max_string; 586181061Sdes truncated = 1; 587181061Sdes } 588240005Szont if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len) 589240005Szont != -1) { 590181061Sdes tmp3 = malloc(len * 4 + 1); 591181061Sdes while (len) { 592240005Szont if (strvisx(tmp3, tmp2, len, 593240005Szont VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string) 594181061Sdes break; 595181061Sdes len--; 596181061Sdes truncated = 1; 597181061Sdes }; 598240005Szont asprintf(&tmp, "\"%s\"%s", tmp3, truncated ? 599240005Szont "..." : ""); 600181061Sdes free(tmp3); 601181061Sdes } else { 602181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 603181061Sdes } 604181061Sdes break; 605181061Sdes } 606181061Sdes case StringArray: { 607181061Sdes int num, size, i; 608181061Sdes char *tmp2; 609181061Sdes char *string; 610181061Sdes char *strarray[100]; /* XXX This is ugly. */ 611101289Smdodd 612240005Szont if (get_struct(pid, (void *)args[sc->offset], 613240005Szont (void *)&strarray, sizeof(strarray)) == -1) 614181061Sdes err(1, "get_struct %p", (void *)args[sc->offset]); 615181061Sdes num = 0; 616181061Sdes size = 0; 617101289Smdodd 618181061Sdes /* Find out how large of a buffer we'll need. */ 619181061Sdes while (strarray[num] != NULL) { 620181061Sdes string = get_string(pid, (void*)strarray[num], 0); 621181061Sdes size += strlen(string); 622181061Sdes free(string); 623181061Sdes num++; 624181061Sdes } 625181061Sdes size += 4 + (num * 4); 626181061Sdes tmp = (char *)malloc(size); 627181061Sdes tmp2 = tmp; 628181061Sdes 629181061Sdes tmp2 += sprintf(tmp2, " ["); 630181061Sdes for (i = 0; i < num; i++) { 631181061Sdes string = get_string(pid, (void*)strarray[i], 0); 632240005Szont tmp2 += sprintf(tmp2, " \"%s\"%c", string, 633240005Szont (i + 1 == num) ? ' ' : ','); 634181061Sdes free(string); 635181061Sdes } 636181061Sdes tmp2 += sprintf(tmp2, "]"); 637181061Sdes break; 638181061Sdes } 639134799Smarcel#ifdef __LP64__ 640181061Sdes case Quad: 641181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 642181061Sdes break; 643134799Smarcel#else 644181061Sdes case Quad: { 645181061Sdes unsigned long long ll; 646181061Sdes ll = *(unsigned long long *)(args + sc->offset); 647181061Sdes asprintf(&tmp, "0x%llx", ll); 648181061Sdes break; 649181061Sdes } 650134799Smarcel#endif 651181061Sdes case Ptr: 652181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 653181061Sdes break; 654181061Sdes case Readlinkres: { 655181061Sdes char *tmp2; 656181061Sdes if (retval == -1) { 657181061Sdes tmp = strdup(""); 658181061Sdes break; 659181061Sdes } 660181061Sdes tmp2 = get_string(pid, (void*)args[sc->offset], retval); 661181061Sdes asprintf(&tmp, "\"%s\"", tmp2); 662181061Sdes free(tmp2); 663181061Sdes break; 664181061Sdes } 665181061Sdes case Ioctl: { 666181061Sdes const char *temp = ioctlname(args[sc->offset]); 667240005Szont if (temp) 668181061Sdes tmp = strdup(temp); 669240005Szont else { 670181061Sdes unsigned long arg = args[sc->offset]; 671240005Szont asprintf(&tmp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }", 672240005Szont arg, arg & IOC_OUT ? "R" : "", 673240005Szont arg & IOC_IN ? "W" : "", IOCGROUP(arg), 674240005Szont isprint(IOCGROUP(arg)) ? (char)IOCGROUP(arg) : '?', 675181061Sdes arg & 0xFF, IOCPARM_LEN(arg)); 676181061Sdes } 677181061Sdes break; 678181061Sdes } 679181061Sdes case Umtx: { 680181061Sdes struct umtx umtx; 681240005Szont if (get_struct(pid, (void *)args[sc->offset], &umtx, 682240005Szont sizeof(umtx)) != -1) 683181061Sdes asprintf(&tmp, "{ 0x%lx }", (long)umtx.u_owner); 684181061Sdes else 685181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 686181061Sdes break; 687181061Sdes } 688181061Sdes case Timespec: { 689181061Sdes struct timespec ts; 690240005Szont if (get_struct(pid, (void *)args[sc->offset], &ts, 691240005Szont sizeof(ts)) != -1) 692240005Szont asprintf(&tmp, "{%ld.%09ld }", (long)ts.tv_sec, 693240005Szont ts.tv_nsec); 694181061Sdes else 695181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 696181061Sdes break; 697181061Sdes } 698181061Sdes case Timeval: { 699181061Sdes struct timeval tv; 700240005Szont if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) 701240005Szont != -1) 702240005Szont asprintf(&tmp, "{%ld.%06ld }", (long)tv.tv_sec, 703240005Szont tv.tv_usec); 704181061Sdes else 705181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 706181061Sdes break; 707181061Sdes } 708181061Sdes case Timeval2: { 709181061Sdes struct timeval tv[2]; 710240005Szont if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) 711240005Szont != -1) 712181061Sdes asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }", 713181061Sdes (long)tv[0].tv_sec, tv[0].tv_usec, 714181061Sdes (long)tv[1].tv_sec, tv[1].tv_usec); 715181061Sdes else 716181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 717181061Sdes break; 718181061Sdes } 719181061Sdes case Itimerval: { 720181061Sdes struct itimerval itv; 721240005Szont if (get_struct(pid, (void *)args[sc->offset], &itv, 722240005Szont sizeof(itv)) != -1) 723181061Sdes asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }", 724181061Sdes (long)itv.it_interval.tv_sec, 725181061Sdes itv.it_interval.tv_usec, 726181061Sdes (long)itv.it_value.tv_sec, 727181061Sdes itv.it_value.tv_usec); 728181061Sdes else 729181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 730181061Sdes break; 731181061Sdes } 732181061Sdes case Pollfd: { 733181061Sdes /* 734240005Szont * XXX: A Pollfd argument expects the /next/ syscall argument 735240005Szont * to be the number of fds in the array. This matches the poll 736240005Szont * syscall. 737181061Sdes */ 738181061Sdes struct pollfd *pfd; 739181061Sdes int numfds = args[sc->offset+1]; 740181061Sdes int bytes = sizeof(struct pollfd) * numfds; 741181061Sdes int i, tmpsize, u, used; 742181061Sdes const int per_fd = 100; 743127332Sdwmalone 744181061Sdes if ((pfd = malloc(bytes)) == NULL) 745240005Szont err(1, "Cannot malloc %d bytes for pollfd array", 746240005Szont bytes); 747240005Szont if (get_struct(pid, (void *)args[sc->offset], pfd, bytes) 748240005Szont != -1) { 749181061Sdes used = 0; 750181061Sdes tmpsize = 1 + per_fd * numfds + 2; 751181061Sdes if ((tmp = malloc(tmpsize)) == NULL) 752240005Szont err(1, "Cannot alloc %d bytes for poll output", 753240005Szont tmpsize); 754127332Sdwmalone 755181061Sdes tmp[used++] = '{'; 756181061Sdes for (i = 0; i < numfds; i++) { 757127332Sdwmalone 758240005Szont u = snprintf(tmp + used, per_fd, "%s%d/%s", 759240005Szont i > 0 ? " " : "", pfd[i].fd, 760240005Szont xlookup_bits(poll_flags, pfd[i].events)); 761181061Sdes if (u > 0) 762181061Sdes used += u < per_fd ? u : per_fd; 763181061Sdes } 764181061Sdes tmp[used++] = '}'; 765181061Sdes tmp[used++] = '\0'; 766181061Sdes } else { 767181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 768181061Sdes } 769181061Sdes free(pfd); 770181061Sdes break; 771127332Sdwmalone } 772181061Sdes case Fd_set: { 773181061Sdes /* 774240005Szont * XXX: A Fd_set argument expects the /first/ syscall argument 775240005Szont * to be the number of fds in the array. This matches the 776240005Szont * select syscall. 777181061Sdes */ 778181061Sdes fd_set *fds; 779181061Sdes int numfds = args[0]; 780181061Sdes int bytes = _howmany(numfds, _NFDBITS) * _NFDBITS; 781181061Sdes int i, tmpsize, u, used; 782181061Sdes const int per_fd = 20; 783127332Sdwmalone 784181061Sdes if ((fds = malloc(bytes)) == NULL) 785240005Szont err(1, "Cannot malloc %d bytes for fd_set array", 786240005Szont bytes); 787240005Szont if (get_struct(pid, (void *)args[sc->offset], fds, bytes) 788240005Szont != -1) { 789181061Sdes used = 0; 790181061Sdes tmpsize = 1 + numfds * per_fd + 2; 791181061Sdes if ((tmp = malloc(tmpsize)) == NULL) 792240005Szont err(1, "Cannot alloc %d bytes for fd_set " 793240005Szont "output", tmpsize); 794127332Sdwmalone 795181061Sdes tmp[used++] = '{'; 796181061Sdes for (i = 0; i < numfds; i++) { 797181061Sdes if (FD_ISSET(i, fds)) { 798240005Szont u = snprintf(tmp + used, per_fd, "%d ", 799240005Szont i); 800181061Sdes if (u > 0) 801181061Sdes used += u < per_fd ? u : per_fd; 802181061Sdes } 803181061Sdes } 804181061Sdes if (tmp[used-1] == ' ') 805181061Sdes used--; 806181061Sdes tmp[used++] = '}'; 807181061Sdes tmp[used++] = '\0'; 808240005Szont } else 809181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 810181061Sdes free(fds); 811181061Sdes break; 812127332Sdwmalone } 813181061Sdes case Signal: { 814181061Sdes long sig; 81549609Sdes 816181061Sdes sig = args[sc->offset]; 817181061Sdes tmp = strsig(sig); 818181061Sdes if (tmp == NULL) 819181061Sdes asprintf(&tmp, "%ld", sig); 820181061Sdes break; 821181061Sdes } 822181061Sdes case Sigset: { 823181061Sdes long sig; 824181061Sdes sigset_t ss; 825181061Sdes int i, used; 826158630Spav 827181061Sdes sig = args[sc->offset]; 828240005Szont if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, 829240005Szont sizeof(ss)) == -1) { 830181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 831181061Sdes break; 832181061Sdes } 833181061Sdes tmp = malloc(sys_nsig * 8); /* 7 bytes avg per signal name */ 834181061Sdes used = 0; 835181061Sdes for (i = 1; i < sys_nsig; i++) { 836240005Szont if (sigismember(&ss, i)) 837181061Sdes used += sprintf(tmp + used, "%s|", strsig(i)); 838181061Sdes } 839181061Sdes if (used) 840181061Sdes tmp[used-1] = 0; 841181061Sdes else 842181061Sdes strcpy(tmp, "0x0"); 843181061Sdes break; 844181061Sdes } 845181061Sdes case Sigprocmask: { 846181061Sdes switch (args[sc->offset]) { 847240005Szont#define S(a) case a: tmp = strdup(#a); break; 848181061Sdes S(SIG_BLOCK); 849181061Sdes S(SIG_UNBLOCK); 850181061Sdes S(SIG_SETMASK); 851127328Salfred#undef S 852181061Sdes } 853181061Sdes if (tmp == NULL) 854181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 855181061Sdes break; 856127328Salfred } 857181061Sdes case Fcntlflag: { 858181061Sdes /* XXX output depends on the value of the previous argument */ 859181061Sdes switch (args[sc->offset-1]) { 860181061Sdes case F_SETFD: 861240005Szont tmp = strdup(xlookup_bits(fcntlfd_arg, 862240005Szont args[sc->offset])); 863181061Sdes break; 864181061Sdes case F_SETFL: 865240005Szont tmp = strdup(xlookup_bits(fcntlfl_arg, 866240005Szont args[sc->offset])); 867181061Sdes break; 868181061Sdes case F_GETFD: 869181061Sdes case F_GETFL: 870181061Sdes case F_GETOWN: 871181061Sdes tmp = strdup(""); 872181061Sdes break; 873181061Sdes default: 874181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 875181061Sdes break; 876181061Sdes } 877181061Sdes break; 878181061Sdes } 879181061Sdes case Open: 880181061Sdes tmp = strdup(xlookup_bits(open_flags, args[sc->offset])); 881181061Sdes break; 882181061Sdes case Fcntl: 883181061Sdes tmp = strdup(xlookup(fcntl_arg, args[sc->offset])); 884181061Sdes break; 885181061Sdes case Mprot: 886181061Sdes tmp = strdup(xlookup_bits(mprot_flags, args[sc->offset])); 887181061Sdes break; 888181061Sdes case Mmapflags: 889181061Sdes tmp = strdup(xlookup_bits(mmap_flags, args[sc->offset])); 890181061Sdes break; 891181061Sdes case Whence: 892181061Sdes tmp = strdup(xlookup(whence_arg, args[sc->offset])); 893181061Sdes break; 894181061Sdes case Sockdomain: 895181061Sdes tmp = strdup(xlookup(sockdomain_arg, args[sc->offset])); 896181061Sdes break; 897181061Sdes case Socktype: 898181061Sdes tmp = strdup(xlookup(socktype_arg, args[sc->offset])); 899181061Sdes break; 900181061Sdes case Shutdown: 901181061Sdes tmp = strdup(xlookup(shutdown_arg, args[sc->offset])); 902181061Sdes break; 903181061Sdes case Resource: 904181061Sdes tmp = strdup(xlookup(resource_arg, args[sc->offset])); 905181061Sdes break; 906181061Sdes case Pathconf: 907181061Sdes tmp = strdup(xlookup(pathconf_arg, args[sc->offset])); 908181061Sdes break; 909181061Sdes case Sockaddr: { 910181061Sdes struct sockaddr_storage ss; 911181061Sdes char addr[64]; 912181061Sdes struct sockaddr_in *lsin; 913181061Sdes struct sockaddr_in6 *lsin6; 914181061Sdes struct sockaddr_un *sun; 915181061Sdes struct sockaddr *sa; 916181061Sdes char *p; 917181061Sdes u_char *q; 918181061Sdes int i; 91985292Sdes 920181061Sdes if (args[sc->offset] == 0) { 921181061Sdes asprintf(&tmp, "NULL"); 922181061Sdes break; 923181061Sdes } 924121606Smarcel 925181061Sdes /* yuck: get ss_len */ 926181061Sdes if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, 927240005Szont sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1) 928181061Sdes err(1, "get_struct %p", (void *)args[sc->offset]); 929181061Sdes /* 930181061Sdes * If ss_len is 0, then try to guess from the sockaddr type. 931181061Sdes * AF_UNIX may be initialized incorrectly, so always frob 932181061Sdes * it by using the "right" size. 933181061Sdes */ 934181061Sdes if (ss.ss_len == 0 || ss.ss_family == AF_UNIX) { 935181061Sdes switch (ss.ss_family) { 936181061Sdes case AF_INET: 937181061Sdes ss.ss_len = sizeof(*lsin); 938181061Sdes break; 939181061Sdes case AF_UNIX: 940181061Sdes ss.ss_len = sizeof(*sun); 941181061Sdes break; 942181061Sdes default: 943181061Sdes /* hurrrr */ 944181061Sdes break; 945181061Sdes } 946181061Sdes } 947240005Szont if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, 948240005Szont ss.ss_len) == -1) { 949181061Sdes err(2, "get_struct %p", (void *)args[sc->offset]); 950181061Sdes } 95185292Sdes 952181061Sdes switch (ss.ss_family) { 953181061Sdes case AF_INET: 954181061Sdes lsin = (struct sockaddr_in *)&ss; 955181061Sdes inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof addr); 956240005Szont asprintf(&tmp, "{ AF_INET %s:%d }", addr, 957240005Szont htons(lsin->sin_port)); 958181061Sdes break; 959181061Sdes case AF_INET6: 960181061Sdes lsin6 = (struct sockaddr_in6 *)&ss; 961240005Szont inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, 962240005Szont sizeof addr); 963240005Szont asprintf(&tmp, "{ AF_INET6 [%s]:%d }", addr, 964240005Szont htons(lsin6->sin6_port)); 965181061Sdes break; 966181061Sdes case AF_UNIX: 967181061Sdes sun = (struct sockaddr_un *)&ss; 968181061Sdes asprintf(&tmp, "{ AF_UNIX \"%s\" }", sun->sun_path); 969181061Sdes break; 970181061Sdes default: 971181061Sdes sa = (struct sockaddr *)&ss; 972240005Szont asprintf(&tmp, "{ sa_len = %d, sa_family = %d, sa_data " 973240005Szont "= {%n%*s } }", (int)sa->sa_len, (int)sa->sa_family, 974240005Szont &i, 6 * (int)(sa->sa_len - ((char *)&sa->sa_data - 975240005Szont (char *)sa)), ""); 976181061Sdes if (tmp != NULL) { 977181061Sdes p = tmp + i; 978240005Szont for (q = (u_char *)&sa->sa_data; 979240005Szont q < (u_char *)sa + sa->sa_len; q++) 980181061Sdes p += sprintf(p, " %#02x,", *q); 981181061Sdes } 982181061Sdes } 983181061Sdes break; 98486138Sgreen } 985181061Sdes case Sigaction: { 986181061Sdes struct sigaction sa; 987181061Sdes char *hand; 988181061Sdes const char *h; 989127332Sdwmalone 990240005Szont if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa)) 991240005Szont != -1) { 992181061Sdes asprintf(&hand, "%p", sa.sa_handler); 993181061Sdes if (sa.sa_handler == SIG_DFL) 994181061Sdes h = "SIG_DFL"; 995181061Sdes else if (sa.sa_handler == SIG_IGN) 996181061Sdes h = "SIG_IGN"; 997181061Sdes else 998181061Sdes h = hand; 999158630Spav 1000240005Szont asprintf(&tmp, "{ %s %s ss_t }", h, 1001181061Sdes xlookup_bits(sigaction_flags, sa.sa_flags)); 1002181061Sdes free(hand); 1003240005Szont } else 1004181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 1005181061Sdes break; 1006181061Sdes } 1007181061Sdes case Kevent: { 1008181061Sdes /* 1009181061Sdes * XXX XXX: the size of the array is determined by either the 1010181061Sdes * next syscall argument, or by the syscall returnvalue, 1011181061Sdes * depending on which argument number we are. This matches the 1012181061Sdes * kevent syscall, but luckily that's the only syscall that uses 1013181061Sdes * them. 1014181061Sdes */ 1015181061Sdes struct kevent *ke; 1016181061Sdes int numevents = -1; 1017181061Sdes int bytes = 0; 1018181061Sdes int i, tmpsize, u, used; 1019181061Sdes const int per_ke = 100; 1020158630Spav 1021181061Sdes if (sc->offset == 1) 1022181061Sdes numevents = args[sc->offset+1]; 1023181061Sdes else if (sc->offset == 3 && retval != -1) 1024181061Sdes numevents = retval; 1025158630Spav 1026181061Sdes if (numevents >= 0) 1027181061Sdes bytes = sizeof(struct kevent) * numevents; 1028181061Sdes if ((ke = malloc(bytes)) == NULL) 1029240005Szont err(1, "Cannot malloc %d bytes for kevent array", 1030240005Szont bytes); 1031240005Szont if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset], 1032240005Szont ke, bytes) != -1) { 1033181061Sdes used = 0; 1034181061Sdes tmpsize = 1 + per_ke * numevents + 2; 1035181061Sdes if ((tmp = malloc(tmpsize)) == NULL) 1036240005Szont err(1, "Cannot alloc %d bytes for kevent " 1037240005Szont "output", tmpsize); 1038158630Spav 1039181061Sdes tmp[used++] = '{'; 1040181061Sdes for (i = 0; i < numevents; i++) { 1041181061Sdes u = snprintf(tmp + used, per_ke, 1042181061Sdes "%s%p,%s,%s,%d,%p,%p", 1043181061Sdes i > 0 ? " " : "", 1044181061Sdes (void *)ke[i].ident, 1045181061Sdes xlookup(kevent_filters, ke[i].filter), 1046181061Sdes xlookup_bits(kevent_flags, ke[i].flags), 1047181061Sdes ke[i].fflags, 1048181061Sdes (void *)ke[i].data, 1049181061Sdes (void *)ke[i].udata); 1050181061Sdes if (u > 0) 1051181061Sdes used += u < per_ke ? u : per_ke; 1052181061Sdes } 1053181061Sdes tmp[used++] = '}'; 1054181061Sdes tmp[used++] = '\0'; 1055181061Sdes } else { 1056181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 1057181061Sdes } 1058181061Sdes free(ke); 1059181061Sdes break; 1060158630Spav } 1061181061Sdes case Stat: { 1062181061Sdes struct stat st; 1063240005Szont if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st)) 1064240005Szont != -1) { 1065181061Sdes char mode[12]; 1066181061Sdes strmode(st.st_mode, mode); 1067240005Szont asprintf(&tmp, 1068240005Szont "{ mode=%s,inode=%jd,size=%jd,blksize=%ld }", mode, 1069240005Szont (intmax_t)st.st_ino, (intmax_t)st.st_size, 1070240005Szont (long)st.st_blksize); 1071181061Sdes } else { 1072181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 1073181061Sdes } 1074181061Sdes break; 1075181061Sdes } 1076181061Sdes case Rusage: { 1077181061Sdes struct rusage ru; 1078240005Szont if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru)) 1079240005Szont != -1) { 1080240005Szont asprintf(&tmp, 1081240005Szont "{ u=%ld.%06ld,s=%ld.%06ld,in=%ld,out=%ld }", 1082181061Sdes (long)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec, 1083181061Sdes (long)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec, 1084181061Sdes ru.ru_inblock, ru.ru_oublock); 1085240005Szont } else 1086181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 1087181061Sdes break; 1088181061Sdes } 1089181061Sdes case Rlimit: { 1090181061Sdes struct rlimit rl; 1091240005Szont if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl)) 1092240005Szont != -1) { 1093181061Sdes asprintf(&tmp, "{ cur=%ju,max=%ju }", 1094181061Sdes rl.rlim_cur, rl.rlim_max); 1095240005Szont } else 1096181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 1097181061Sdes break; 1098181061Sdes } 1099181061Sdes default: 1100181061Sdes errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK); 1101181061Sdes } 1102181061Sdes return (tmp); 110331567Ssef} 110431567Ssef 110531567Ssef/* 110631567Ssef * print_syscall 110731567Ssef * Print (to outfile) the system call and its arguments. Note that 110831567Ssef * nargs is the number of arguments (not the number of words; this is 110931567Ssef * potentially confusing, I know). 111031567Ssef */ 111131567Ssef 111231567Ssefvoid 1113240005Szontprint_syscall(struct trussinfo *trussinfo, const char *name, int nargs, 1114240005Szont char **s_args) 1115181061Sdes{ 1116181061Sdes struct timespec timediff; 1117240005Szont int i, len; 1118101283Smdodd 1119240005Szont len = 0; 1120181061Sdes if (trussinfo->flags & FOLLOWFORKS) 1121181061Sdes len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid); 1122101283Smdodd 1123240562Szont if (name != NULL && (strcmp(name, "execve") == 0 || 1124240005Szont strcmp(name, "exit") == 0)) { 1125240562Szont clock_gettime(CLOCK_REALTIME, &trussinfo->curthread->after); 1126181061Sdes } 1127101285Smdodd 1128181061Sdes if (trussinfo->flags & ABSOLUTETIMESTAMPS) { 1129240562Szont timespecsubt(&trussinfo->curthread->after, 1130240562Szont &trussinfo->start_time, &timediff); 1131181061Sdes len += fprintf(trussinfo->outfile, "%ld.%09ld ", 1132181061Sdes (long)timediff.tv_sec, timediff.tv_nsec); 1133181061Sdes } 1134101285Smdodd 1135181061Sdes if (trussinfo->flags & RELATIVETIMESTAMPS) { 1136240562Szont timespecsubt(&trussinfo->curthread->after, 1137240562Szont &trussinfo->curthread->before, &timediff); 1138181061Sdes len += fprintf(trussinfo->outfile, "%ld.%09ld ", 1139181061Sdes (long)timediff.tv_sec, timediff.tv_nsec); 1140181061Sdes } 1141101285Smdodd 1142181061Sdes len += fprintf(trussinfo->outfile, "%s(", name); 1143101283Smdodd 1144181061Sdes for (i = 0; i < nargs; i++) { 1145181061Sdes if (s_args[i]) 1146181061Sdes len += fprintf(trussinfo->outfile, "%s", s_args[i]); 1147181061Sdes else 1148240005Szont len += fprintf(trussinfo->outfile, 1149240005Szont "<missing argument>"); 1150240005Szont len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? 1151240005Szont "," : ""); 1152181061Sdes } 1153181061Sdes len += fprintf(trussinfo->outfile, ")"); 1154181061Sdes for (i = 0; i < 6 - (len / 8); i++) 1155181061Sdes fprintf(trussinfo->outfile, "\t"); 115631567Ssef} 115758224Ssef 115858224Ssefvoid 1159122348Smarcelprint_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs, 1160192025Sdds char **s_args, int errorp, long retval, struct syscall *sc) 1161122348Smarcel{ 1162192025Sdds struct timespec timediff; 1163181061Sdes 1164192025Sdds if (trussinfo->flags & COUNTONLY) { 1165192025Sdds if (!sc) 1166192025Sdds return; 1167240562Szont clock_gettime(CLOCK_REALTIME, &trussinfo->curthread->after); 1168240562Szont timespecsubt(&trussinfo->curthread->after, 1169240562Szont &trussinfo->curthread->before, &timediff); 1170192025Sdds timespecadd(&sc->time, &timediff, &sc->time); 1171192025Sdds sc->ncalls++; 1172192025Sdds if (errorp) 1173192025Sdds sc->nerror++; 1174192025Sdds return; 1175192025Sdds } 1176192025Sdds 1177181061Sdes print_syscall(trussinfo, name, nargs, s_args); 1178181061Sdes fflush(trussinfo->outfile); 1179240005Szont if (errorp) 1180240005Szont fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval, 1181240005Szont strerror(retval)); 1182240005Szont else { 1183200780Sjh /* 1184200780Sjh * Because pipe(2) has a special assembly glue to provide the 1185200780Sjh * libc API, we have to adjust retval. 1186200780Sjh */ 1187240005Szont if (name != NULL && strcmp(name, "pipe") == 0) 1188200780Sjh retval = 0; 1189181061Sdes fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval, retval); 1190181061Sdes } 119158224Ssef} 1192192025Sdds 1193192025Sddsvoid 1194192025Sddsprint_summary(struct trussinfo *trussinfo) 1195192025Sdds{ 1196240005Szont struct timespec total = {0, 0}; 1197192025Sdds struct syscall *sc; 1198192025Sdds int ncall, nerror; 1199192025Sdds 1200192025Sdds fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n", 1201240005Szont "syscall", "seconds", "calls", "errors"); 1202192025Sdds ncall = nerror = 0; 1203192025Sdds for (sc = syscalls; sc->name != NULL; sc++) 1204192025Sdds if (sc->ncalls) { 1205200781Sjh fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 1206200781Sjh sc->name, (intmax_t)sc->time.tv_sec, 1207200781Sjh sc->time.tv_nsec, sc->ncalls, sc->nerror); 1208192025Sdds timespecadd(&total, &sc->time, &total); 1209192025Sdds ncall += sc->ncalls; 1210192025Sdds nerror += sc->nerror; 1211192025Sdds } 1212192025Sdds fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n", 1213240005Szont "", "-------------", "-------", "-------"); 1214200781Sjh fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 1215240005Szont "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror); 1216192025Sdds} 1217