syscalls.c revision 200902
131567Ssef/* 231899Ssef * Copryight 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 200902 2009-12-23 15:22:50Z ed $"; 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 */ 9231567Ssefstruct 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 272158630Spav#define X(a) { a, #a }, 273158630Spav#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) 278158630Spav X(EVFILT_NETDEV) 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 286158630Spavstruct 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{ 417158630Spav static char str[512]; 418158630Spav int len = 0; 419158630Spav int rem = val; 420158630Spav 421181061Sdes for (; xlat->str != NULL; xlat++) { 422181061Sdes if ((xlat->val & rem) == xlat->val) { 423158630Spav /* don't print the "all-bits-zero" string unless all 424158630Spav bits are really zero */ 425158630Spav if (xlat->val == 0 && val != 0) 426158630Spav continue; 427158630Spav len += sprintf(str + len, "%s|", xlat->str); 428158630Spav rem &= ~(xlat->val); 429158630Spav } 430158630Spav } 431158630Spav /* if we have leftover bits or didn't match anything */ 432158630Spav if (rem || len == 0) 433158630Spav len += sprintf(str + len, "0x%x", rem); 434158630Spav if (len && str[len - 1] == '|') 435158630Spav len--; 436158630Spav str[len] = 0; 437181061Sdes return (str); 438158630Spav} 439158630Spav 44031567Ssef/* 44131567Ssef * If/when the list gets big, it might be desirable to do it 44231567Ssef * as a hash table or binary search. 44331567Ssef */ 44431567Ssef 44531567Ssefstruct syscall * 446181061Sdesget_syscall(const char *name) 447181061Sdes{ 44831567Ssef struct syscall *sc = syscalls; 44931567Ssef 450133349Salfred if (name == NULL) 451133349Salfred return (NULL); 45231567Ssef while (sc->name) { 45331567Ssef if (!strcmp(name, sc->name)) 454181061Sdes return (sc); 45531567Ssef sc++; 45631567Ssef } 457181061Sdes return (NULL); 45831567Ssef} 45931567Ssef 46031567Ssef/* 46185292Sdes * get_struct 46285292Sdes * 46385292Sdes * Copy a fixed amount of bytes from the process. 46485292Sdes */ 46585292Sdes 46687703Smarkmstatic int 467181061Sdesget_struct(int pid, void *offset, void *buf, int len) 468181061Sdes{ 469168569Sdelphij struct ptrace_io_desc iorequest; 470181061Sdes 471168569Sdelphij iorequest.piod_op = PIOD_READ_D; 472168569Sdelphij iorequest.piod_offs = offset; 473168569Sdelphij iorequest.piod_addr = buf; 474168569Sdelphij iorequest.piod_len = len; 475168569Sdelphij if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) 476181061Sdes return (-1); 477181061Sdes return (0); 47885292Sdes} 47985292Sdes 480181061Sdes#define MAXSIZE 4096 481181061Sdes#define BLOCKSIZE 1024 48285292Sdes/* 48331567Ssef * get_string 48431567Ssef * Copy a string from the process. Note that it is 48531567Ssef * expected to be a C string, but if max is set, it will 48631567Ssef * only get that much. 48731567Ssef */ 48831567Ssef 489168569Sdelphijstatic char * 490181061Sdesget_string(pid_t pid, void *offset, int max) 491181061Sdes{ 49232275Scharnier char *buf; 493168569Sdelphij struct ptrace_io_desc iorequest; 494168569Sdelphij int totalsize, size; 495168569Sdelphij int diff = 0; 496168569Sdelphij int i; 497181061Sdes 498181061Sdes totalsize = size = max ? (max + 1) : BLOCKSIZE; 499168569Sdelphij buf = malloc(totalsize); 500168569Sdelphij if (buf == NULL) 501181061Sdes return (NULL); 502181061Sdes for (;;) { 503168569Sdelphij diff = totalsize - size; 504168569Sdelphij iorequest.piod_op = PIOD_READ_D; 505168569Sdelphij iorequest.piod_offs = (char *)offset + diff; 506168569Sdelphij iorequest.piod_addr = buf + diff; 507168569Sdelphij iorequest.piod_len = size; 508168569Sdelphij if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) { 509168569Sdelphij free(buf); 510181061Sdes return (NULL); 51131567Ssef } 512168569Sdelphij for (i = 0 ; i < size; i++) { 513168569Sdelphij if (buf[diff + i] == '\0') 514168569Sdelphij return (buf); 515168569Sdelphij } 516168569Sdelphij if (totalsize < MAXSIZE - BLOCKSIZE && max == 0) { 517168569Sdelphij totalsize += BLOCKSIZE; 518168569Sdelphij buf = realloc(buf, totalsize); 519168569Sdelphij size = BLOCKSIZE; 520181061Sdes } else { 521168569Sdelphij buf[totalsize] = '\0'; 522181061Sdes return (buf); 523168569Sdelphij } 52431567Ssef } 52531567Ssef} 52631567Ssef 52731567Ssef 52831567Ssef/* 52931567Ssef * print_arg 53031567Ssef * Converts a syscall argument into a string. Said string is 53131567Ssef * allocated via malloc(), so needs to be free()'d. The file 53231567Ssef * descriptor is for the process' memory (via /proc), and is used 53331567Ssef * to get any data (where the argument is a pointer). sc is 53431567Ssef * a pointer to the syscall description (see above); args is 53531567Ssef * an array of all of the system call arguments. 53631567Ssef */ 53731567Ssef 53831567Ssefchar * 539181061Sdesprint_arg(struct syscall_args *sc, unsigned long *args, long retval, struct trussinfo *trussinfo) 540181061Sdes{ 541181061Sdes char *tmp = NULL; 542181061Sdes int pid = trussinfo->pid; 543158630Spav 544181061Sdes switch (sc->type & ARG_MASK) { 545181061Sdes case Hex: 546181061Sdes asprintf(&tmp, "0x%x", (int)args[sc->offset]); 547181061Sdes break; 548181061Sdes case Octal: 549181061Sdes asprintf(&tmp, "0%o", (int)args[sc->offset]); 550181061Sdes break; 551181061Sdes case Int: 552181061Sdes asprintf(&tmp, "%d", (int)args[sc->offset]); 553181061Sdes break; 554181061Sdes case Name: { 555181061Sdes /* NULL-terminated string. */ 556181061Sdes char *tmp2; 557181061Sdes tmp2 = get_string(pid, (void*)args[sc->offset], 0); 558181061Sdes asprintf(&tmp, "\"%s\"", tmp2); 559181061Sdes free(tmp2); 560181061Sdes break; 561181061Sdes } 562181061Sdes case BinString: { 563181061Sdes /* Binary block of data that might have printable characters. 564181061Sdes XXX If type|OUT, assume that the length is the syscall's 565181061Sdes return value. Otherwise, assume that the length of the block 566181061Sdes is in the next syscall argument. */ 567181061Sdes int max_string = trussinfo->strsize; 568181061Sdes char tmp2[max_string+1], *tmp3; 569181061Sdes int len; 570181061Sdes int truncated = 0; 571158630Spav 572181061Sdes if (sc->type & OUT) 573181061Sdes len = retval; 574181061Sdes else 575181061Sdes len = args[sc->offset + 1]; 576101289Smdodd 577181061Sdes /* Don't print more than max_string characters, to avoid word 578181061Sdes wrap. If we have to truncate put some ... after the string. 579181061Sdes */ 580181061Sdes if (len > max_string) { 581181061Sdes len = max_string; 582181061Sdes truncated = 1; 583181061Sdes } 584181061Sdes if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len) != -1) { 585181061Sdes tmp3 = malloc(len * 4 + 1); 586181061Sdes while (len) { 587181061Sdes if (strvisx(tmp3, tmp2, len, VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string) 588181061Sdes break; 589181061Sdes len--; 590181061Sdes truncated = 1; 591181061Sdes }; 592181061Sdes asprintf(&tmp, "\"%s\"%s", tmp3, truncated?"...":""); 593181061Sdes free(tmp3); 594181061Sdes } else { 595181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 596181061Sdes } 597181061Sdes break; 598181061Sdes } 599181061Sdes case StringArray: { 600181061Sdes int num, size, i; 601181061Sdes char *tmp2; 602181061Sdes char *string; 603181061Sdes char *strarray[100]; /* XXX This is ugly. */ 604101289Smdodd 605181061Sdes if (get_struct(pid, (void *)args[sc->offset], (void *)&strarray, 606181061Sdes sizeof(strarray)) == -1) { 607181061Sdes err(1, "get_struct %p", (void *)args[sc->offset]); 608181061Sdes } 609181061Sdes num = 0; 610181061Sdes size = 0; 611101289Smdodd 612181061Sdes /* Find out how large of a buffer we'll need. */ 613181061Sdes while (strarray[num] != NULL) { 614181061Sdes string = get_string(pid, (void*)strarray[num], 0); 615181061Sdes size += strlen(string); 616181061Sdes free(string); 617181061Sdes num++; 618181061Sdes } 619181061Sdes size += 4 + (num * 4); 620181061Sdes tmp = (char *)malloc(size); 621181061Sdes tmp2 = tmp; 622181061Sdes 623181061Sdes tmp2 += sprintf(tmp2, " ["); 624181061Sdes for (i = 0; i < num; i++) { 625181061Sdes string = get_string(pid, (void*)strarray[i], 0); 626181061Sdes tmp2 += sprintf(tmp2, " \"%s\"%c", string, (i+1 == num) ? ' ' : ','); 627181061Sdes free(string); 628181061Sdes } 629181061Sdes tmp2 += sprintf(tmp2, "]"); 630181061Sdes break; 631181061Sdes } 632134799Smarcel#ifdef __LP64__ 633181061Sdes case Quad: 634181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 635181061Sdes break; 636134799Smarcel#else 637181061Sdes case Quad: { 638181061Sdes unsigned long long ll; 639181061Sdes ll = *(unsigned long long *)(args + sc->offset); 640181061Sdes asprintf(&tmp, "0x%llx", ll); 641181061Sdes break; 642181061Sdes } 643134799Smarcel#endif 644181061Sdes case Ptr: 645181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 646181061Sdes break; 647181061Sdes case Readlinkres: { 648181061Sdes char *tmp2; 649181061Sdes if (retval == -1) { 650181061Sdes tmp = strdup(""); 651181061Sdes break; 652181061Sdes } 653181061Sdes tmp2 = get_string(pid, (void*)args[sc->offset], retval); 654181061Sdes asprintf(&tmp, "\"%s\"", tmp2); 655181061Sdes free(tmp2); 656181061Sdes break; 657181061Sdes } 658181061Sdes case Ioctl: { 659181061Sdes const char *temp = ioctlname(args[sc->offset]); 660181061Sdes if (temp) { 661181061Sdes tmp = strdup(temp); 662181061Sdes } else { 663181061Sdes unsigned long arg = args[sc->offset]; 664181061Sdes asprintf(&tmp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }", arg, 665181061Sdes arg&IOC_OUT?"R":"", arg&IOC_IN?"W":"", 666181061Sdes IOCGROUP(arg), isprint(IOCGROUP(arg))?(char)IOCGROUP(arg):'?', 667181061Sdes arg & 0xFF, IOCPARM_LEN(arg)); 668181061Sdes } 669181061Sdes break; 670181061Sdes } 671181061Sdes case Umtx: { 672181061Sdes struct umtx umtx; 673181061Sdes if (get_struct(pid, (void *)args[sc->offset], &umtx, sizeof(umtx)) != -1) 674181061Sdes asprintf(&tmp, "{ 0x%lx }", (long)umtx.u_owner); 675181061Sdes else 676181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 677181061Sdes break; 678181061Sdes } 679181061Sdes case Timespec: { 680181061Sdes struct timespec ts; 681181061Sdes if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts)) != -1) 682181061Sdes asprintf(&tmp, "{%ld.%09ld }", (long)ts.tv_sec, ts.tv_nsec); 683181061Sdes else 684181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 685181061Sdes break; 686181061Sdes } 687181061Sdes case Timeval: { 688181061Sdes struct timeval tv; 689181061Sdes if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) != -1) 690181061Sdes asprintf(&tmp, "{%ld.%06ld }", (long)tv.tv_sec, tv.tv_usec); 691181061Sdes else 692181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 693181061Sdes break; 694181061Sdes } 695181061Sdes case Timeval2: { 696181061Sdes struct timeval tv[2]; 697181061Sdes if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) != -1) 698181061Sdes asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }", 699181061Sdes (long)tv[0].tv_sec, tv[0].tv_usec, 700181061Sdes (long)tv[1].tv_sec, tv[1].tv_usec); 701181061Sdes else 702181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 703181061Sdes break; 704181061Sdes } 705181061Sdes case Itimerval: { 706181061Sdes struct itimerval itv; 707181061Sdes if (get_struct(pid, (void *)args[sc->offset], &itv, sizeof(itv)) != -1) 708181061Sdes asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }", 709181061Sdes (long)itv.it_interval.tv_sec, 710181061Sdes itv.it_interval.tv_usec, 711181061Sdes (long)itv.it_value.tv_sec, 712181061Sdes itv.it_value.tv_usec); 713181061Sdes else 714181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 715181061Sdes break; 716181061Sdes } 717181061Sdes case Pollfd: { 718181061Sdes /* 719181061Sdes * XXX: A Pollfd argument expects the /next/ syscall argument to be 720181061Sdes * the number of fds in the array. This matches the poll syscall. 721181061Sdes */ 722181061Sdes struct pollfd *pfd; 723181061Sdes int numfds = args[sc->offset+1]; 724181061Sdes int bytes = sizeof(struct pollfd) * numfds; 725181061Sdes int i, tmpsize, u, used; 726181061Sdes const int per_fd = 100; 727127332Sdwmalone 728181061Sdes if ((pfd = malloc(bytes)) == NULL) 729181061Sdes err(1, "Cannot malloc %d bytes for pollfd array", bytes); 730181061Sdes if (get_struct(pid, (void *)args[sc->offset], pfd, bytes) != -1) { 731127332Sdwmalone 732181061Sdes used = 0; 733181061Sdes tmpsize = 1 + per_fd * numfds + 2; 734181061Sdes if ((tmp = malloc(tmpsize)) == NULL) 735181061Sdes err(1, "Cannot alloc %d bytes for poll output", tmpsize); 736127332Sdwmalone 737181061Sdes tmp[used++] = '{'; 738181061Sdes for (i = 0; i < numfds; i++) { 739127332Sdwmalone 740181061Sdes u = snprintf(tmp + used, per_fd, 741181061Sdes "%s%d/%s", 742181061Sdes i > 0 ? " " : "", 743181061Sdes pfd[i].fd, 744181061Sdes xlookup_bits(poll_flags, pfd[i].events) ); 745181061Sdes if (u > 0) 746181061Sdes used += u < per_fd ? u : per_fd; 747181061Sdes } 748181061Sdes tmp[used++] = '}'; 749181061Sdes tmp[used++] = '\0'; 750181061Sdes } else { 751181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 752181061Sdes } 753181061Sdes free(pfd); 754181061Sdes break; 755127332Sdwmalone } 756181061Sdes case Fd_set: { 757181061Sdes /* 758181061Sdes * XXX: A Fd_set argument expects the /first/ syscall argument to be 759181061Sdes * the number of fds in the array. This matches the select syscall. 760181061Sdes */ 761181061Sdes fd_set *fds; 762181061Sdes int numfds = args[0]; 763181061Sdes int bytes = _howmany(numfds, _NFDBITS) * _NFDBITS; 764181061Sdes int i, tmpsize, u, used; 765181061Sdes const int per_fd = 20; 766127332Sdwmalone 767181061Sdes if ((fds = malloc(bytes)) == NULL) 768181061Sdes err(1, "Cannot malloc %d bytes for fd_set array", bytes); 769181061Sdes if (get_struct(pid, (void *)args[sc->offset], fds, bytes) != -1) { 770181061Sdes used = 0; 771181061Sdes tmpsize = 1 + numfds * per_fd + 2; 772181061Sdes if ((tmp = malloc(tmpsize)) == NULL) 773181061Sdes err(1, "Cannot alloc %d bytes for fd_set output", tmpsize); 774127332Sdwmalone 775181061Sdes tmp[used++] = '{'; 776181061Sdes for (i = 0; i < numfds; i++) { 777181061Sdes if (FD_ISSET(i, fds)) { 778181061Sdes u = snprintf(tmp + used, per_fd, "%d ", i); 779181061Sdes if (u > 0) 780181061Sdes used += u < per_fd ? u : per_fd; 781181061Sdes } 782181061Sdes } 783181061Sdes if (tmp[used-1] == ' ') 784181061Sdes used--; 785181061Sdes tmp[used++] = '}'; 786181061Sdes tmp[used++] = '\0'; 787181061Sdes } else { 788181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 789181061Sdes } 790181061Sdes free(fds); 791181061Sdes break; 792127332Sdwmalone } 793181061Sdes case Signal: { 794181061Sdes long sig; 79549609Sdes 796181061Sdes sig = args[sc->offset]; 797181061Sdes tmp = strsig(sig); 798181061Sdes if (tmp == NULL) 799181061Sdes asprintf(&tmp, "%ld", sig); 800181061Sdes break; 801181061Sdes } 802181061Sdes case Sigset: { 803181061Sdes long sig; 804181061Sdes sigset_t ss; 805181061Sdes int i, used; 806158630Spav 807181061Sdes sig = args[sc->offset]; 808181061Sdes if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, sizeof(ss)) == -1) { 809181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 810181061Sdes break; 811181061Sdes } 812181061Sdes tmp = malloc(sys_nsig * 8); /* 7 bytes avg per signal name */ 813181061Sdes used = 0; 814181061Sdes for (i = 1; i < sys_nsig; i++) { 815181061Sdes if (sigismember(&ss, i)) { 816181061Sdes used += sprintf(tmp + used, "%s|", strsig(i)); 817181061Sdes } 818181061Sdes } 819181061Sdes if (used) 820181061Sdes tmp[used-1] = 0; 821181061Sdes else 822181061Sdes strcpy(tmp, "0x0"); 823181061Sdes break; 824181061Sdes } 825181061Sdes case Sigprocmask: { 826181061Sdes switch (args[sc->offset]) { 827127328Salfred#define S(a) case a: tmp = strdup(#a); break; 828181061Sdes S(SIG_BLOCK); 829181061Sdes S(SIG_UNBLOCK); 830181061Sdes S(SIG_SETMASK); 831127328Salfred#undef S 832181061Sdes } 833181061Sdes if (tmp == NULL) 834181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 835181061Sdes break; 836127328Salfred } 837181061Sdes case Fcntlflag: { 838181061Sdes /* XXX output depends on the value of the previous argument */ 839181061Sdes switch (args[sc->offset-1]) { 840181061Sdes case F_SETFD: 841181061Sdes tmp = strdup(xlookup_bits(fcntlfd_arg, args[sc->offset])); 842181061Sdes break; 843181061Sdes case F_SETFL: 844181061Sdes tmp = strdup(xlookup_bits(fcntlfl_arg, args[sc->offset])); 845181061Sdes break; 846181061Sdes case F_GETFD: 847181061Sdes case F_GETFL: 848181061Sdes case F_GETOWN: 849181061Sdes tmp = strdup(""); 850181061Sdes break; 851181061Sdes default: 852181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 853181061Sdes break; 854181061Sdes } 855181061Sdes break; 856181061Sdes } 857181061Sdes case Open: 858181061Sdes tmp = strdup(xlookup_bits(open_flags, args[sc->offset])); 859181061Sdes break; 860181061Sdes case Fcntl: 861181061Sdes tmp = strdup(xlookup(fcntl_arg, args[sc->offset])); 862181061Sdes break; 863181061Sdes case Mprot: 864181061Sdes tmp = strdup(xlookup_bits(mprot_flags, args[sc->offset])); 865181061Sdes break; 866181061Sdes case Mmapflags: 867181061Sdes tmp = strdup(xlookup_bits(mmap_flags, args[sc->offset])); 868181061Sdes break; 869181061Sdes case Whence: 870181061Sdes tmp = strdup(xlookup(whence_arg, args[sc->offset])); 871181061Sdes break; 872181061Sdes case Sockdomain: 873181061Sdes tmp = strdup(xlookup(sockdomain_arg, args[sc->offset])); 874181061Sdes break; 875181061Sdes case Socktype: 876181061Sdes tmp = strdup(xlookup(socktype_arg, args[sc->offset])); 877181061Sdes break; 878181061Sdes case Shutdown: 879181061Sdes tmp = strdup(xlookup(shutdown_arg, args[sc->offset])); 880181061Sdes break; 881181061Sdes case Resource: 882181061Sdes tmp = strdup(xlookup(resource_arg, args[sc->offset])); 883181061Sdes break; 884181061Sdes case Pathconf: 885181061Sdes tmp = strdup(xlookup(pathconf_arg, args[sc->offset])); 886181061Sdes break; 887181061Sdes case Sockaddr: { 888181061Sdes struct sockaddr_storage ss; 889181061Sdes char addr[64]; 890181061Sdes struct sockaddr_in *lsin; 891181061Sdes struct sockaddr_in6 *lsin6; 892181061Sdes struct sockaddr_un *sun; 893181061Sdes struct sockaddr *sa; 894181061Sdes char *p; 895181061Sdes u_char *q; 896181061Sdes int i; 89785292Sdes 898181061Sdes if (args[sc->offset] == 0) { 899181061Sdes asprintf(&tmp, "NULL"); 900181061Sdes break; 901181061Sdes } 902121606Smarcel 903181061Sdes /* yuck: get ss_len */ 904181061Sdes if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, 905181061Sdes sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1) 906181061Sdes err(1, "get_struct %p", (void *)args[sc->offset]); 907181061Sdes /* 908181061Sdes * If ss_len is 0, then try to guess from the sockaddr type. 909181061Sdes * AF_UNIX may be initialized incorrectly, so always frob 910181061Sdes * it by using the "right" size. 911181061Sdes */ 912181061Sdes if (ss.ss_len == 0 || ss.ss_family == AF_UNIX) { 913181061Sdes switch (ss.ss_family) { 914181061Sdes case AF_INET: 915181061Sdes ss.ss_len = sizeof(*lsin); 916181061Sdes break; 917181061Sdes case AF_UNIX: 918181061Sdes ss.ss_len = sizeof(*sun); 919181061Sdes break; 920181061Sdes default: 921181061Sdes /* hurrrr */ 922181061Sdes break; 923181061Sdes } 924181061Sdes } 925181061Sdes if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, ss.ss_len) 926181061Sdes == -1) { 927181061Sdes err(2, "get_struct %p", (void *)args[sc->offset]); 928181061Sdes } 92985292Sdes 930181061Sdes switch (ss.ss_family) { 931181061Sdes case AF_INET: 932181061Sdes lsin = (struct sockaddr_in *)&ss; 933181061Sdes inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof addr); 934181061Sdes asprintf(&tmp, "{ AF_INET %s:%d }", addr, htons(lsin->sin_port)); 935181061Sdes break; 936181061Sdes case AF_INET6: 937181061Sdes lsin6 = (struct sockaddr_in6 *)&ss; 938181061Sdes inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, sizeof addr); 939181061Sdes asprintf(&tmp, "{ AF_INET6 [%s]:%d }", addr, htons(lsin6->sin6_port)); 940181061Sdes break; 941181061Sdes case AF_UNIX: 942181061Sdes sun = (struct sockaddr_un *)&ss; 943181061Sdes asprintf(&tmp, "{ AF_UNIX \"%s\" }", sun->sun_path); 944181061Sdes break; 945181061Sdes default: 946181061Sdes sa = (struct sockaddr *)&ss; 947181061Sdes asprintf(&tmp, "{ sa_len = %d, sa_family = %d, sa_data = {%n%*s } }", 948181061Sdes (int)sa->sa_len, (int)sa->sa_family, &i, 949181061Sdes 6 * (int)(sa->sa_len - ((char *)&sa->sa_data - (char *)sa)), ""); 950181061Sdes if (tmp != NULL) { 951181061Sdes p = tmp + i; 952181061Sdes for (q = (u_char *)&sa->sa_data; q < (u_char *)sa + sa->sa_len; q++) 953181061Sdes p += sprintf(p, " %#02x,", *q); 954181061Sdes } 955181061Sdes } 956181061Sdes break; 95786138Sgreen } 958181061Sdes case Sigaction: { 959181061Sdes struct sigaction sa; 960181061Sdes char *hand; 961181061Sdes const char *h; 962127332Sdwmalone 963181061Sdes if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa)) != -1) { 964127332Sdwmalone 965181061Sdes asprintf(&hand, "%p", sa.sa_handler); 966181061Sdes if (sa.sa_handler == SIG_DFL) 967181061Sdes h = "SIG_DFL"; 968181061Sdes else if (sa.sa_handler == SIG_IGN) 969181061Sdes h = "SIG_IGN"; 970181061Sdes else 971181061Sdes h = hand; 972158630Spav 973181061Sdes asprintf(&tmp, "{ %s %s ss_t }", 974181061Sdes h, 975181061Sdes xlookup_bits(sigaction_flags, sa.sa_flags)); 976181061Sdes free(hand); 977181061Sdes } else { 978181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 979181061Sdes } 980181061Sdes break; 981181061Sdes } 982181061Sdes case Kevent: { 983181061Sdes /* 984181061Sdes * XXX XXX: the size of the array is determined by either the 985181061Sdes * next syscall argument, or by the syscall returnvalue, 986181061Sdes * depending on which argument number we are. This matches the 987181061Sdes * kevent syscall, but luckily that's the only syscall that uses 988181061Sdes * them. 989181061Sdes */ 990181061Sdes struct kevent *ke; 991181061Sdes int numevents = -1; 992181061Sdes int bytes = 0; 993181061Sdes int i, tmpsize, u, used; 994181061Sdes const int per_ke = 100; 995158630Spav 996181061Sdes if (sc->offset == 1) 997181061Sdes numevents = args[sc->offset+1]; 998181061Sdes else if (sc->offset == 3 && retval != -1) 999181061Sdes numevents = retval; 1000158630Spav 1001181061Sdes if (numevents >= 0) 1002181061Sdes bytes = sizeof(struct kevent) * numevents; 1003181061Sdes if ((ke = malloc(bytes)) == NULL) 1004181061Sdes err(1, "Cannot malloc %d bytes for kevent array", bytes); 1005181061Sdes if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset], ke, bytes) != -1) { 1006181061Sdes used = 0; 1007181061Sdes tmpsize = 1 + per_ke * numevents + 2; 1008181061Sdes if ((tmp = malloc(tmpsize)) == NULL) 1009181061Sdes err(1, "Cannot alloc %d bytes for kevent output", tmpsize); 1010158630Spav 1011181061Sdes tmp[used++] = '{'; 1012181061Sdes for (i = 0; i < numevents; i++) { 1013181061Sdes u = snprintf(tmp + used, per_ke, 1014181061Sdes "%s%p,%s,%s,%d,%p,%p", 1015181061Sdes i > 0 ? " " : "", 1016181061Sdes (void *)ke[i].ident, 1017181061Sdes xlookup(kevent_filters, ke[i].filter), 1018181061Sdes xlookup_bits(kevent_flags, ke[i].flags), 1019181061Sdes ke[i].fflags, 1020181061Sdes (void *)ke[i].data, 1021181061Sdes (void *)ke[i].udata); 1022181061Sdes if (u > 0) 1023181061Sdes used += u < per_ke ? u : per_ke; 1024181061Sdes } 1025181061Sdes tmp[used++] = '}'; 1026181061Sdes tmp[used++] = '\0'; 1027181061Sdes } else { 1028181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 1029181061Sdes } 1030181061Sdes free(ke); 1031181061Sdes break; 1032158630Spav } 1033181061Sdes case Stat: { 1034181061Sdes struct stat st; 1035181061Sdes if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st)) != -1) { 1036181061Sdes char mode[12]; 1037181061Sdes strmode(st.st_mode, mode); 1038181061Sdes asprintf(&tmp, "{ mode=%s,inode=%jd,size=%jd,blksize=%ld }", 1039181061Sdes mode, 1040181061Sdes (intmax_t)st.st_ino,(intmax_t)st.st_size,(long)st.st_blksize); 1041181061Sdes } else { 1042181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 1043181061Sdes } 1044181061Sdes break; 1045181061Sdes } 1046181061Sdes case Rusage: { 1047181061Sdes struct rusage ru; 1048181061Sdes if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru)) != -1) { 1049181061Sdes asprintf(&tmp, "{ u=%ld.%06ld,s=%ld.%06ld,in=%ld,out=%ld }", 1050181061Sdes (long)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec, 1051181061Sdes (long)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec, 1052181061Sdes ru.ru_inblock, ru.ru_oublock); 1053181061Sdes } else { 1054181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 1055181061Sdes } 1056181061Sdes break; 1057181061Sdes } 1058181061Sdes case Rlimit: { 1059181061Sdes struct rlimit rl; 1060181061Sdes if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl)) != -1) { 1061181061Sdes asprintf(&tmp, "{ cur=%ju,max=%ju }", 1062181061Sdes rl.rlim_cur, rl.rlim_max); 1063181061Sdes } else { 1064181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 1065181061Sdes } 1066181061Sdes break; 1067181061Sdes } 1068181061Sdes default: 1069181061Sdes errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK); 1070181061Sdes } 1071181061Sdes return (tmp); 107231567Ssef} 107331567Ssef 107431567Ssef/* 107531567Ssef * print_syscall 107631567Ssef * Print (to outfile) the system call and its arguments. Note that 107731567Ssef * nargs is the number of arguments (not the number of words; this is 107831567Ssef * potentially confusing, I know). 107931567Ssef */ 108031567Ssef 108131567Ssefvoid 1082181061Sdesprint_syscall(struct trussinfo *trussinfo, const char *name, int nargs, char **s_args) 1083181061Sdes{ 1084181061Sdes int i; 1085181061Sdes int len = 0; 1086181061Sdes struct timespec timediff; 1087101283Smdodd 1088181061Sdes if (trussinfo->flags & FOLLOWFORKS) 1089181061Sdes len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid); 1090101283Smdodd 1091181061Sdes if (name != NULL && (!strcmp(name, "execve") || !strcmp(name, "exit"))) { 1092181061Sdes clock_gettime(CLOCK_REALTIME, &trussinfo->after); 1093181061Sdes } 1094101285Smdodd 1095181061Sdes if (trussinfo->flags & ABSOLUTETIMESTAMPS) { 1096181061Sdes timespecsubt(&trussinfo->after, &trussinfo->start_time, &timediff); 1097181061Sdes len += fprintf(trussinfo->outfile, "%ld.%09ld ", 1098181061Sdes (long)timediff.tv_sec, timediff.tv_nsec); 1099181061Sdes } 1100101285Smdodd 1101181061Sdes if (trussinfo->flags & RELATIVETIMESTAMPS) { 1102181061Sdes timespecsubt(&trussinfo->after, &trussinfo->before, &timediff); 1103181061Sdes len += fprintf(trussinfo->outfile, "%ld.%09ld ", 1104181061Sdes (long)timediff.tv_sec, timediff.tv_nsec); 1105181061Sdes } 1106101285Smdodd 1107181061Sdes len += fprintf(trussinfo->outfile, "%s(", name); 1108101283Smdodd 1109181061Sdes for (i = 0; i < nargs; i++) { 1110181061Sdes if (s_args[i]) 1111181061Sdes len += fprintf(trussinfo->outfile, "%s", s_args[i]); 1112181061Sdes else 1113181061Sdes len += fprintf(trussinfo->outfile, "<missing argument>"); 1114181061Sdes len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? "," : ""); 1115181061Sdes } 1116181061Sdes len += fprintf(trussinfo->outfile, ")"); 1117181061Sdes for (i = 0; i < 6 - (len / 8); i++) 1118181061Sdes fprintf(trussinfo->outfile, "\t"); 111931567Ssef} 112058224Ssef 112158224Ssefvoid 1122122348Smarcelprint_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs, 1123192025Sdds char **s_args, int errorp, long retval, struct syscall *sc) 1124122348Smarcel{ 1125192025Sdds struct timespec timediff; 1126181061Sdes 1127192025Sdds if (trussinfo->flags & COUNTONLY) { 1128192025Sdds if (!sc) 1129192025Sdds return; 1130192025Sdds clock_gettime(CLOCK_REALTIME, &trussinfo->after); 1131192025Sdds timespecsubt(&trussinfo->after, &trussinfo->before, &timediff); 1132192025Sdds timespecadd(&sc->time, &timediff, &sc->time); 1133192025Sdds sc->ncalls++; 1134192025Sdds if (errorp) 1135192025Sdds sc->nerror++; 1136192025Sdds return; 1137192025Sdds } 1138192025Sdds 1139181061Sdes print_syscall(trussinfo, name, nargs, s_args); 1140181061Sdes fflush(trussinfo->outfile); 1141181061Sdes if (errorp) { 1142181061Sdes fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval, strerror(retval)); 1143181061Sdes } else { 1144200780Sjh /* 1145200780Sjh * Because pipe(2) has a special assembly glue to provide the 1146200780Sjh * libc API, we have to adjust retval. 1147200780Sjh */ 1148200780Sjh if (name != NULL && !strcmp(name, "pipe")) 1149200780Sjh retval = 0; 1150181061Sdes fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval, retval); 1151181061Sdes } 115258224Ssef} 1153192025Sdds 1154192025Sddsvoid 1155192025Sddsprint_summary(struct trussinfo *trussinfo) 1156192025Sdds{ 1157192025Sdds struct syscall *sc; 1158192025Sdds struct timespec total = {0, 0}; 1159192025Sdds int ncall, nerror; 1160192025Sdds 1161192025Sdds fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n", 1162192025Sdds "syscall", "seconds", "calls", "errors"); 1163192025Sdds ncall = nerror = 0; 1164192025Sdds for (sc = syscalls; sc->name != NULL; sc++) 1165192025Sdds if (sc->ncalls) { 1166200781Sjh fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 1167200781Sjh sc->name, (intmax_t)sc->time.tv_sec, 1168200781Sjh sc->time.tv_nsec, sc->ncalls, sc->nerror); 1169192025Sdds timespecadd(&total, &sc->time, &total); 1170192025Sdds ncall += sc->ncalls; 1171192025Sdds nerror += sc->nerror; 1172192025Sdds } 1173192025Sdds fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n", 1174192025Sdds "", "-------------", "-------", "-------"); 1175200781Sjh fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 1176200781Sjh "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror); 1177192025Sdds} 1178