syscalls.c revision 253850
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 253850 2013-08-01 02:57:04Z markj $"; 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 }, 96253850Smarkj { .name = "vfork", .ret_type = 1, .nargs = 0 }, 97253850Smarkj { .name = "rfork", .ret_type = 1, .nargs = 1, 98253850Smarkj .args = { { Rforkflags, 0 } } }, 99200751Sjh { .name = "getegid", .ret_type = 1, .nargs = 0 }, 100200751Sjh { .name = "geteuid", .ret_type = 1, .nargs = 0 }, 101200751Sjh { .name = "getgid", .ret_type = 1, .nargs = 0 }, 102200751Sjh { .name = "getpid", .ret_type = 1, .nargs = 0 }, 103200751Sjh { .name = "getpgid", .ret_type = 1, .nargs = 1, 104200751Sjh .args = { { Int, 0 } } }, 105200751Sjh { .name = "getpgrp", .ret_type = 1, .nargs = 0 }, 106200751Sjh { .name = "getppid", .ret_type = 1, .nargs = 0 }, 107200751Sjh { .name = "getsid", .ret_type = 1, .nargs = 1, 108200751Sjh .args = { { Int, 0 } } }, 109200751Sjh { .name = "getuid", .ret_type = 1, .nargs = 0 }, 110192025Sdds { .name = "readlink", .ret_type = 1, .nargs = 3, 111192025Sdds .args = { { Name, 0 } , { Readlinkres | OUT, 1 }, { Int, 2 } } }, 112192025Sdds { .name = "lseek", .ret_type = 2, .nargs = 3, 113192025Sdds .args = { { Int, 0 }, { Quad, 1 + QUAD_ALIGN }, { Whence, 1 + QUAD_SLOTS + QUAD_ALIGN } } }, 114192025Sdds { .name = "linux_lseek", .ret_type = 2, .nargs = 3, 115192025Sdds .args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } }, 116192025Sdds { .name = "mmap", .ret_type = 2, .nargs = 6, 117192025Sdds .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 }, { Mmapflags, 3 }, { Int, 4 }, { Quad, 5 + QUAD_ALIGN } } }, 118192025Sdds { .name = "mprotect", .ret_type = 1, .nargs = 3, 119192025Sdds .args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 } } }, 120192025Sdds { .name = "open", .ret_type = 1, .nargs = 3, 121192025Sdds .args = { { Name | IN, 0 } , { Open, 1 }, { Octal, 2 } } }, 122192025Sdds { .name = "mkdir", .ret_type = 1, .nargs = 2, 123192025Sdds .args = { { Name, 0 } , { Octal, 1 } } }, 124192025Sdds { .name = "linux_open", .ret_type = 1, .nargs = 3, 125192025Sdds .args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } }, 126192025Sdds { .name = "close", .ret_type = 1, .nargs = 1, 127192025Sdds .args = { { Int, 0 } } }, 128192025Sdds { .name = "link", .ret_type = 0, .nargs = 2, 129192025Sdds .args = { { Name, 0 }, { Name, 1 } } }, 130192025Sdds { .name = "unlink", .ret_type = 0, .nargs = 1, 131192025Sdds .args = { { Name, 0 } } }, 132192025Sdds { .name = "chdir", .ret_type = 0, .nargs = 1, 133192025Sdds .args = { { Name, 0 } } }, 134192025Sdds { .name = "chroot", .ret_type = 0, .nargs = 1, 135192025Sdds .args = { { Name, 0 } } }, 136192025Sdds { .name = "mknod", .ret_type = 0, .nargs = 3, 137192025Sdds .args = { { Name, 0 }, { Octal, 1 }, { Int, 3 } } }, 138192025Sdds { .name = "chmod", .ret_type = 0, .nargs = 2, 139192025Sdds .args = { { Name, 0 }, { Octal, 1 } } }, 140192025Sdds { .name = "chown", .ret_type = 0, .nargs = 3, 141192025Sdds .args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } }, 142192025Sdds { .name = "mount", .ret_type = 0, .nargs = 4, 143192025Sdds .args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } }, 144192025Sdds { .name = "umount", .ret_type = 0, .nargs = 2, 145192025Sdds .args = { { Name, 0 }, { Int, 2 } } }, 146192025Sdds { .name = "fstat", .ret_type = 1, .nargs = 2, 147192025Sdds .args = { { Int, 0 }, { Stat | OUT , 1 } } }, 148192025Sdds { .name = "stat", .ret_type = 1, .nargs = 2, 149192025Sdds .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } }, 150192025Sdds { .name = "lstat", .ret_type = 1, .nargs = 2, 151192025Sdds .args = { { Name | IN, 0 }, { Stat | OUT, 1 } } }, 152192025Sdds { .name = "linux_newstat", .ret_type = 1, .nargs = 2, 153192025Sdds .args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } }, 154192025Sdds { .name = "linux_newfstat", .ret_type = 1, .nargs = 2, 155192025Sdds .args = { { Int, 0 }, { Ptr | OUT, 1 } } }, 156192025Sdds { .name = "write", .ret_type = 1, .nargs = 3, 157192025Sdds .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 } } }, 158192025Sdds { .name = "ioctl", .ret_type = 1, .nargs = 3, 159192025Sdds .args = { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 } } }, 160192025Sdds { .name = "break", .ret_type = 1, .nargs = 1, 161192025Sdds .args = { { Ptr, 0 } } }, 162192025Sdds { .name = "exit", .ret_type = 0, .nargs = 1, 163192025Sdds .args = { { Hex, 0 } } }, 164192025Sdds { .name = "access", .ret_type = 1, .nargs = 2, 165192025Sdds .args = { { Name | IN, 0 }, { Int, 1 } } }, 166192025Sdds { .name = "sigaction", .ret_type = 1, .nargs = 3, 167192025Sdds .args = { { Signal, 0 }, { Sigaction | IN, 1 }, { Sigaction | OUT, 2 } } }, 168192025Sdds { .name = "accept", .ret_type = 1, .nargs = 3, 169192025Sdds .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 170192025Sdds { .name = "bind", .ret_type = 1, .nargs = 3, 171192025Sdds .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, 172192025Sdds { .name = "connect", .ret_type = 1, .nargs = 3, 173192025Sdds .args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, 174192025Sdds { .name = "getpeername", .ret_type = 1, .nargs = 3, 175192025Sdds .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 176192025Sdds { .name = "getsockname", .ret_type = 1, .nargs = 3, 177192025Sdds .args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 178192025Sdds { .name = "recvfrom", .ret_type = 1, .nargs = 6, 179192025Sdds .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } }, 180192025Sdds { .name = "sendto", .ret_type = 1, .nargs = 6, 181192025Sdds .args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } }, 182192025Sdds { .name = "execve", .ret_type = 1, .nargs = 3, 183192025Sdds .args = { { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } }, 184192025Sdds { .name = "linux_execve", .ret_type = 1, .nargs = 3, 185192025Sdds .args = { { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } }, 186192025Sdds { .name = "kldload", .ret_type = 0, .nargs = 1, 187192025Sdds .args = { { Name | IN, 0 } } }, 188192025Sdds { .name = "kldunload", .ret_type = 0, .nargs = 1, 189192025Sdds .args = { { Int, 0 } } }, 190192025Sdds { .name = "kldfind", .ret_type = 0, .nargs = 1, 191192025Sdds .args = { { Name | IN, 0 } } }, 192192025Sdds { .name = "kldnext", .ret_type = 0, .nargs = 1, 193192025Sdds .args = { { Int, 0 } } }, 194192025Sdds { .name = "kldstat", .ret_type = 0, .nargs = 2, 195192025Sdds .args = { { Int, 0 }, { Ptr, 1 } } }, 196192025Sdds { .name = "kldfirstmod", .ret_type = 0, .nargs = 1, 197192025Sdds .args = { { Int, 0 } } }, 198192025Sdds { .name = "nanosleep", .ret_type = 0, .nargs = 1, 199192025Sdds .args = { { Timespec, 0 } } }, 200192025Sdds { .name = "select", .ret_type = 1, .nargs = 5, 201192025Sdds .args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, { Timeval, 4 } } }, 202192025Sdds { .name = "poll", .ret_type = 1, .nargs = 3, 203192025Sdds .args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } }, 204192025Sdds { .name = "gettimeofday", .ret_type = 1, .nargs = 2, 205192025Sdds .args = { { Timeval | OUT, 0 }, { Ptr, 1 } } }, 206192025Sdds { .name = "clock_gettime", .ret_type = 1, .nargs = 2, 207192025Sdds .args = { { Int, 0 }, { Timespec | OUT, 1 } } }, 208192025Sdds { .name = "getitimer", .ret_type = 1, .nargs = 2, 209192025Sdds .args = { { Int, 0 }, { Itimerval | OUT, 2 } } }, 210192025Sdds { .name = "setitimer", .ret_type = 1, .nargs = 3, 211192025Sdds .args = { { Int, 0 }, { Itimerval, 1 } , { Itimerval | OUT, 2 } } }, 212192025Sdds { .name = "kse_release", .ret_type = 0, .nargs = 1, 213192025Sdds .args = { { Timespec, 0 } } }, 214192025Sdds { .name = "kevent", .ret_type = 0, .nargs = 6, 215192025Sdds .args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 }, { Int, 4 }, { Timespec, 5 } } }, 216192025Sdds { .name = "_umtx_lock", .ret_type = 0, .nargs = 1, 217192025Sdds .args = { { Umtx, 0 } } }, 218192025Sdds { .name = "_umtx_unlock", .ret_type = 0, .nargs = 1, 219192025Sdds .args = { { Umtx, 0 } } }, 220192025Sdds { .name = "sigprocmask", .ret_type = 0, .nargs = 3, 221192025Sdds .args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } }, 222192025Sdds { .name = "unmount", .ret_type = 1, .nargs = 2, 223192025Sdds .args = { { Name, 0 }, { Int, 1 } } }, 224192025Sdds { .name = "socket", .ret_type = 1, .nargs = 3, 225192025Sdds .args = { { Sockdomain, 0 }, { Socktype, 1 }, { Int, 2 } } }, 226192025Sdds { .name = "getrusage", .ret_type = 1, .nargs = 2, 227192025Sdds .args = { { Int, 0 }, { Rusage | OUT, 1 } } }, 228192025Sdds { .name = "__getcwd", .ret_type = 1, .nargs = 2, 229192025Sdds .args = { { Name | OUT, 0 }, { Int, 1 } } }, 230192025Sdds { .name = "shutdown", .ret_type = 1, .nargs = 2, 231192025Sdds .args = { { Int, 0 }, { Shutdown, 1 } } }, 232192025Sdds { .name = "getrlimit", .ret_type = 1, .nargs = 2, 233192025Sdds .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } }, 234192025Sdds { .name = "setrlimit", .ret_type = 1, .nargs = 2, 235192025Sdds .args = { { Resource, 0 }, { Rlimit | IN, 1 } } }, 236192025Sdds { .name = "utimes", .ret_type = 1, .nargs = 2, 237192025Sdds .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } }, 238192025Sdds { .name = "lutimes", .ret_type = 1, .nargs = 2, 239192025Sdds .args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } }, 240192025Sdds { .name = "futimes", .ret_type = 1, .nargs = 2, 241192025Sdds .args = { { Int, 0 }, { Timeval | IN, 1 } } }, 242192025Sdds { .name = "chflags", .ret_type = 1, .nargs = 2, 243192025Sdds .args = { { Name | IN, 0 }, { Hex, 1 } } }, 244192025Sdds { .name = "lchflags", .ret_type = 1, .nargs = 2, 245192025Sdds .args = { { Name | IN, 0 }, { Hex, 1 } } }, 246192025Sdds { .name = "pathconf", .ret_type = 1, .nargs = 2, 247192025Sdds .args = { { Name | IN, 0 }, { Pathconf, 1 } } }, 248200780Sjh { .name = "pipe", .ret_type = 1, .nargs = 1, 249200780Sjh .args = { { Ptr, 0 } } }, 250192025Sdds { .name = "truncate", .ret_type = 1, .nargs = 3, 251192025Sdds .args = { { Name | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 } } }, 252192025Sdds { .name = "ftruncate", .ret_type = 1, .nargs = 3, 253192025Sdds .args = { { Int | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 } } }, 254192025Sdds { .name = "kill", .ret_type = 1, .nargs = 2, 255192025Sdds .args = { { Int | IN, 0 }, { Signal | IN, 1 } } }, 256192025Sdds { .name = "munmap", .ret_type = 1, .nargs = 2, 257192025Sdds .args = { { Ptr, 0 }, { Int, 1 } } }, 258192025Sdds { .name = "read", .ret_type = 1, .nargs = 3, 259192025Sdds .args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 } } }, 260192025Sdds { .name = "rename", .ret_type = 1, .nargs = 2, 261192025Sdds .args = { { Name , 0 } , { Name, 1 } } }, 262192025Sdds { .name = "symlink", .ret_type = 1, .nargs = 2, 263192025Sdds .args = { { Name , 0 } , { Name, 1 } } }, 264200902Sed { .name = "posix_openpt", .ret_type = 1, .nargs = 1, 265200902Sed .args = { { Open, 0 } } }, 266192025Sdds { .name = 0 }, 26731567Ssef}; 26831567Ssef 269158630Spav/* Xlat idea taken from strace */ 270158630Spavstruct xlat { 271158630Spav int val; 272168569Sdelphij const char *str; 273158630Spav}; 274158630Spav 275240005Szont#define X(a) { a, #a }, 276240005Szont#define XEND { 0, NULL } 277158630Spav 278158630Spavstatic struct xlat kevent_filters[] = { 279158630Spav X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE) 280158630Spav X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER) 281201350Sbrooks X(EVFILT_FS) X(EVFILT_READ) XEND 282158630Spav}; 283158630Spav 284158630Spavstatic struct xlat kevent_flags[] = { 285158630Spav X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT) 286158630Spav X(EV_CLEAR) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND 287158630Spav}; 288158630Spav 289228396Sedstatic struct xlat poll_flags[] = { 290158630Spav X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR) 291158630Spav X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND) 292158630Spav X(POLLWRBAND) X(POLLINIGNEOF) XEND 293158630Spav}; 294158630Spav 295158630Spavstatic struct xlat mmap_flags[] = { 296158630Spav X(MAP_SHARED) X(MAP_PRIVATE) X(MAP_FIXED) X(MAP_RENAME) 297158630Spav X(MAP_NORESERVE) X(MAP_RESERVED0080) X(MAP_RESERVED0100) 298158630Spav X(MAP_HASSEMAPHORE) X(MAP_STACK) X(MAP_NOSYNC) X(MAP_ANON) 299158630Spav X(MAP_NOCORE) XEND 300158630Spav}; 301158630Spav 302158630Spavstatic struct xlat mprot_flags[] = { 303158630Spav X(PROT_NONE) X(PROT_READ) X(PROT_WRITE) X(PROT_EXEC) XEND 304158630Spav}; 305158630Spav 306158630Spavstatic struct xlat whence_arg[] = { 307158630Spav X(SEEK_SET) X(SEEK_CUR) X(SEEK_END) XEND 308158630Spav}; 309158630Spav 310158630Spavstatic struct xlat sigaction_flags[] = { 311158630Spav X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP) 312158630Spav X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND 313158630Spav}; 314158630Spav 315158630Spavstatic struct xlat fcntl_arg[] = { 316158630Spav X(F_DUPFD) X(F_GETFD) X(F_SETFD) X(F_GETFL) X(F_SETFL) 317158630Spav X(F_GETOWN) X(F_SETOWN) X(F_GETLK) X(F_SETLK) X(F_SETLKW) XEND 318158630Spav}; 319158630Spav 320158630Spavstatic struct xlat fcntlfd_arg[] = { 321158630Spav X(FD_CLOEXEC) XEND 322158630Spav}; 323158630Spav 324158630Spavstatic struct xlat fcntlfl_arg[] = { 325158630Spav X(O_APPEND) X(O_ASYNC) X(O_FSYNC) X(O_NONBLOCK) X(O_NOFOLLOW) 326158630Spav X(O_DIRECT) XEND 327158630Spav}; 328158630Spav 329158630Spavstatic struct xlat sockdomain_arg[] = { 330158630Spav X(PF_UNSPEC) X(PF_LOCAL) X(PF_UNIX) X(PF_INET) X(PF_IMPLINK) 331158630Spav X(PF_PUP) X(PF_CHAOS) X(PF_NETBIOS) X(PF_ISO) X(PF_OSI) 332158630Spav X(PF_ECMA) X(PF_DATAKIT) X(PF_CCITT) X(PF_SNA) X(PF_DECnet) 333158630Spav X(PF_DLI) X(PF_LAT) X(PF_HYLINK) X(PF_APPLETALK) X(PF_ROUTE) 334158630Spav X(PF_LINK) X(PF_XTP) X(PF_COIP) X(PF_CNT) X(PF_SIP) X(PF_IPX) 335158630Spav X(PF_RTIP) X(PF_PIP) X(PF_ISDN) X(PF_KEY) X(PF_INET6) 336158630Spav X(PF_NATM) X(PF_ATM) X(PF_NETGRAPH) X(PF_SLOW) X(PF_SCLUSTER) 337158630Spav X(PF_ARP) X(PF_BLUETOOTH) XEND 338158630Spav}; 339158630Spav 340158630Spavstatic struct xlat socktype_arg[] = { 341158630Spav X(SOCK_STREAM) X(SOCK_DGRAM) X(SOCK_RAW) X(SOCK_RDM) 342158630Spav X(SOCK_SEQPACKET) XEND 343158630Spav}; 344158630Spav 345158630Spavstatic struct xlat open_flags[] = { 346158630Spav X(O_RDONLY) X(O_WRONLY) X(O_RDWR) X(O_ACCMODE) X(O_NONBLOCK) 347158630Spav X(O_APPEND) X(O_SHLOCK) X(O_EXLOCK) X(O_ASYNC) X(O_FSYNC) 348158630Spav X(O_NOFOLLOW) X(O_CREAT) X(O_TRUNC) X(O_EXCL) X(O_NOCTTY) 349252414Smjg X(O_DIRECT) X(O_DIRECTORY) X(O_EXEC) X(O_TTY_INIT) X(O_CLOEXEC) XEND 350158630Spav}; 351158630Spav 352158630Spavstatic struct xlat shutdown_arg[] = { 353158630Spav X(SHUT_RD) X(SHUT_WR) X(SHUT_RDWR) XEND 354158630Spav}; 355158630Spav 356158630Spavstatic struct xlat resource_arg[] = { 357158630Spav X(RLIMIT_CPU) X(RLIMIT_FSIZE) X(RLIMIT_DATA) X(RLIMIT_STACK) 358158630Spav X(RLIMIT_CORE) X(RLIMIT_RSS) X(RLIMIT_MEMLOCK) X(RLIMIT_NPROC) 359158630Spav X(RLIMIT_NOFILE) X(RLIMIT_SBSIZE) X(RLIMIT_VMEM) XEND 360158630Spav}; 361158630Spav 362158630Spavstatic struct xlat pathconf_arg[] = { 363158630Spav X(_PC_LINK_MAX) X(_PC_MAX_CANON) X(_PC_MAX_INPUT) 364158630Spav X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF) 365158630Spav X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE) 366158630Spav X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO) 367158630Spav X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS) 368158630Spav X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE) 369158630Spav X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN) 370158630Spav X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX) 371158630Spav X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT) 372158630Spav XEND 373158630Spav}; 374158630Spav 375253850Smarkjstatic struct xlat rfork_flags[] = { 376253850Smarkj X(RFPROC) X(RFNOWAIT) X(RFFDG) X(RFCFDG) X(RFTHREAD) X(RFMEM) 377253850Smarkj X(RFSIGSHARE) X(RFTSIGZMB) X(RFLINUXTHPN) XEND 378253850Smarkj}; 379253850Smarkj 380158630Spav#undef X 381158630Spav#undef XEND 382158630Spav 383181061Sdes/* 384181061Sdes * Searches an xlat array for a value, and returns it if found. Otherwise 385181061Sdes * return a string representation. 386181061Sdes */ 387181061Sdesstatic const char * 388181061Sdeslookup(struct xlat *xlat, int val, int base) 389158630Spav{ 390158630Spav static char tmp[16]; 391181061Sdes 392158630Spav for (; xlat->str != NULL; xlat++) 393158630Spav if (xlat->val == val) 394181061Sdes return (xlat->str); 395158630Spav switch (base) { 396158630Spav case 8: 397158630Spav sprintf(tmp, "0%o", val); 398158630Spav break; 399158630Spav case 16: 400158630Spav sprintf(tmp, "0x%x", val); 401158630Spav break; 402158630Spav case 10: 403158630Spav sprintf(tmp, "%u", val); 404158630Spav break; 405158630Spav default: 406158630Spav errx(1,"Unknown lookup base"); 407158630Spav break; 408158630Spav } 409181061Sdes return (tmp); 410158630Spav} 411158630Spav 412168569Sdelphijstatic const char * 413168569Sdelphijxlookup(struct xlat *xlat, int val) 414158630Spav{ 415181061Sdes 416181061Sdes return (lookup(xlat, val, 16)); 417158630Spav} 418158630Spav 419158630Spav/* Searches an xlat array containing bitfield values. Remaining bits 420158630Spav set after removing the known ones are printed at the end: 421158630Spav IN|0x400 */ 422181061Sdesstatic char * 423181061Sdesxlookup_bits(struct xlat *xlat, int val) 424158630Spav{ 425240005Szont int len, rem; 426158630Spav static char str[512]; 427158630Spav 428240005Szont len = 0; 429240005Szont rem = val; 430181061Sdes for (; xlat->str != NULL; xlat++) { 431181061Sdes if ((xlat->val & rem) == xlat->val) { 432158630Spav /* don't print the "all-bits-zero" string unless all 433158630Spav bits are really zero */ 434158630Spav if (xlat->val == 0 && val != 0) 435158630Spav continue; 436158630Spav len += sprintf(str + len, "%s|", xlat->str); 437158630Spav rem &= ~(xlat->val); 438158630Spav } 439158630Spav } 440158630Spav /* if we have leftover bits or didn't match anything */ 441158630Spav if (rem || len == 0) 442158630Spav len += sprintf(str + len, "0x%x", rem); 443158630Spav if (len && str[len - 1] == '|') 444158630Spav len--; 445158630Spav str[len] = 0; 446181061Sdes return (str); 447158630Spav} 448158630Spav 44931567Ssef/* 45031567Ssef * If/when the list gets big, it might be desirable to do it 45131567Ssef * as a hash table or binary search. 45231567Ssef */ 45331567Ssef 45431567Ssefstruct syscall * 455181061Sdesget_syscall(const char *name) 456181061Sdes{ 457240005Szont struct syscall *sc; 45831567Ssef 459240005Szont sc = syscalls; 460133349Salfred if (name == NULL) 461133349Salfred return (NULL); 46231567Ssef while (sc->name) { 463240005Szont if (strcmp(name, sc->name) == 0) 464181061Sdes return (sc); 46531567Ssef sc++; 46631567Ssef } 467181061Sdes return (NULL); 46831567Ssef} 46931567Ssef 47031567Ssef/* 47185292Sdes * get_struct 47285292Sdes * 47385292Sdes * Copy a fixed amount of bytes from the process. 47485292Sdes */ 47585292Sdes 47687703Smarkmstatic int 477239501Szontget_struct(pid_t pid, void *offset, void *buf, int len) 478181061Sdes{ 479168569Sdelphij struct ptrace_io_desc iorequest; 480181061Sdes 481168569Sdelphij iorequest.piod_op = PIOD_READ_D; 482168569Sdelphij iorequest.piod_offs = offset; 483168569Sdelphij iorequest.piod_addr = buf; 484168569Sdelphij iorequest.piod_len = len; 485168569Sdelphij if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) 486181061Sdes return (-1); 487181061Sdes return (0); 48885292Sdes} 48985292Sdes 490240005Szont#define MAXSIZE 4096 491240005Szont#define BLOCKSIZE 1024 49285292Sdes/* 49331567Ssef * get_string 49431567Ssef * Copy a string from the process. Note that it is 49531567Ssef * expected to be a C string, but if max is set, it will 49631567Ssef * only get that much. 49731567Ssef */ 49831567Ssef 499168569Sdelphijstatic char * 500181061Sdesget_string(pid_t pid, void *offset, int max) 501181061Sdes{ 502240005Szont struct ptrace_io_desc iorequest; 50332275Scharnier char *buf; 504240005Szont int diff, i, size, totalsize; 505181061Sdes 506240005Szont diff = 0; 507181061Sdes totalsize = size = max ? (max + 1) : BLOCKSIZE; 508168569Sdelphij buf = malloc(totalsize); 509168569Sdelphij if (buf == NULL) 510181061Sdes return (NULL); 511181061Sdes for (;;) { 512168569Sdelphij diff = totalsize - size; 513168569Sdelphij iorequest.piod_op = PIOD_READ_D; 514168569Sdelphij iorequest.piod_offs = (char *)offset + diff; 515168569Sdelphij iorequest.piod_addr = buf + diff; 516168569Sdelphij iorequest.piod_len = size; 517168569Sdelphij if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) { 518168569Sdelphij free(buf); 519181061Sdes return (NULL); 52031567Ssef } 521168569Sdelphij for (i = 0 ; i < size; i++) { 522168569Sdelphij if (buf[diff + i] == '\0') 523168569Sdelphij return (buf); 524168569Sdelphij } 525168569Sdelphij if (totalsize < MAXSIZE - BLOCKSIZE && max == 0) { 526168569Sdelphij totalsize += BLOCKSIZE; 527168569Sdelphij buf = realloc(buf, totalsize); 528168569Sdelphij size = BLOCKSIZE; 529181061Sdes } else { 530216224Sjh buf[totalsize - 1] = '\0'; 531181061Sdes return (buf); 532168569Sdelphij } 53331567Ssef } 53431567Ssef} 53531567Ssef 53631567Ssef 53731567Ssef/* 53831567Ssef * print_arg 53931567Ssef * Converts a syscall argument into a string. Said string is 54031567Ssef * allocated via malloc(), so needs to be free()'d. The file 54131567Ssef * descriptor is for the process' memory (via /proc), and is used 54231567Ssef * to get any data (where the argument is a pointer). sc is 54331567Ssef * a pointer to the syscall description (see above); args is 54431567Ssef * an array of all of the system call arguments. 54531567Ssef */ 54631567Ssef 54731567Ssefchar * 548240005Szontprint_arg(struct syscall_args *sc, unsigned long *args, long retval, 549240005Szont struct trussinfo *trussinfo) 550181061Sdes{ 551240005Szont char *tmp; 552240005Szont pid_t pid; 553158630Spav 554240005Szont tmp = NULL; 555240005Szont pid = trussinfo->pid; 556181061Sdes switch (sc->type & ARG_MASK) { 557181061Sdes case Hex: 558181061Sdes asprintf(&tmp, "0x%x", (int)args[sc->offset]); 559181061Sdes break; 560181061Sdes case Octal: 561181061Sdes asprintf(&tmp, "0%o", (int)args[sc->offset]); 562181061Sdes break; 563181061Sdes case Int: 564181061Sdes asprintf(&tmp, "%d", (int)args[sc->offset]); 565181061Sdes break; 566181061Sdes case Name: { 567181061Sdes /* NULL-terminated string. */ 568181061Sdes char *tmp2; 569181061Sdes tmp2 = get_string(pid, (void*)args[sc->offset], 0); 570181061Sdes asprintf(&tmp, "\"%s\"", tmp2); 571181061Sdes free(tmp2); 572181061Sdes break; 573181061Sdes } 574181061Sdes case BinString: { 575181061Sdes /* Binary block of data that might have printable characters. 576181061Sdes XXX If type|OUT, assume that the length is the syscall's 577181061Sdes return value. Otherwise, assume that the length of the block 578181061Sdes is in the next syscall argument. */ 579181061Sdes int max_string = trussinfo->strsize; 580181061Sdes char tmp2[max_string+1], *tmp3; 581181061Sdes int len; 582181061Sdes int truncated = 0; 583158630Spav 584181061Sdes if (sc->type & OUT) 585181061Sdes len = retval; 586181061Sdes else 587181061Sdes len = args[sc->offset + 1]; 588101289Smdodd 589181061Sdes /* Don't print more than max_string characters, to avoid word 590181061Sdes wrap. If we have to truncate put some ... after the string. 591181061Sdes */ 592181061Sdes if (len > max_string) { 593181061Sdes len = max_string; 594181061Sdes truncated = 1; 595181061Sdes } 596240005Szont if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len) 597240005Szont != -1) { 598181061Sdes tmp3 = malloc(len * 4 + 1); 599181061Sdes while (len) { 600240005Szont if (strvisx(tmp3, tmp2, len, 601240005Szont VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string) 602181061Sdes break; 603181061Sdes len--; 604181061Sdes truncated = 1; 605181061Sdes }; 606240005Szont asprintf(&tmp, "\"%s\"%s", tmp3, truncated ? 607240005Szont "..." : ""); 608181061Sdes free(tmp3); 609181061Sdes } else { 610181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 611181061Sdes } 612181061Sdes break; 613181061Sdes } 614181061Sdes case StringArray: { 615181061Sdes int num, size, i; 616181061Sdes char *tmp2; 617181061Sdes char *string; 618181061Sdes char *strarray[100]; /* XXX This is ugly. */ 619101289Smdodd 620240005Szont if (get_struct(pid, (void *)args[sc->offset], 621240005Szont (void *)&strarray, sizeof(strarray)) == -1) 622181061Sdes err(1, "get_struct %p", (void *)args[sc->offset]); 623181061Sdes num = 0; 624181061Sdes size = 0; 625101289Smdodd 626181061Sdes /* Find out how large of a buffer we'll need. */ 627181061Sdes while (strarray[num] != NULL) { 628181061Sdes string = get_string(pid, (void*)strarray[num], 0); 629181061Sdes size += strlen(string); 630181061Sdes free(string); 631181061Sdes num++; 632181061Sdes } 633181061Sdes size += 4 + (num * 4); 634181061Sdes tmp = (char *)malloc(size); 635181061Sdes tmp2 = tmp; 636181061Sdes 637181061Sdes tmp2 += sprintf(tmp2, " ["); 638181061Sdes for (i = 0; i < num; i++) { 639181061Sdes string = get_string(pid, (void*)strarray[i], 0); 640240005Szont tmp2 += sprintf(tmp2, " \"%s\"%c", string, 641240005Szont (i + 1 == num) ? ' ' : ','); 642181061Sdes free(string); 643181061Sdes } 644181061Sdes tmp2 += sprintf(tmp2, "]"); 645181061Sdes break; 646181061Sdes } 647134799Smarcel#ifdef __LP64__ 648181061Sdes case Quad: 649181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 650181061Sdes break; 651134799Smarcel#else 652181061Sdes case Quad: { 653181061Sdes unsigned long long ll; 654181061Sdes ll = *(unsigned long long *)(args + sc->offset); 655181061Sdes asprintf(&tmp, "0x%llx", ll); 656181061Sdes break; 657181061Sdes } 658134799Smarcel#endif 659181061Sdes case Ptr: 660181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 661181061Sdes break; 662181061Sdes case Readlinkres: { 663181061Sdes char *tmp2; 664181061Sdes if (retval == -1) { 665181061Sdes tmp = strdup(""); 666181061Sdes break; 667181061Sdes } 668181061Sdes tmp2 = get_string(pid, (void*)args[sc->offset], retval); 669181061Sdes asprintf(&tmp, "\"%s\"", tmp2); 670181061Sdes free(tmp2); 671181061Sdes break; 672181061Sdes } 673181061Sdes case Ioctl: { 674181061Sdes const char *temp = ioctlname(args[sc->offset]); 675240005Szont if (temp) 676181061Sdes tmp = strdup(temp); 677240005Szont else { 678181061Sdes unsigned long arg = args[sc->offset]; 679240005Szont asprintf(&tmp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }", 680240005Szont arg, arg & IOC_OUT ? "R" : "", 681240005Szont arg & IOC_IN ? "W" : "", IOCGROUP(arg), 682240005Szont isprint(IOCGROUP(arg)) ? (char)IOCGROUP(arg) : '?', 683181061Sdes arg & 0xFF, IOCPARM_LEN(arg)); 684181061Sdes } 685181061Sdes break; 686181061Sdes } 687181061Sdes case Umtx: { 688181061Sdes struct umtx umtx; 689240005Szont if (get_struct(pid, (void *)args[sc->offset], &umtx, 690240005Szont sizeof(umtx)) != -1) 691181061Sdes asprintf(&tmp, "{ 0x%lx }", (long)umtx.u_owner); 692181061Sdes else 693181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 694181061Sdes break; 695181061Sdes } 696181061Sdes case Timespec: { 697181061Sdes struct timespec ts; 698240005Szont if (get_struct(pid, (void *)args[sc->offset], &ts, 699240005Szont sizeof(ts)) != -1) 700240005Szont asprintf(&tmp, "{%ld.%09ld }", (long)ts.tv_sec, 701240005Szont ts.tv_nsec); 702181061Sdes else 703181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 704181061Sdes break; 705181061Sdes } 706181061Sdes case Timeval: { 707181061Sdes struct timeval tv; 708240005Szont if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) 709240005Szont != -1) 710240005Szont asprintf(&tmp, "{%ld.%06ld }", (long)tv.tv_sec, 711240005Szont tv.tv_usec); 712181061Sdes else 713181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 714181061Sdes break; 715181061Sdes } 716181061Sdes case Timeval2: { 717181061Sdes struct timeval tv[2]; 718240005Szont if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) 719240005Szont != -1) 720181061Sdes asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }", 721181061Sdes (long)tv[0].tv_sec, tv[0].tv_usec, 722181061Sdes (long)tv[1].tv_sec, tv[1].tv_usec); 723181061Sdes else 724181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 725181061Sdes break; 726181061Sdes } 727181061Sdes case Itimerval: { 728181061Sdes struct itimerval itv; 729240005Szont if (get_struct(pid, (void *)args[sc->offset], &itv, 730240005Szont sizeof(itv)) != -1) 731181061Sdes asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }", 732181061Sdes (long)itv.it_interval.tv_sec, 733181061Sdes itv.it_interval.tv_usec, 734181061Sdes (long)itv.it_value.tv_sec, 735181061Sdes itv.it_value.tv_usec); 736181061Sdes else 737181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 738181061Sdes break; 739181061Sdes } 740181061Sdes case Pollfd: { 741181061Sdes /* 742240005Szont * XXX: A Pollfd argument expects the /next/ syscall argument 743240005Szont * to be the number of fds in the array. This matches the poll 744240005Szont * syscall. 745181061Sdes */ 746181061Sdes struct pollfd *pfd; 747181061Sdes int numfds = args[sc->offset+1]; 748181061Sdes int bytes = sizeof(struct pollfd) * numfds; 749181061Sdes int i, tmpsize, u, used; 750181061Sdes const int per_fd = 100; 751127332Sdwmalone 752181061Sdes if ((pfd = malloc(bytes)) == NULL) 753240005Szont err(1, "Cannot malloc %d bytes for pollfd array", 754240005Szont bytes); 755240005Szont if (get_struct(pid, (void *)args[sc->offset], pfd, bytes) 756240005Szont != -1) { 757181061Sdes used = 0; 758181061Sdes tmpsize = 1 + per_fd * numfds + 2; 759181061Sdes if ((tmp = malloc(tmpsize)) == NULL) 760240005Szont err(1, "Cannot alloc %d bytes for poll output", 761240005Szont tmpsize); 762127332Sdwmalone 763181061Sdes tmp[used++] = '{'; 764181061Sdes for (i = 0; i < numfds; i++) { 765127332Sdwmalone 766240005Szont u = snprintf(tmp + used, per_fd, "%s%d/%s", 767240005Szont i > 0 ? " " : "", pfd[i].fd, 768240005Szont xlookup_bits(poll_flags, pfd[i].events)); 769181061Sdes if (u > 0) 770181061Sdes used += u < per_fd ? u : per_fd; 771181061Sdes } 772181061Sdes tmp[used++] = '}'; 773181061Sdes tmp[used++] = '\0'; 774181061Sdes } else { 775181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 776181061Sdes } 777181061Sdes free(pfd); 778181061Sdes break; 779127332Sdwmalone } 780181061Sdes case Fd_set: { 781181061Sdes /* 782240005Szont * XXX: A Fd_set argument expects the /first/ syscall argument 783240005Szont * to be the number of fds in the array. This matches the 784240005Szont * select syscall. 785181061Sdes */ 786181061Sdes fd_set *fds; 787181061Sdes int numfds = args[0]; 788181061Sdes int bytes = _howmany(numfds, _NFDBITS) * _NFDBITS; 789181061Sdes int i, tmpsize, u, used; 790181061Sdes const int per_fd = 20; 791127332Sdwmalone 792181061Sdes if ((fds = malloc(bytes)) == NULL) 793240005Szont err(1, "Cannot malloc %d bytes for fd_set array", 794240005Szont bytes); 795240005Szont if (get_struct(pid, (void *)args[sc->offset], fds, bytes) 796240005Szont != -1) { 797181061Sdes used = 0; 798181061Sdes tmpsize = 1 + numfds * per_fd + 2; 799181061Sdes if ((tmp = malloc(tmpsize)) == NULL) 800240005Szont err(1, "Cannot alloc %d bytes for fd_set " 801240005Szont "output", tmpsize); 802127332Sdwmalone 803181061Sdes tmp[used++] = '{'; 804181061Sdes for (i = 0; i < numfds; i++) { 805181061Sdes if (FD_ISSET(i, fds)) { 806240005Szont u = snprintf(tmp + used, per_fd, "%d ", 807240005Szont i); 808181061Sdes if (u > 0) 809181061Sdes used += u < per_fd ? u : per_fd; 810181061Sdes } 811181061Sdes } 812181061Sdes if (tmp[used-1] == ' ') 813181061Sdes used--; 814181061Sdes tmp[used++] = '}'; 815181061Sdes tmp[used++] = '\0'; 816240005Szont } else 817181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 818181061Sdes free(fds); 819181061Sdes break; 820127332Sdwmalone } 821181061Sdes case Signal: { 822181061Sdes long sig; 82349609Sdes 824181061Sdes sig = args[sc->offset]; 825181061Sdes tmp = strsig(sig); 826181061Sdes if (tmp == NULL) 827181061Sdes asprintf(&tmp, "%ld", sig); 828181061Sdes break; 829181061Sdes } 830181061Sdes case Sigset: { 831181061Sdes long sig; 832181061Sdes sigset_t ss; 833181061Sdes int i, used; 834158630Spav 835181061Sdes sig = args[sc->offset]; 836240005Szont if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, 837240005Szont sizeof(ss)) == -1) { 838181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 839181061Sdes break; 840181061Sdes } 841181061Sdes tmp = malloc(sys_nsig * 8); /* 7 bytes avg per signal name */ 842181061Sdes used = 0; 843181061Sdes for (i = 1; i < sys_nsig; i++) { 844240005Szont if (sigismember(&ss, i)) 845181061Sdes used += sprintf(tmp + used, "%s|", strsig(i)); 846181061Sdes } 847181061Sdes if (used) 848181061Sdes tmp[used-1] = 0; 849181061Sdes else 850181061Sdes strcpy(tmp, "0x0"); 851181061Sdes break; 852181061Sdes } 853181061Sdes case Sigprocmask: { 854181061Sdes switch (args[sc->offset]) { 855240005Szont#define S(a) case a: tmp = strdup(#a); break; 856181061Sdes S(SIG_BLOCK); 857181061Sdes S(SIG_UNBLOCK); 858181061Sdes S(SIG_SETMASK); 859127328Salfred#undef S 860181061Sdes } 861181061Sdes if (tmp == NULL) 862181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 863181061Sdes break; 864127328Salfred } 865181061Sdes case Fcntlflag: { 866181061Sdes /* XXX output depends on the value of the previous argument */ 867181061Sdes switch (args[sc->offset-1]) { 868181061Sdes case F_SETFD: 869240005Szont tmp = strdup(xlookup_bits(fcntlfd_arg, 870240005Szont args[sc->offset])); 871181061Sdes break; 872181061Sdes case F_SETFL: 873240005Szont tmp = strdup(xlookup_bits(fcntlfl_arg, 874240005Szont args[sc->offset])); 875181061Sdes break; 876181061Sdes case F_GETFD: 877181061Sdes case F_GETFL: 878181061Sdes case F_GETOWN: 879181061Sdes tmp = strdup(""); 880181061Sdes break; 881181061Sdes default: 882181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 883181061Sdes break; 884181061Sdes } 885181061Sdes break; 886181061Sdes } 887181061Sdes case Open: 888181061Sdes tmp = strdup(xlookup_bits(open_flags, args[sc->offset])); 889181061Sdes break; 890181061Sdes case Fcntl: 891181061Sdes tmp = strdup(xlookup(fcntl_arg, args[sc->offset])); 892181061Sdes break; 893181061Sdes case Mprot: 894181061Sdes tmp = strdup(xlookup_bits(mprot_flags, args[sc->offset])); 895181061Sdes break; 896181061Sdes case Mmapflags: 897181061Sdes tmp = strdup(xlookup_bits(mmap_flags, args[sc->offset])); 898181061Sdes break; 899181061Sdes case Whence: 900181061Sdes tmp = strdup(xlookup(whence_arg, args[sc->offset])); 901181061Sdes break; 902181061Sdes case Sockdomain: 903181061Sdes tmp = strdup(xlookup(sockdomain_arg, args[sc->offset])); 904181061Sdes break; 905181061Sdes case Socktype: 906181061Sdes tmp = strdup(xlookup(socktype_arg, args[sc->offset])); 907181061Sdes break; 908181061Sdes case Shutdown: 909181061Sdes tmp = strdup(xlookup(shutdown_arg, args[sc->offset])); 910181061Sdes break; 911181061Sdes case Resource: 912181061Sdes tmp = strdup(xlookup(resource_arg, args[sc->offset])); 913181061Sdes break; 914181061Sdes case Pathconf: 915181061Sdes tmp = strdup(xlookup(pathconf_arg, args[sc->offset])); 916181061Sdes break; 917253850Smarkj case Rforkflags: 918253850Smarkj tmp = strdup(xlookup_bits(rfork_flags, args[sc->offset])); 919253850Smarkj break; 920181061Sdes case Sockaddr: { 921181061Sdes struct sockaddr_storage ss; 922181061Sdes char addr[64]; 923181061Sdes struct sockaddr_in *lsin; 924181061Sdes struct sockaddr_in6 *lsin6; 925181061Sdes struct sockaddr_un *sun; 926181061Sdes struct sockaddr *sa; 927181061Sdes char *p; 928181061Sdes u_char *q; 929181061Sdes int i; 93085292Sdes 931181061Sdes if (args[sc->offset] == 0) { 932181061Sdes asprintf(&tmp, "NULL"); 933181061Sdes break; 934181061Sdes } 935121606Smarcel 936181061Sdes /* yuck: get ss_len */ 937181061Sdes if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, 938240005Szont sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1) 939181061Sdes err(1, "get_struct %p", (void *)args[sc->offset]); 940181061Sdes /* 941181061Sdes * If ss_len is 0, then try to guess from the sockaddr type. 942181061Sdes * AF_UNIX may be initialized incorrectly, so always frob 943181061Sdes * it by using the "right" size. 944181061Sdes */ 945181061Sdes if (ss.ss_len == 0 || ss.ss_family == AF_UNIX) { 946181061Sdes switch (ss.ss_family) { 947181061Sdes case AF_INET: 948181061Sdes ss.ss_len = sizeof(*lsin); 949181061Sdes break; 950181061Sdes case AF_UNIX: 951181061Sdes ss.ss_len = sizeof(*sun); 952181061Sdes break; 953181061Sdes default: 954181061Sdes /* hurrrr */ 955181061Sdes break; 956181061Sdes } 957181061Sdes } 958240005Szont if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, 959240005Szont ss.ss_len) == -1) { 960181061Sdes err(2, "get_struct %p", (void *)args[sc->offset]); 961181061Sdes } 96285292Sdes 963181061Sdes switch (ss.ss_family) { 964181061Sdes case AF_INET: 965181061Sdes lsin = (struct sockaddr_in *)&ss; 966181061Sdes inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof addr); 967240005Szont asprintf(&tmp, "{ AF_INET %s:%d }", addr, 968240005Szont htons(lsin->sin_port)); 969181061Sdes break; 970181061Sdes case AF_INET6: 971181061Sdes lsin6 = (struct sockaddr_in6 *)&ss; 972240005Szont inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, 973240005Szont sizeof addr); 974240005Szont asprintf(&tmp, "{ AF_INET6 [%s]:%d }", addr, 975240005Szont htons(lsin6->sin6_port)); 976181061Sdes break; 977181061Sdes case AF_UNIX: 978181061Sdes sun = (struct sockaddr_un *)&ss; 979181061Sdes asprintf(&tmp, "{ AF_UNIX \"%s\" }", sun->sun_path); 980181061Sdes break; 981181061Sdes default: 982181061Sdes sa = (struct sockaddr *)&ss; 983240005Szont asprintf(&tmp, "{ sa_len = %d, sa_family = %d, sa_data " 984240005Szont "= {%n%*s } }", (int)sa->sa_len, (int)sa->sa_family, 985240005Szont &i, 6 * (int)(sa->sa_len - ((char *)&sa->sa_data - 986240005Szont (char *)sa)), ""); 987181061Sdes if (tmp != NULL) { 988181061Sdes p = tmp + i; 989240005Szont for (q = (u_char *)&sa->sa_data; 990240005Szont q < (u_char *)sa + sa->sa_len; q++) 991181061Sdes p += sprintf(p, " %#02x,", *q); 992181061Sdes } 993181061Sdes } 994181061Sdes break; 99586138Sgreen } 996181061Sdes case Sigaction: { 997181061Sdes struct sigaction sa; 998181061Sdes char *hand; 999181061Sdes const char *h; 1000127332Sdwmalone 1001240005Szont if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa)) 1002240005Szont != -1) { 1003181061Sdes asprintf(&hand, "%p", sa.sa_handler); 1004181061Sdes if (sa.sa_handler == SIG_DFL) 1005181061Sdes h = "SIG_DFL"; 1006181061Sdes else if (sa.sa_handler == SIG_IGN) 1007181061Sdes h = "SIG_IGN"; 1008181061Sdes else 1009181061Sdes h = hand; 1010158630Spav 1011240005Szont asprintf(&tmp, "{ %s %s ss_t }", h, 1012181061Sdes xlookup_bits(sigaction_flags, sa.sa_flags)); 1013181061Sdes free(hand); 1014240005Szont } else 1015181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 1016181061Sdes break; 1017181061Sdes } 1018181061Sdes case Kevent: { 1019181061Sdes /* 1020181061Sdes * XXX XXX: the size of the array is determined by either the 1021181061Sdes * next syscall argument, or by the syscall returnvalue, 1022181061Sdes * depending on which argument number we are. This matches the 1023181061Sdes * kevent syscall, but luckily that's the only syscall that uses 1024181061Sdes * them. 1025181061Sdes */ 1026181061Sdes struct kevent *ke; 1027181061Sdes int numevents = -1; 1028181061Sdes int bytes = 0; 1029181061Sdes int i, tmpsize, u, used; 1030181061Sdes const int per_ke = 100; 1031158630Spav 1032181061Sdes if (sc->offset == 1) 1033181061Sdes numevents = args[sc->offset+1]; 1034181061Sdes else if (sc->offset == 3 && retval != -1) 1035181061Sdes numevents = retval; 1036158630Spav 1037181061Sdes if (numevents >= 0) 1038181061Sdes bytes = sizeof(struct kevent) * numevents; 1039181061Sdes if ((ke = malloc(bytes)) == NULL) 1040240005Szont err(1, "Cannot malloc %d bytes for kevent array", 1041240005Szont bytes); 1042240005Szont if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset], 1043240005Szont ke, bytes) != -1) { 1044181061Sdes used = 0; 1045181061Sdes tmpsize = 1 + per_ke * numevents + 2; 1046181061Sdes if ((tmp = malloc(tmpsize)) == NULL) 1047240005Szont err(1, "Cannot alloc %d bytes for kevent " 1048240005Szont "output", tmpsize); 1049158630Spav 1050181061Sdes tmp[used++] = '{'; 1051181061Sdes for (i = 0; i < numevents; i++) { 1052181061Sdes u = snprintf(tmp + used, per_ke, 1053181061Sdes "%s%p,%s,%s,%d,%p,%p", 1054181061Sdes i > 0 ? " " : "", 1055181061Sdes (void *)ke[i].ident, 1056181061Sdes xlookup(kevent_filters, ke[i].filter), 1057181061Sdes xlookup_bits(kevent_flags, ke[i].flags), 1058181061Sdes ke[i].fflags, 1059181061Sdes (void *)ke[i].data, 1060181061Sdes (void *)ke[i].udata); 1061181061Sdes if (u > 0) 1062181061Sdes used += u < per_ke ? u : per_ke; 1063181061Sdes } 1064181061Sdes tmp[used++] = '}'; 1065181061Sdes tmp[used++] = '\0'; 1066181061Sdes } else { 1067181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 1068181061Sdes } 1069181061Sdes free(ke); 1070181061Sdes break; 1071158630Spav } 1072181061Sdes case Stat: { 1073181061Sdes struct stat st; 1074240005Szont if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st)) 1075240005Szont != -1) { 1076181061Sdes char mode[12]; 1077181061Sdes strmode(st.st_mode, mode); 1078240005Szont asprintf(&tmp, 1079240005Szont "{ mode=%s,inode=%jd,size=%jd,blksize=%ld }", mode, 1080240005Szont (intmax_t)st.st_ino, (intmax_t)st.st_size, 1081240005Szont (long)st.st_blksize); 1082181061Sdes } else { 1083181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 1084181061Sdes } 1085181061Sdes break; 1086181061Sdes } 1087181061Sdes case Rusage: { 1088181061Sdes struct rusage ru; 1089240005Szont if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru)) 1090240005Szont != -1) { 1091240005Szont asprintf(&tmp, 1092240005Szont "{ u=%ld.%06ld,s=%ld.%06ld,in=%ld,out=%ld }", 1093181061Sdes (long)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec, 1094181061Sdes (long)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec, 1095181061Sdes ru.ru_inblock, ru.ru_oublock); 1096240005Szont } else 1097181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 1098181061Sdes break; 1099181061Sdes } 1100181061Sdes case Rlimit: { 1101181061Sdes struct rlimit rl; 1102240005Szont if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl)) 1103240005Szont != -1) { 1104181061Sdes asprintf(&tmp, "{ cur=%ju,max=%ju }", 1105181061Sdes rl.rlim_cur, rl.rlim_max); 1106240005Szont } else 1107181061Sdes asprintf(&tmp, "0x%lx", args[sc->offset]); 1108181061Sdes break; 1109181061Sdes } 1110181061Sdes default: 1111181061Sdes errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK); 1112181061Sdes } 1113181061Sdes return (tmp); 111431567Ssef} 111531567Ssef 111631567Ssef/* 111731567Ssef * print_syscall 111831567Ssef * Print (to outfile) the system call and its arguments. Note that 111931567Ssef * nargs is the number of arguments (not the number of words; this is 112031567Ssef * potentially confusing, I know). 112131567Ssef */ 112231567Ssef 112331567Ssefvoid 1124240005Szontprint_syscall(struct trussinfo *trussinfo, const char *name, int nargs, 1125240005Szont char **s_args) 1126181061Sdes{ 1127181061Sdes struct timespec timediff; 1128240005Szont int i, len; 1129101283Smdodd 1130240005Szont len = 0; 1131181061Sdes if (trussinfo->flags & FOLLOWFORKS) 1132181061Sdes len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid); 1133101283Smdodd 1134240562Szont if (name != NULL && (strcmp(name, "execve") == 0 || 1135240005Szont strcmp(name, "exit") == 0)) { 1136240562Szont clock_gettime(CLOCK_REALTIME, &trussinfo->curthread->after); 1137181061Sdes } 1138101285Smdodd 1139181061Sdes if (trussinfo->flags & ABSOLUTETIMESTAMPS) { 1140247338Sdelphij timespecsubt(&trussinfo->curthread->after, 1141240562Szont &trussinfo->start_time, &timediff); 1142181061Sdes len += fprintf(trussinfo->outfile, "%ld.%09ld ", 1143181061Sdes (long)timediff.tv_sec, timediff.tv_nsec); 1144181061Sdes } 1145101285Smdodd 1146181061Sdes if (trussinfo->flags & RELATIVETIMESTAMPS) { 1147247338Sdelphij timespecsubt(&trussinfo->curthread->after, 1148240562Szont &trussinfo->curthread->before, &timediff); 1149181061Sdes len += fprintf(trussinfo->outfile, "%ld.%09ld ", 1150181061Sdes (long)timediff.tv_sec, timediff.tv_nsec); 1151181061Sdes } 1152101285Smdodd 1153181061Sdes len += fprintf(trussinfo->outfile, "%s(", name); 1154101283Smdodd 1155181061Sdes for (i = 0; i < nargs; i++) { 1156181061Sdes if (s_args[i]) 1157181061Sdes len += fprintf(trussinfo->outfile, "%s", s_args[i]); 1158181061Sdes else 1159240005Szont len += fprintf(trussinfo->outfile, 1160240005Szont "<missing argument>"); 1161240005Szont len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? 1162240005Szont "," : ""); 1163181061Sdes } 1164181061Sdes len += fprintf(trussinfo->outfile, ")"); 1165181061Sdes for (i = 0; i < 6 - (len / 8); i++) 1166181061Sdes fprintf(trussinfo->outfile, "\t"); 116731567Ssef} 116858224Ssef 116958224Ssefvoid 1170122348Smarcelprint_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs, 1171192025Sdds char **s_args, int errorp, long retval, struct syscall *sc) 1172122348Smarcel{ 1173192025Sdds struct timespec timediff; 1174181061Sdes 1175192025Sdds if (trussinfo->flags & COUNTONLY) { 1176192025Sdds if (!sc) 1177192025Sdds return; 1178240562Szont clock_gettime(CLOCK_REALTIME, &trussinfo->curthread->after); 1179247338Sdelphij timespecsubt(&trussinfo->curthread->after, 1180240562Szont &trussinfo->curthread->before, &timediff); 1181247338Sdelphij timespecadd(&sc->time, &timediff, &sc->time); 1182192025Sdds sc->ncalls++; 1183192025Sdds if (errorp) 1184192025Sdds sc->nerror++; 1185192025Sdds return; 1186192025Sdds } 1187192025Sdds 1188181061Sdes print_syscall(trussinfo, name, nargs, s_args); 1189181061Sdes fflush(trussinfo->outfile); 1190240005Szont if (errorp) 1191240005Szont fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval, 1192240005Szont strerror(retval)); 1193240005Szont else { 1194200780Sjh /* 1195200780Sjh * Because pipe(2) has a special assembly glue to provide the 1196200780Sjh * libc API, we have to adjust retval. 1197200780Sjh */ 1198240005Szont if (name != NULL && strcmp(name, "pipe") == 0) 1199200780Sjh retval = 0; 1200181061Sdes fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval, retval); 1201181061Sdes } 120258224Ssef} 1203192025Sdds 1204192025Sddsvoid 1205192025Sddsprint_summary(struct trussinfo *trussinfo) 1206192025Sdds{ 1207240005Szont struct timespec total = {0, 0}; 1208192025Sdds struct syscall *sc; 1209192025Sdds int ncall, nerror; 1210192025Sdds 1211192025Sdds fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n", 1212240005Szont "syscall", "seconds", "calls", "errors"); 1213192025Sdds ncall = nerror = 0; 1214192025Sdds for (sc = syscalls; sc->name != NULL; sc++) 1215192025Sdds if (sc->ncalls) { 1216200781Sjh fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 1217200781Sjh sc->name, (intmax_t)sc->time.tv_sec, 1218200781Sjh sc->time.tv_nsec, sc->ncalls, sc->nerror); 1219247338Sdelphij timespecadd(&total, &sc->time, &total); 1220192025Sdds ncall += sc->ncalls; 1221192025Sdds nerror += sc->nerror; 1222192025Sdds } 1223192025Sdds fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n", 1224240005Szont "", "-------------", "-------", "-------"); 1225200781Sjh fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", 1226240005Szont "", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror); 1227192025Sdds} 1228