| 1 |
/* |
| 2 |
* Copyright 1997 Sean Eric Fagan |
| 3 |
* |
| 4 |
* Redistribution and use in source and binary forms, with or without |
| 5 |
* modification, are permitted provided that the following conditions |
| 6 |
* are met: |
| 7 |
* 1. Redistributions of source code must retain the above copyright |
| 8 |
* notice, this list of conditions and the following disclaimer. |
| 9 |
* 2. Redistributions in binary form must reproduce the above copyright |
| 10 |
* notice, this list of conditions and the following disclaimer in the |
| 11 |
* documentation and/or other materials provided with the distribution. |
| 12 |
* 3. All advertising materials mentioning features or use of this software |
| 13 |
* must display the following acknowledgement: |
| 14 |
* This product includes software developed by Sean Eric Fagan |
| 15 |
* 4. Neither the name of the author may be used to endorse or promote |
| 16 |
* products derived from this software without specific prior written |
| 17 |
* permission. |
| 18 |
* |
| 19 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 20 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 21 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 22 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| 23 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 24 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 25 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 26 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 27 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 28 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 29 |
* SUCH DAMAGE. |
| 30 |
*/ |
| 31 |
|
| 32 |
#ifndef lint |
| 33 |
static const char rcsid[] = |
| 34 |
"$FreeBSD$"; |
| 35 |
#endif /* not lint */ |
| 36 |
|
| 37 |
/* |
| 38 |
* This file has routines used to print out system calls and their |
| 39 |
* arguments. |
| 40 |
*/ |
| 41 |
|
| 42 |
#include <sys/types.h> |
| 43 |
#include <sys/mman.h> |
| 44 |
#include <sys/procctl.h> |
| 45 |
#include <sys/ptrace.h> |
| 46 |
#include <sys/socket.h> |
| 47 |
#include <sys/time.h> |
| 48 |
#include <sys/un.h> |
| 49 |
#include <sys/wait.h> |
| 50 |
#include <netinet/in.h> |
| 51 |
#include <arpa/inet.h> |
| 52 |
#include <sys/ioccom.h> |
| 53 |
#include <machine/atomic.h> |
| 54 |
#include <errno.h> |
| 55 |
#include <sys/umtx.h> |
| 56 |
#include <sys/event.h> |
| 57 |
#include <sys/stat.h> |
| 58 |
#include <sys/resource.h> |
| 59 |
|
| 60 |
#include <ctype.h> |
| 61 |
#include <err.h> |
| 62 |
#include <fcntl.h> |
| 63 |
#include <poll.h> |
| 64 |
#include <signal.h> |
| 65 |
#include <stdint.h> |
| 66 |
#include <stdio.h> |
| 67 |
#include <stdlib.h> |
| 68 |
#include <string.h> |
| 69 |
#include <time.h> |
| 70 |
#include <unistd.h> |
| 71 |
#include <vis.h> |
| 72 |
|
| 73 |
#include "truss.h" |
| 74 |
#include "extern.h" |
| 75 |
#include "syscall.h" |
| 76 |
|
| 77 |
/* 64-bit alignment on 32-bit platforms. */ |
| 78 |
#ifdef __powerpc__ |
| 79 |
#define QUAD_ALIGN 1 |
| 80 |
#else |
| 81 |
#define QUAD_ALIGN 0 |
| 82 |
#endif |
| 83 |
|
| 84 |
/* Number of slots needed for a 64-bit argument. */ |
| 85 |
#ifdef __LP64__ |
| 86 |
#define QUAD_SLOTS 1 |
| 87 |
#else |
| 88 |
#define QUAD_SLOTS 2 |
| 89 |
#endif |
| 90 |
|
| 91 |
/* |
| 92 |
* This should probably be in its own file, sorted alphabetically. |
| 93 |
*/ |
| 94 |
static struct syscall syscalls[] = { |
| 95 |
{ .name = "fcntl", .ret_type = 1, .nargs = 3, |
| 96 |
.args = { { Int, 0 } , { Fcntl, 1 }, { Fcntlflag | OUT, 2 } } }, |
| 97 |
{ .name = "fork", .ret_type = 1, .nargs = 0 }, |
| 98 |
{ .name = "vfork", .ret_type = 1, .nargs = 0 }, |
| 99 |
{ .name = "rfork", .ret_type = 1, .nargs = 1, |
| 100 |
.args = { { Rforkflags, 0 } } }, |
| 101 |
{ .name = "getegid", .ret_type = 1, .nargs = 0 }, |
| 102 |
{ .name = "geteuid", .ret_type = 1, .nargs = 0 }, |
| 103 |
{ .name = "linux_readlink", .ret_type = 1, .nargs = 3, |
| 104 |
.args = { { Name, 0 } , { Name | OUT, 1 }, { Int, 2 }}}, |
| 105 |
{ .name = "linux_socketcall", .ret_type = 1, .nargs = 2, |
| 106 |
.args = { { Int, 0 } , { LinuxSockArgs, 1 }}}, |
| 107 |
{ .name = "getgid", .ret_type = 1, .nargs = 0 }, |
| 108 |
{ .name = "getpid", .ret_type = 1, .nargs = 0 }, |
| 109 |
{ .name = "getpgid", .ret_type = 1, .nargs = 1, |
| 110 |
.args = { { Int, 0 } } }, |
| 111 |
{ .name = "getpgrp", .ret_type = 1, .nargs = 0 }, |
| 112 |
{ .name = "getppid", .ret_type = 1, .nargs = 0 }, |
| 113 |
{ .name = "getsid", .ret_type = 1, .nargs = 1, |
| 114 |
.args = { { Int, 0 } } }, |
| 115 |
{ .name = "getuid", .ret_type = 1, .nargs = 0 }, |
| 116 |
{ .name = "readlink", .ret_type = 1, .nargs = 3, |
| 117 |
.args = { { Name, 0 } , { Readlinkres | OUT, 1 }, { Int, 2 } } }, |
| 118 |
{ .name = "lseek", .ret_type = 2, .nargs = 3, |
| 119 |
.args = { { Int, 0 }, { Quad, 1 + QUAD_ALIGN }, { Whence, 1 + QUAD_SLOTS + QUAD_ALIGN } } }, |
| 120 |
{ .name = "linux_lseek", .ret_type = 2, .nargs = 3, |
| 121 |
.args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } }, |
| 122 |
{ .name = "mmap", .ret_type = 2, .nargs = 6, |
| 123 |
.args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 }, { Mmapflags, 3 }, { Int, 4 }, { Quad, 5 + QUAD_ALIGN } } }, |
| 124 |
{ .name = "linux_mkdir", .ret_type = 1, .nargs = 2, |
| 125 |
.args = { { Name | IN, 0} , {Int, 1}}}, |
| 126 |
{ .name = "mprotect", .ret_type = 1, .nargs = 3, |
| 127 |
.args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 } } }, |
| 128 |
{ .name = "open", .ret_type = 1, .nargs = 3, |
| 129 |
.args = { { Name | IN, 0 } , { Open, 1 }, { Octal, 2 } } }, |
| 130 |
{ .name = "mkdir", .ret_type = 1, .nargs = 2, |
| 131 |
.args = { { Name, 0 } , { Octal, 1 } } }, |
| 132 |
{ .name = "linux_open", .ret_type = 1, .nargs = 3, |
| 133 |
.args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } }, |
| 134 |
{ .name = "close", .ret_type = 1, .nargs = 1, |
| 135 |
.args = { { Int, 0 } } }, |
| 136 |
{ .name = "link", .ret_type = 0, .nargs = 2, |
| 137 |
.args = { { Name, 0 }, { Name, 1 } } }, |
| 138 |
{ .name = "unlink", .ret_type = 0, .nargs = 1, |
| 139 |
.args = { { Name, 0 } } }, |
| 140 |
{ .name = "chdir", .ret_type = 0, .nargs = 1, |
| 141 |
.args = { { Name, 0 } } }, |
| 142 |
{ .name = "chroot", .ret_type = 0, .nargs = 1, |
| 143 |
.args = { { Name, 0 } } }, |
| 144 |
{ .name = "mknod", .ret_type = 0, .nargs = 3, |
| 145 |
.args = { { Name, 0 }, { Octal, 1 }, { Int, 3 } } }, |
| 146 |
{ .name = "chmod", .ret_type = 0, .nargs = 2, |
| 147 |
.args = { { Name, 0 }, { Octal, 1 } } }, |
| 148 |
{ .name = "chown", .ret_type = 0, .nargs = 3, |
| 149 |
.args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } }, |
| 150 |
{ .name = "linux_stat64", .ret_type = 1, .nargs = 3, |
| 151 |
.args = { { Name | IN, 0 }, { Ptr | OUT, 1 }, { Ptr | IN, 1 }}}, |
| 152 |
{ .name = "mount", .ret_type = 0, .nargs = 4, |
| 153 |
.args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } }, |
| 154 |
{ .name = "umount", .ret_type = 0, .nargs = 2, |
| 155 |
.args = { { Name, 0 }, { Int, 2 } } }, |
| 156 |
{ .name = "fstat", .ret_type = 1, .nargs = 2, |
| 157 |
.args = { { Int, 0 }, { Stat | OUT , 1 } } }, |
| 158 |
{ .name = "stat", .ret_type = 1, .nargs = 2, |
| 159 |
.args = { { Name | IN, 0 }, { Stat | OUT, 1 } } }, |
| 160 |
{ .name = "lstat", .ret_type = 1, .nargs = 2, |
| 161 |
.args = { { Name | IN, 0 }, { Stat | OUT, 1 } } }, |
| 162 |
{ .name = "linux_newstat", .ret_type = 1, .nargs = 2, |
| 163 |
.args = { { Name | IN, 0 }, { Ptr | OUT, 1 } } }, |
| 164 |
{ .name = "linux_access", .ret_type = 1, .nargs = 2, |
| 165 |
.args = { { Name, 0 }, { Int, 1 }}}, |
| 166 |
{ .name = "linux_newfstat", .ret_type = 1, .nargs = 2, |
| 167 |
.args = { { Int, 0 }, { Ptr | OUT, 1 } } }, |
| 168 |
{ .name = "write", .ret_type = 1, .nargs = 3, |
| 169 |
.args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 } } }, |
| 170 |
{ .name = "ioctl", .ret_type = 1, .nargs = 3, |
| 171 |
.args = { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 } } }, |
| 172 |
{ .name = "break", .ret_type = 1, .nargs = 1, |
| 173 |
.args = { { Ptr, 0 } } }, |
| 174 |
{ .name = "exit", .ret_type = 0, .nargs = 1, |
| 175 |
.args = { { Hex, 0 } } }, |
| 176 |
{ .name = "access", .ret_type = 1, .nargs = 2, |
| 177 |
.args = { { Name | IN, 0 }, { Int, 1 } } }, |
| 178 |
{ .name = "sigaction", .ret_type = 1, .nargs = 3, |
| 179 |
.args = { { Signal, 0 }, { Sigaction | IN, 1 }, { Sigaction | OUT, 2 } } }, |
| 180 |
{ .name = "accept", .ret_type = 1, .nargs = 3, |
| 181 |
.args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, |
| 182 |
{ .name = "bind", .ret_type = 1, .nargs = 3, |
| 183 |
.args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, |
| 184 |
{ .name = "connect", .ret_type = 1, .nargs = 3, |
| 185 |
.args = { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, |
| 186 |
{ .name = "getpeername", .ret_type = 1, .nargs = 3, |
| 187 |
.args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, |
| 188 |
{ .name = "getsockname", .ret_type = 1, .nargs = 3, |
| 189 |
.args = { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, |
| 190 |
{ .name = "recvfrom", .ret_type = 1, .nargs = 6, |
| 191 |
.args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } }, |
| 192 |
{ .name = "sendto", .ret_type = 1, .nargs = 6, |
| 193 |
.args = { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } }, |
| 194 |
{ .name = "execve", .ret_type = 1, .nargs = 3, |
| 195 |
.args = { { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } }, |
| 196 |
{ .name = "linux_execve", .ret_type = 1, .nargs = 3, |
| 197 |
.args = { { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } }, |
| 198 |
{ .name = "kldload", .ret_type = 0, .nargs = 1, |
| 199 |
.args = { { Name | IN, 0 } } }, |
| 200 |
{ .name = "kldunload", .ret_type = 0, .nargs = 1, |
| 201 |
.args = { { Int, 0 } } }, |
| 202 |
{ .name = "kldfind", .ret_type = 0, .nargs = 1, |
| 203 |
.args = { { Name | IN, 0 } } }, |
| 204 |
{ .name = "kldnext", .ret_type = 0, .nargs = 1, |
| 205 |
.args = { { Int, 0 } } }, |
| 206 |
{ .name = "kldstat", .ret_type = 0, .nargs = 2, |
| 207 |
.args = { { Int, 0 }, { Ptr, 1 } } }, |
| 208 |
{ .name = "kldfirstmod", .ret_type = 0, .nargs = 1, |
| 209 |
.args = { { Int, 0 } } }, |
| 210 |
{ .name = "nanosleep", .ret_type = 0, .nargs = 1, |
| 211 |
.args = { { Timespec, 0 } } }, |
| 212 |
{ .name = "select", .ret_type = 1, .nargs = 5, |
| 213 |
.args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, { Timeval, 4 } } }, |
| 214 |
{ .name = "poll", .ret_type = 1, .nargs = 3, |
| 215 |
.args = { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } }, |
| 216 |
{ .name = "gettimeofday", .ret_type = 1, .nargs = 2, |
| 217 |
.args = { { Timeval | OUT, 0 }, { Ptr, 1 } } }, |
| 218 |
{ .name = "clock_gettime", .ret_type = 1, .nargs = 2, |
| 219 |
.args = { { Int, 0 }, { Timespec | OUT, 1 } } }, |
| 220 |
{ .name = "getitimer", .ret_type = 1, .nargs = 2, |
| 221 |
.args = { { Int, 0 }, { Itimerval | OUT, 2 } } }, |
| 222 |
{ .name = "setitimer", .ret_type = 1, .nargs = 3, |
| 223 |
.args = { { Int, 0 }, { Itimerval, 1 } , { Itimerval | OUT, 2 } } }, |
| 224 |
{ .name = "kse_release", .ret_type = 0, .nargs = 1, |
| 225 |
.args = { { Timespec, 0 } } }, |
| 226 |
{ .name = "kevent", .ret_type = 0, .nargs = 6, |
| 227 |
.args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 }, { Int, 4 }, { Timespec, 5 } } }, |
| 228 |
{ .name = "_umtx_lock", .ret_type = 0, .nargs = 1, |
| 229 |
.args = { { Umtx, 0 } } }, |
| 230 |
{ .name = "_umtx_unlock", .ret_type = 0, .nargs = 1, |
| 231 |
.args = { { Umtx, 0 } } }, |
| 232 |
{ .name = "sigprocmask", .ret_type = 0, .nargs = 3, |
| 233 |
.args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } }, |
| 234 |
{ .name = "unmount", .ret_type = 1, .nargs = 2, |
| 235 |
.args = { { Name, 0 }, { Int, 1 } } }, |
| 236 |
{ .name = "socket", .ret_type = 1, .nargs = 3, |
| 237 |
.args = { { Sockdomain, 0 }, { Socktype, 1 }, { Int, 2 } } }, |
| 238 |
{ .name = "getrusage", .ret_type = 1, .nargs = 2, |
| 239 |
.args = { { Int, 0 }, { Rusage | OUT, 1 } } }, |
| 240 |
{ .name = "__getcwd", .ret_type = 1, .nargs = 2, |
| 241 |
.args = { { Name | OUT, 0 }, { Int, 1 } } }, |
| 242 |
{ .name = "shutdown", .ret_type = 1, .nargs = 2, |
| 243 |
.args = { { Int, 0 }, { Shutdown, 1 } } }, |
| 244 |
{ .name = "getrlimit", .ret_type = 1, .nargs = 2, |
| 245 |
.args = { { Resource, 0 }, { Rlimit | OUT, 1 } } }, |
| 246 |
{ .name = "setrlimit", .ret_type = 1, .nargs = 2, |
| 247 |
.args = { { Resource, 0 }, { Rlimit | IN, 1 } } }, |
| 248 |
{ .name = "utimes", .ret_type = 1, .nargs = 2, |
| 249 |
.args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } }, |
| 250 |
{ .name = "lutimes", .ret_type = 1, .nargs = 2, |
| 251 |
.args = { { Name | IN, 0 }, { Timeval2 | IN, 1 } } }, |
| 252 |
{ .name = "futimes", .ret_type = 1, .nargs = 2, |
| 253 |
.args = { { Int, 0 }, { Timeval | IN, 1 } } }, |
| 254 |
{ .name = "chflags", .ret_type = 1, .nargs = 2, |
| 255 |
.args = { { Name | IN, 0 }, { Hex, 1 } } }, |
| 256 |
{ .name = "lchflags", .ret_type = 1, .nargs = 2, |
| 257 |
.args = { { Name | IN, 0 }, { Hex, 1 } } }, |
| 258 |
{ .name = "pathconf", .ret_type = 1, .nargs = 2, |
| 259 |
.args = { { Name | IN, 0 }, { Pathconf, 1 } } }, |
| 260 |
{ .name = "pipe", .ret_type = 1, .nargs = 1, |
| 261 |
.args = { { Ptr, 0 } } }, |
| 262 |
{ .name = "truncate", .ret_type = 1, .nargs = 3, |
| 263 |
.args = { { Name | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 } } }, |
| 264 |
{ .name = "ftruncate", .ret_type = 1, .nargs = 3, |
| 265 |
.args = { { Int | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 } } }, |
| 266 |
{ .name = "kill", .ret_type = 1, .nargs = 2, |
| 267 |
.args = { { Int | IN, 0 }, { Signal | IN, 1 } } }, |
| 268 |
{ .name = "munmap", .ret_type = 1, .nargs = 2, |
| 269 |
.args = { { Ptr, 0 }, { Int, 1 } } }, |
| 270 |
{ .name = "read", .ret_type = 1, .nargs = 3, |
| 271 |
.args = { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 } } }, |
| 272 |
{ .name = "rename", .ret_type = 1, .nargs = 2, |
| 273 |
.args = { { Name , 0 } , { Name, 1 } } }, |
| 274 |
{ .name = "symlink", .ret_type = 1, .nargs = 2, |
| 275 |
.args = { { Name , 0 } , { Name, 1 } } }, |
| 276 |
{ .name = "posix_openpt", .ret_type = 1, .nargs = 1, |
| 277 |
.args = { { Open, 0 } } }, |
| 278 |
{ .name = "wait4", .ret_type = 1, .nargs = 4, |
| 279 |
.args = { { Int, 0 }, { ExitStatus | OUT, 1 }, { Waitoptions, 2 }, |
| 280 |
{ Rusage | OUT, 3 } } }, |
| 281 |
{ .name = "wait6", .ret_type = 1, .nargs = 6, |
| 282 |
.args = { { Idtype, 0 }, { Int, 1 }, { ExitStatus | OUT, 2 }, |
| 283 |
{ Waitoptions, 3 }, { Rusage | OUT, 4 }, { Ptr, 5 } } }, |
| 284 |
{ .name = "procctl", .ret_type = 1, .nargs = 4, |
| 285 |
.args = { { Idtype, 0 }, { Int, 1 }, { Procctl, 2 }, { Ptr, 3 } } }, |
| 286 |
{ .name = "_umtx_op", .ret_type = 1, .nargs = 5, |
| 287 |
.args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 }, |
| 288 |
{ Ptr, 4 } } }, |
| 289 |
{ .name = 0 }, |
| 290 |
}; |
| 291 |
|
| 292 |
/* Xlat idea taken from strace */ |
| 293 |
struct xlat { |
| 294 |
int val; |
| 295 |
const char *str; |
| 296 |
}; |
| 297 |
|
| 298 |
#define X(a) { a, #a }, |
| 299 |
#define XEND { 0, NULL } |
| 300 |
|
| 301 |
static struct xlat kevent_filters[] = { |
| 302 |
X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE) |
| 303 |
X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER) |
| 304 |
X(EVFILT_FS) X(EVFILT_READ) XEND |
| 305 |
}; |
| 306 |
|
| 307 |
static struct xlat kevent_flags[] = { |
| 308 |
X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT) |
| 309 |
X(EV_CLEAR) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND |
| 310 |
}; |
| 311 |
|
| 312 |
static struct xlat poll_flags[] = { |
| 313 |
X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR) |
| 314 |
X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND) |
| 315 |
X(POLLWRBAND) X(POLLINIGNEOF) XEND |
| 316 |
}; |
| 317 |
|
| 318 |
static struct xlat mmap_flags[] = { |
| 319 |
X(MAP_SHARED) X(MAP_PRIVATE) X(MAP_FIXED) X(MAP_RENAME) |
| 320 |
X(MAP_NORESERVE) X(MAP_RESERVED0080) X(MAP_RESERVED0100) |
| 321 |
X(MAP_HASSEMAPHORE) X(MAP_STACK) X(MAP_NOSYNC) X(MAP_ANON) |
| 322 |
X(MAP_NOCORE) X(MAP_PREFAULT_READ) |
| 323 |
#ifdef MAP_32BIT |
| 324 |
X(MAP_32BIT) |
| 325 |
#endif |
| 326 |
XEND |
| 327 |
}; |
| 328 |
|
| 329 |
static struct xlat mprot_flags[] = { |
| 330 |
X(PROT_NONE) X(PROT_READ) X(PROT_WRITE) X(PROT_EXEC) XEND |
| 331 |
}; |
| 332 |
|
| 333 |
static struct xlat whence_arg[] = { |
| 334 |
X(SEEK_SET) X(SEEK_CUR) X(SEEK_END) XEND |
| 335 |
}; |
| 336 |
|
| 337 |
static struct xlat sigaction_flags[] = { |
| 338 |
X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP) |
| 339 |
X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND |
| 340 |
}; |
| 341 |
|
| 342 |
static struct xlat fcntl_arg[] = { |
| 343 |
X(F_DUPFD) X(F_GETFD) X(F_SETFD) X(F_GETFL) X(F_SETFL) |
| 344 |
X(F_GETOWN) X(F_SETOWN) X(F_GETLK) X(F_SETLK) X(F_SETLKW) XEND |
| 345 |
}; |
| 346 |
|
| 347 |
static struct xlat fcntlfd_arg[] = { |
| 348 |
X(FD_CLOEXEC) XEND |
| 349 |
}; |
| 350 |
|
| 351 |
static struct xlat fcntlfl_arg[] = { |
| 352 |
X(O_APPEND) X(O_ASYNC) X(O_FSYNC) X(O_NONBLOCK) X(O_NOFOLLOW) |
| 353 |
X(O_DIRECT) XEND |
| 354 |
}; |
| 355 |
|
| 356 |
static struct xlat sockdomain_arg[] = { |
| 357 |
X(PF_UNSPEC) X(PF_LOCAL) X(PF_UNIX) X(PF_INET) X(PF_IMPLINK) |
| 358 |
X(PF_PUP) X(PF_CHAOS) X(PF_NETBIOS) X(PF_ISO) X(PF_OSI) |
| 359 |
X(PF_ECMA) X(PF_DATAKIT) X(PF_CCITT) X(PF_SNA) X(PF_DECnet) |
| 360 |
X(PF_DLI) X(PF_LAT) X(PF_HYLINK) X(PF_APPLETALK) X(PF_ROUTE) |
| 361 |
X(PF_LINK) X(PF_XTP) X(PF_COIP) X(PF_CNT) X(PF_SIP) X(PF_IPX) |
| 362 |
X(PF_RTIP) X(PF_PIP) X(PF_ISDN) X(PF_KEY) X(PF_INET6) |
| 363 |
X(PF_NATM) X(PF_ATM) X(PF_NETGRAPH) X(PF_SLOW) X(PF_SCLUSTER) |
| 364 |
X(PF_ARP) X(PF_BLUETOOTH) XEND |
| 365 |
}; |
| 366 |
|
| 367 |
static struct xlat socktype_arg[] = { |
| 368 |
X(SOCK_STREAM) X(SOCK_DGRAM) X(SOCK_RAW) X(SOCK_RDM) |
| 369 |
X(SOCK_SEQPACKET) XEND |
| 370 |
}; |
| 371 |
|
| 372 |
static struct xlat open_flags[] = { |
| 373 |
X(O_RDONLY) X(O_WRONLY) X(O_RDWR) X(O_ACCMODE) X(O_NONBLOCK) |
| 374 |
X(O_APPEND) X(O_SHLOCK) X(O_EXLOCK) X(O_ASYNC) X(O_FSYNC) |
| 375 |
X(O_NOFOLLOW) X(O_CREAT) X(O_TRUNC) X(O_EXCL) X(O_NOCTTY) |
| 376 |
X(O_DIRECT) X(O_DIRECTORY) X(O_EXEC) X(O_TTY_INIT) X(O_CLOEXEC) XEND |
| 377 |
}; |
| 378 |
|
| 379 |
static struct xlat shutdown_arg[] = { |
| 380 |
X(SHUT_RD) X(SHUT_WR) X(SHUT_RDWR) XEND |
| 381 |
}; |
| 382 |
|
| 383 |
static struct xlat resource_arg[] = { |
| 384 |
X(RLIMIT_CPU) X(RLIMIT_FSIZE) X(RLIMIT_DATA) X(RLIMIT_STACK) |
| 385 |
X(RLIMIT_CORE) X(RLIMIT_RSS) X(RLIMIT_MEMLOCK) X(RLIMIT_NPROC) |
| 386 |
X(RLIMIT_NOFILE) X(RLIMIT_SBSIZE) X(RLIMIT_VMEM) XEND |
| 387 |
}; |
| 388 |
|
| 389 |
static struct xlat pathconf_arg[] = { |
| 390 |
X(_PC_LINK_MAX) X(_PC_MAX_CANON) X(_PC_MAX_INPUT) |
| 391 |
X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF) |
| 392 |
X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE) |
| 393 |
X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO) |
| 394 |
X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS) |
| 395 |
X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE) |
| 396 |
X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN) |
| 397 |
X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX) |
| 398 |
X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT) |
| 399 |
XEND |
| 400 |
}; |
| 401 |
|
| 402 |
static struct xlat rfork_flags[] = { |
| 403 |
X(RFPROC) X(RFNOWAIT) X(RFFDG) X(RFCFDG) X(RFTHREAD) X(RFMEM) |
| 404 |
X(RFSIGSHARE) X(RFTSIGZMB) X(RFLINUXTHPN) XEND |
| 405 |
}; |
| 406 |
|
| 407 |
static struct xlat wait_options[] = { |
| 408 |
X(WNOHANG) X(WUNTRACED) X(WCONTINUED) X(WNOWAIT) X(WEXITED) |
| 409 |
X(WTRAPPED) XEND |
| 410 |
}; |
| 411 |
|
| 412 |
static struct xlat idtype_arg[] = { |
| 413 |
X(P_PID) X(P_PPID) X(P_PGID) X(P_SID) X(P_CID) X(P_UID) X(P_GID) |
| 414 |
X(P_ALL) X(P_LWPID) X(P_TASKID) X(P_PROJID) X(P_POOLID) X(P_JAILID) |
| 415 |
X(P_CTID) X(P_CPUID) X(P_PSETID) XEND |
| 416 |
}; |
| 417 |
|
| 418 |
static struct xlat procctl_arg[] = { |
| 419 |
X(PROC_SPROTECT) XEND |
| 420 |
}; |
| 421 |
|
| 422 |
static struct xlat umtx_ops[] = { |
| 423 |
X(UMTX_OP_LOCK) X(UMTX_OP_UNLOCK) X(UMTX_OP_WAIT) |
| 424 |
X(UMTX_OP_WAKE) X(UMTX_OP_MUTEX_TRYLOCK) X(UMTX_OP_MUTEX_LOCK) |
| 425 |
X(UMTX_OP_MUTEX_UNLOCK) X(UMTX_OP_SET_CEILING) X(UMTX_OP_CV_WAIT) |
| 426 |
X(UMTX_OP_CV_SIGNAL) X(UMTX_OP_CV_BROADCAST) X(UMTX_OP_WAIT_UINT) |
| 427 |
X(UMTX_OP_RW_RDLOCK) X(UMTX_OP_RW_WRLOCK) X(UMTX_OP_RW_UNLOCK) |
| 428 |
X(UMTX_OP_WAIT_UINT_PRIVATE) X(UMTX_OP_WAKE_PRIVATE) |
| 429 |
X(UMTX_OP_MUTEX_WAIT) X(UMTX_OP_MUTEX_WAKE) X(UMTX_OP_SEM_WAIT) |
| 430 |
X(UMTX_OP_SEM_WAKE) X(UMTX_OP_NWAKE_PRIVATE) X(UMTX_OP_MUTEX_WAKE2) |
| 431 |
XEND |
| 432 |
}; |
| 433 |
|
| 434 |
#undef X |
| 435 |
#undef XEND |
| 436 |
|
| 437 |
/* |
| 438 |
* Searches an xlat array for a value, and returns it if found. Otherwise |
| 439 |
* return a string representation. |
| 440 |
*/ |
| 441 |
static const char * |
| 442 |
lookup(struct xlat *xlat, int val, int base) |
| 443 |
{ |
| 444 |
static char tmp[16]; |
| 445 |
|
| 446 |
for (; xlat->str != NULL; xlat++) |
| 447 |
if (xlat->val == val) |
| 448 |
return (xlat->str); |
| 449 |
switch (base) { |
| 450 |
case 8: |
| 451 |
sprintf(tmp, "0%o", val); |
| 452 |
break; |
| 453 |
case 16: |
| 454 |
sprintf(tmp, "0x%x", val); |
| 455 |
break; |
| 456 |
case 10: |
| 457 |
sprintf(tmp, "%u", val); |
| 458 |
break; |
| 459 |
default: |
| 460 |
errx(1,"Unknown lookup base"); |
| 461 |
break; |
| 462 |
} |
| 463 |
return (tmp); |
| 464 |
} |
| 465 |
|
| 466 |
static const char * |
| 467 |
xlookup(struct xlat *xlat, int val) |
| 468 |
{ |
| 469 |
|
| 470 |
return (lookup(xlat, val, 16)); |
| 471 |
} |
| 472 |
|
| 473 |
/* Searches an xlat array containing bitfield values. Remaining bits |
| 474 |
set after removing the known ones are printed at the end: |
| 475 |
IN|0x400 */ |
| 476 |
static char * |
| 477 |
xlookup_bits(struct xlat *xlat, int val) |
| 478 |
{ |
| 479 |
int len, rem; |
| 480 |
static char str[512]; |
| 481 |
|
| 482 |
len = 0; |
| 483 |
rem = val; |
| 484 |
for (; xlat->str != NULL; xlat++) { |
| 485 |
if ((xlat->val & rem) == xlat->val) { |
| 486 |
/* don't print the "all-bits-zero" string unless all |
| 487 |
bits are really zero */ |
| 488 |
if (xlat->val == 0 && val != 0) |
| 489 |
continue; |
| 490 |
len += sprintf(str + len, "%s|", xlat->str); |
| 491 |
rem &= ~(xlat->val); |
| 492 |
} |
| 493 |
} |
| 494 |
/* if we have leftover bits or didn't match anything */ |
| 495 |
if (rem || len == 0) |
| 496 |
len += sprintf(str + len, "0x%x", rem); |
| 497 |
if (len && str[len - 1] == '|') |
| 498 |
len--; |
| 499 |
str[len] = 0; |
| 500 |
return (str); |
| 501 |
} |
| 502 |
|
| 503 |
/* |
| 504 |
* If/when the list gets big, it might be desirable to do it |
| 505 |
* as a hash table or binary search. |
| 506 |
*/ |
| 507 |
|
| 508 |
struct syscall * |
| 509 |
get_syscall(const char *name) |
| 510 |
{ |
| 511 |
struct syscall *sc; |
| 512 |
|
| 513 |
sc = syscalls; |
| 514 |
if (name == NULL) |
| 515 |
return (NULL); |
| 516 |
while (sc->name) { |
| 517 |
if (strcmp(name, sc->name) == 0) |
| 518 |
return (sc); |
| 519 |
sc++; |
| 520 |
} |
| 521 |
return (NULL); |
| 522 |
} |
| 523 |
|
| 524 |
/* |
| 525 |
* get_struct |
| 526 |
* |
| 527 |
* Copy a fixed amount of bytes from the process. |
| 528 |
*/ |
| 529 |
|
| 530 |
static int |
| 531 |
get_struct(pid_t pid, void *offset, void *buf, int len) |
| 532 |
{ |
| 533 |
struct ptrace_io_desc iorequest; |
| 534 |
|
| 535 |
iorequest.piod_op = PIOD_READ_D; |
| 536 |
iorequest.piod_offs = offset; |
| 537 |
iorequest.piod_addr = buf; |
| 538 |
iorequest.piod_len = len; |
| 539 |
if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) |
| 540 |
return (-1); |
| 541 |
return (0); |
| 542 |
} |
| 543 |
|
| 544 |
#define MAXSIZE 4096 |
| 545 |
#define BLOCKSIZE 1024 |
| 546 |
/* |
| 547 |
* get_string |
| 548 |
* Copy a string from the process. Note that it is |
| 549 |
* expected to be a C string, but if max is set, it will |
| 550 |
* only get that much. |
| 551 |
*/ |
| 552 |
|
| 553 |
static char * |
| 554 |
get_string(pid_t pid, void *offset, int max) |
| 555 |
{ |
| 556 |
struct ptrace_io_desc iorequest; |
| 557 |
char *buf; |
| 558 |
int diff, i, size, totalsize; |
| 559 |
|
| 560 |
diff = 0; |
| 561 |
totalsize = size = max ? (max + 1) : BLOCKSIZE; |
| 562 |
buf = malloc(totalsize); |
| 563 |
if (buf == NULL) |
| 564 |
return (NULL); |
| 565 |
for (;;) { |
| 566 |
diff = totalsize - size; |
| 567 |
iorequest.piod_op = PIOD_READ_D; |
| 568 |
iorequest.piod_offs = (char *)offset + diff; |
| 569 |
iorequest.piod_addr = buf + diff; |
| 570 |
iorequest.piod_len = size; |
| 571 |
if (ptrace(PT_IO, pid, (caddr_t)&iorequest, 0) < 0) { |
| 572 |
free(buf); |
| 573 |
return (NULL); |
| 574 |
} |
| 575 |
for (i = 0 ; i < size; i++) { |
| 576 |
if (buf[diff + i] == '\0') |
| 577 |
return (buf); |
| 578 |
} |
| 579 |
if (totalsize < MAXSIZE - BLOCKSIZE && max == 0) { |
| 580 |
totalsize += BLOCKSIZE; |
| 581 |
buf = realloc(buf, totalsize); |
| 582 |
size = BLOCKSIZE; |
| 583 |
} else { |
| 584 |
buf[totalsize - 1] = '\0'; |
| 585 |
return (buf); |
| 586 |
} |
| 587 |
} |
| 588 |
} |
| 589 |
|
| 590 |
static char * |
| 591 |
strsig2(int sig) |
| 592 |
{ |
| 593 |
char *tmp; |
| 594 |
|
| 595 |
tmp = strsig(sig); |
| 596 |
if (tmp == NULL) |
| 597 |
asprintf(&tmp, "%d", sig); |
| 598 |
return (tmp); |
| 599 |
} |
| 600 |
|
| 601 |
/* |
| 602 |
* print_arg |
| 603 |
* Converts a syscall argument into a string. Said string is |
| 604 |
* allocated via malloc(), so needs to be free()'d. The file |
| 605 |
* descriptor is for the process' memory (via /proc), and is used |
| 606 |
* to get any data (where the argument is a pointer). sc is |
| 607 |
* a pointer to the syscall description (see above); args is |
| 608 |
* an array of all of the system call arguments. |
| 609 |
*/ |
| 610 |
|
| 611 |
char * |
| 612 |
print_arg(struct syscall_args *sc, unsigned long *args, long retval, |
| 613 |
struct trussinfo *trussinfo) |
| 614 |
{ |
| 615 |
char *tmp; |
| 616 |
pid_t pid; |
| 617 |
|
| 618 |
tmp = NULL; |
| 619 |
pid = trussinfo->pid; |
| 620 |
switch (sc->type & ARG_MASK) { |
| 621 |
case Hex: |
| 622 |
asprintf(&tmp, "0x%x", (int)args[sc->offset]); |
| 623 |
break; |
| 624 |
case Octal: |
| 625 |
asprintf(&tmp, "0%o", (int)args[sc->offset]); |
| 626 |
break; |
| 627 |
case Int: |
| 628 |
asprintf(&tmp, "%d", (int)args[sc->offset]); |
| 629 |
break; |
| 630 |
case LongHex: |
| 631 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 632 |
break; |
| 633 |
case Name: { |
| 634 |
/* NULL-terminated string. */ |
| 635 |
char *tmp2; |
| 636 |
tmp2 = get_string(pid, (void*)args[sc->offset], 0); |
| 637 |
asprintf(&tmp, "\"%s\"", tmp2); |
| 638 |
free(tmp2); |
| 639 |
break; |
| 640 |
} |
| 641 |
case BinString: { |
| 642 |
/* Binary block of data that might have printable characters. |
| 643 |
XXX If type|OUT, assume that the length is the syscall's |
| 644 |
return value. Otherwise, assume that the length of the block |
| 645 |
is in the next syscall argument. */ |
| 646 |
int max_string = trussinfo->strsize; |
| 647 |
char tmp2[max_string+1], *tmp3; |
| 648 |
int len; |
| 649 |
int truncated = 0; |
| 650 |
|
| 651 |
if (sc->type & OUT) |
| 652 |
len = retval; |
| 653 |
else |
| 654 |
len = args[sc->offset + 1]; |
| 655 |
|
| 656 |
/* Don't print more than max_string characters, to avoid word |
| 657 |
wrap. If we have to truncate put some ... after the string. |
| 658 |
*/ |
| 659 |
if (len > max_string) { |
| 660 |
len = max_string; |
| 661 |
truncated = 1; |
| 662 |
} |
| 663 |
if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len) |
| 664 |
!= -1) { |
| 665 |
tmp3 = malloc(len * 4 + 1); |
| 666 |
while (len) { |
| 667 |
if (strvisx(tmp3, tmp2, len, |
| 668 |
VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string) |
| 669 |
break; |
| 670 |
len--; |
| 671 |
truncated = 1; |
| 672 |
}; |
| 673 |
asprintf(&tmp, "\"%s\"%s", tmp3, truncated ? |
| 674 |
"..." : ""); |
| 675 |
free(tmp3); |
| 676 |
} else { |
| 677 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 678 |
} |
| 679 |
break; |
| 680 |
} |
| 681 |
case StringArray: { |
| 682 |
int num, size, i; |
| 683 |
char *tmp2; |
| 684 |
char *string; |
| 685 |
char *strarray[100]; /* XXX This is ugly. */ |
| 686 |
|
| 687 |
if (get_struct(pid, (void *)args[sc->offset], |
| 688 |
(void *)&strarray, sizeof(strarray)) == -1) |
| 689 |
err(1, "get_struct %p", (void *)args[sc->offset]); |
| 690 |
num = 0; |
| 691 |
size = 0; |
| 692 |
|
| 693 |
/* Find out how large of a buffer we'll need. */ |
| 694 |
while (strarray[num] != NULL) { |
| 695 |
string = get_string(pid, (void*)strarray[num], 0); |
| 696 |
size += strlen(string); |
| 697 |
free(string); |
| 698 |
num++; |
| 699 |
} |
| 700 |
size += 4 + (num * 4); |
| 701 |
tmp = (char *)malloc(size); |
| 702 |
tmp2 = tmp; |
| 703 |
|
| 704 |
tmp2 += sprintf(tmp2, " ["); |
| 705 |
for (i = 0; i < num; i++) { |
| 706 |
string = get_string(pid, (void*)strarray[i], 0); |
| 707 |
tmp2 += sprintf(tmp2, " \"%s\"%c", string, |
| 708 |
(i + 1 == num) ? ' ' : ','); |
| 709 |
free(string); |
| 710 |
} |
| 711 |
tmp2 += sprintf(tmp2, "]"); |
| 712 |
break; |
| 713 |
} |
| 714 |
#ifdef __LP64__ |
| 715 |
case Quad: |
| 716 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 717 |
break; |
| 718 |
#else |
| 719 |
case Quad: { |
| 720 |
unsigned long long ll; |
| 721 |
ll = *(unsigned long long *)(args + sc->offset); |
| 722 |
asprintf(&tmp, "0x%llx", ll); |
| 723 |
break; |
| 724 |
} |
| 725 |
#endif |
| 726 |
case Ptr: |
| 727 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 728 |
break; |
| 729 |
case Readlinkres: { |
| 730 |
char *tmp2; |
| 731 |
if (retval == -1) { |
| 732 |
tmp = strdup(""); |
| 733 |
break; |
| 734 |
} |
| 735 |
tmp2 = get_string(pid, (void*)args[sc->offset], retval); |
| 736 |
asprintf(&tmp, "\"%s\"", tmp2); |
| 737 |
free(tmp2); |
| 738 |
break; |
| 739 |
} |
| 740 |
case Ioctl: { |
| 741 |
const char *temp = ioctlname(args[sc->offset]); |
| 742 |
if (temp) |
| 743 |
tmp = strdup(temp); |
| 744 |
else { |
| 745 |
unsigned long arg = args[sc->offset]; |
| 746 |
asprintf(&tmp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu }", |
| 747 |
arg, arg & IOC_OUT ? "R" : "", |
| 748 |
arg & IOC_IN ? "W" : "", IOCGROUP(arg), |
| 749 |
isprint(IOCGROUP(arg)) ? (char)IOCGROUP(arg) : '?', |
| 750 |
arg & 0xFF, IOCPARM_LEN(arg)); |
| 751 |
} |
| 752 |
break; |
| 753 |
} |
| 754 |
case Umtx: { |
| 755 |
struct umtx umtx; |
| 756 |
if (get_struct(pid, (void *)args[sc->offset], &umtx, |
| 757 |
sizeof(umtx)) != -1) |
| 758 |
asprintf(&tmp, "{ 0x%lx }", (long)umtx.u_owner); |
| 759 |
else |
| 760 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 761 |
break; |
| 762 |
} |
| 763 |
case Timespec: { |
| 764 |
struct timespec ts; |
| 765 |
if (get_struct(pid, (void *)args[sc->offset], &ts, |
| 766 |
sizeof(ts)) != -1) |
| 767 |
asprintf(&tmp, "{%ld.%09ld }", (long)ts.tv_sec, |
| 768 |
ts.tv_nsec); |
| 769 |
else |
| 770 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 771 |
break; |
| 772 |
} |
| 773 |
case Timeval: { |
| 774 |
struct timeval tv; |
| 775 |
if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) |
| 776 |
!= -1) |
| 777 |
asprintf(&tmp, "{%ld.%06ld }", (long)tv.tv_sec, |
| 778 |
tv.tv_usec); |
| 779 |
else |
| 780 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 781 |
break; |
| 782 |
} |
| 783 |
case Timeval2: { |
| 784 |
struct timeval tv[2]; |
| 785 |
if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) |
| 786 |
!= -1) |
| 787 |
asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }", |
| 788 |
(long)tv[0].tv_sec, tv[0].tv_usec, |
| 789 |
(long)tv[1].tv_sec, tv[1].tv_usec); |
| 790 |
else |
| 791 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 792 |
break; |
| 793 |
} |
| 794 |
case Itimerval: { |
| 795 |
struct itimerval itv; |
| 796 |
if (get_struct(pid, (void *)args[sc->offset], &itv, |
| 797 |
sizeof(itv)) != -1) |
| 798 |
asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }", |
| 799 |
(long)itv.it_interval.tv_sec, |
| 800 |
itv.it_interval.tv_usec, |
| 801 |
(long)itv.it_value.tv_sec, |
| 802 |
itv.it_value.tv_usec); |
| 803 |
else |
| 804 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 805 |
break; |
| 806 |
} |
| 807 |
case LinuxSockArgs: |
| 808 |
{ |
| 809 |
struct linux_socketcall_args largs; |
| 810 |
if (get_struct(pid, (void *)args[sc->offset], (void *)&largs, |
| 811 |
sizeof(largs)) == -1) { |
| 812 |
err(1, "get_struct %p", (void *)args[sc->offset]); |
| 813 |
} |
| 814 |
const char *what; |
| 815 |
char buf[30]; |
| 816 |
|
| 817 |
switch (largs.what) { |
| 818 |
case LINUX_SOCKET: |
| 819 |
what = "LINUX_SOCKET"; |
| 820 |
break; |
| 821 |
case LINUX_BIND: |
| 822 |
what = "LINUX_BIND"; |
| 823 |
break; |
| 824 |
case LINUX_CONNECT: |
| 825 |
what = "LINUX_CONNECT"; |
| 826 |
break; |
| 827 |
case LINUX_LISTEN: |
| 828 |
what = "LINUX_LISTEN"; |
| 829 |
break; |
| 830 |
case LINUX_ACCEPT: |
| 831 |
what = "LINUX_ACCEPT"; |
| 832 |
break; |
| 833 |
case LINUX_GETSOCKNAME: |
| 834 |
what = "LINUX_GETSOCKNAME"; |
| 835 |
break; |
| 836 |
case LINUX_GETPEERNAME: |
| 837 |
what = "LINUX_GETPEERNAME"; |
| 838 |
break; |
| 839 |
case LINUX_SOCKETPAIR: |
| 840 |
what = "LINUX_SOCKETPAIR"; |
| 841 |
break; |
| 842 |
case LINUX_SEND: |
| 843 |
what = "LINUX_SEND"; |
| 844 |
break; |
| 845 |
case LINUX_RECV: |
| 846 |
what = "LINUX_RECV"; |
| 847 |
break; |
| 848 |
case LINUX_SENDTO: |
| 849 |
what = "LINUX_SENDTO"; |
| 850 |
break; |
| 851 |
case LINUX_RECVFROM: |
| 852 |
what = "LINUX_RECVFROM"; |
| 853 |
break; |
| 854 |
case LINUX_SHUTDOWN: |
| 855 |
what = "LINUX_SHUTDOWN"; |
| 856 |
break; |
| 857 |
case LINUX_SETSOCKOPT: |
| 858 |
what = "LINUX_SETSOCKOPT"; |
| 859 |
break; |
| 860 |
case LINUX_GETSOCKOPT: |
| 861 |
what = "LINUX_GETSOCKOPT"; |
| 862 |
break; |
| 863 |
case LINUX_SENDMSG: |
| 864 |
what = "LINUX_SENDMSG"; |
| 865 |
break; |
| 866 |
case LINUX_RECVMSG: |
| 867 |
what = "LINUX_RECVMSG"; |
| 868 |
break; |
| 869 |
default: |
| 870 |
sprintf(buf, "%d", largs.what); |
| 871 |
what = buf; |
| 872 |
break; |
| 873 |
} |
| 874 |
asprintf(&tmp, "(0x%lx)%s, 0x%lx", args[sc->offset], what, (long unsigned int)largs.args); |
| 875 |
break; |
| 876 |
} |
| 877 |
case Pollfd: { |
| 878 |
/* |
| 879 |
* XXX: A Pollfd argument expects the /next/ syscall argument |
| 880 |
* to be the number of fds in the array. This matches the poll |
| 881 |
* syscall. |
| 882 |
*/ |
| 883 |
struct pollfd *pfd; |
| 884 |
int numfds = args[sc->offset+1]; |
| 885 |
int bytes = sizeof(struct pollfd) * numfds; |
| 886 |
int i, tmpsize, u, used; |
| 887 |
const int per_fd = 100; |
| 888 |
|
| 889 |
if ((pfd = malloc(bytes)) == NULL) |
| 890 |
err(1, "Cannot malloc %d bytes for pollfd array", |
| 891 |
bytes); |
| 892 |
if (get_struct(pid, (void *)args[sc->offset], pfd, bytes) |
| 893 |
!= -1) { |
| 894 |
used = 0; |
| 895 |
tmpsize = 1 + per_fd * numfds + 2; |
| 896 |
if ((tmp = malloc(tmpsize)) == NULL) |
| 897 |
err(1, "Cannot alloc %d bytes for poll output", |
| 898 |
tmpsize); |
| 899 |
|
| 900 |
tmp[used++] = '{'; |
| 901 |
for (i = 0; i < numfds; i++) { |
| 902 |
|
| 903 |
u = snprintf(tmp + used, per_fd, "%s%d/%s", |
| 904 |
i > 0 ? " " : "", pfd[i].fd, |
| 905 |
xlookup_bits(poll_flags, pfd[i].events)); |
| 906 |
if (u > 0) |
| 907 |
used += u < per_fd ? u : per_fd; |
| 908 |
} |
| 909 |
tmp[used++] = '}'; |
| 910 |
tmp[used++] = '\0'; |
| 911 |
} else { |
| 912 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 913 |
} |
| 914 |
free(pfd); |
| 915 |
break; |
| 916 |
} |
| 917 |
case Fd_set: { |
| 918 |
/* |
| 919 |
* XXX: A Fd_set argument expects the /first/ syscall argument |
| 920 |
* to be the number of fds in the array. This matches the |
| 921 |
* select syscall. |
| 922 |
*/ |
| 923 |
fd_set *fds; |
| 924 |
int numfds = args[0]; |
| 925 |
int bytes = _howmany(numfds, _NFDBITS) * _NFDBITS; |
| 926 |
int i, tmpsize, u, used; |
| 927 |
const int per_fd = 20; |
| 928 |
|
| 929 |
if ((fds = malloc(bytes)) == NULL) |
| 930 |
err(1, "Cannot malloc %d bytes for fd_set array", |
| 931 |
bytes); |
| 932 |
if (get_struct(pid, (void *)args[sc->offset], fds, bytes) |
| 933 |
!= -1) { |
| 934 |
used = 0; |
| 935 |
tmpsize = 1 + numfds * per_fd + 2; |
| 936 |
if ((tmp = malloc(tmpsize)) == NULL) |
| 937 |
err(1, "Cannot alloc %d bytes for fd_set " |
| 938 |
"output", tmpsize); |
| 939 |
|
| 940 |
tmp[used++] = '{'; |
| 941 |
for (i = 0; i < numfds; i++) { |
| 942 |
if (FD_ISSET(i, fds)) { |
| 943 |
u = snprintf(tmp + used, per_fd, "%d ", |
| 944 |
i); |
| 945 |
if (u > 0) |
| 946 |
used += u < per_fd ? u : per_fd; |
| 947 |
} |
| 948 |
} |
| 949 |
if (tmp[used-1] == ' ') |
| 950 |
used--; |
| 951 |
tmp[used++] = '}'; |
| 952 |
tmp[used++] = '\0'; |
| 953 |
} else |
| 954 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 955 |
free(fds); |
| 956 |
break; |
| 957 |
} |
| 958 |
case Signal: |
| 959 |
tmp = strsig2(args[sc->offset]); |
| 960 |
break; |
| 961 |
case Sigset: { |
| 962 |
long sig; |
| 963 |
sigset_t ss; |
| 964 |
int i, used; |
| 965 |
char *signame; |
| 966 |
|
| 967 |
sig = args[sc->offset]; |
| 968 |
if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, |
| 969 |
sizeof(ss)) == -1) { |
| 970 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 971 |
break; |
| 972 |
} |
| 973 |
tmp = malloc(sys_nsig * 8); /* 7 bytes avg per signal name */ |
| 974 |
used = 0; |
| 975 |
for (i = 1; i < sys_nsig; i++) { |
| 976 |
if (sigismember(&ss, i)) { |
| 977 |
signame = strsig(i); |
| 978 |
used += sprintf(tmp + used, "%s|", signame); |
| 979 |
free(signame); |
| 980 |
} |
| 981 |
} |
| 982 |
if (used) |
| 983 |
tmp[used-1] = 0; |
| 984 |
else |
| 985 |
strcpy(tmp, "0x0"); |
| 986 |
break; |
| 987 |
} |
| 988 |
case Sigprocmask: { |
| 989 |
switch (args[sc->offset]) { |
| 990 |
#define S(a) case a: tmp = strdup(#a); break; |
| 991 |
S(SIG_BLOCK); |
| 992 |
S(SIG_UNBLOCK); |
| 993 |
S(SIG_SETMASK); |
| 994 |
#undef S |
| 995 |
} |
| 996 |
if (tmp == NULL) |
| 997 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 998 |
break; |
| 999 |
} |
| 1000 |
case Fcntlflag: { |
| 1001 |
/* XXX output depends on the value of the previous argument */ |
| 1002 |
switch (args[sc->offset-1]) { |
| 1003 |
case F_SETFD: |
| 1004 |
tmp = strdup(xlookup_bits(fcntlfd_arg, |
| 1005 |
args[sc->offset])); |
| 1006 |
break; |
| 1007 |
case F_SETFL: |
| 1008 |
tmp = strdup(xlookup_bits(fcntlfl_arg, |
| 1009 |
args[sc->offset])); |
| 1010 |
break; |
| 1011 |
case F_GETFD: |
| 1012 |
case F_GETFL: |
| 1013 |
case F_GETOWN: |
| 1014 |
tmp = strdup(""); |
| 1015 |
break; |
| 1016 |
default: |
| 1017 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 1018 |
break; |
| 1019 |
} |
| 1020 |
break; |
| 1021 |
} |
| 1022 |
case Open: |
| 1023 |
tmp = strdup(xlookup_bits(open_flags, args[sc->offset])); |
| 1024 |
break; |
| 1025 |
case Fcntl: |
| 1026 |
tmp = strdup(xlookup(fcntl_arg, args[sc->offset])); |
| 1027 |
break; |
| 1028 |
case Mprot: |
| 1029 |
tmp = strdup(xlookup_bits(mprot_flags, args[sc->offset])); |
| 1030 |
break; |
| 1031 |
case Mmapflags: { |
| 1032 |
char *base, *alignstr; |
| 1033 |
int align, flags; |
| 1034 |
|
| 1035 |
/* |
| 1036 |
* MAP_ALIGNED can't be handled by xlookup_bits(), so |
| 1037 |
* generate that string manually and prepend it to the |
| 1038 |
* string from xlookup_bits(). Have to be careful to |
| 1039 |
* avoid outputting MAP_ALIGNED|0 if MAP_ALIGNED is |
| 1040 |
* the only flag. |
| 1041 |
*/ |
| 1042 |
flags = args[sc->offset] & ~MAP_ALIGNMENT_MASK; |
| 1043 |
align = args[sc->offset] & MAP_ALIGNMENT_MASK; |
| 1044 |
if (align != 0) { |
| 1045 |
if (align == MAP_ALIGNED_SUPER) |
| 1046 |
alignstr = strdup("MAP_ALIGNED_SUPER"); |
| 1047 |
else |
| 1048 |
asprintf(&alignstr, "MAP_ALIGNED(%d)", |
| 1049 |
align >> MAP_ALIGNMENT_SHIFT); |
| 1050 |
if (flags == 0) { |
| 1051 |
tmp = alignstr; |
| 1052 |
break; |
| 1053 |
} |
| 1054 |
} else |
| 1055 |
alignstr = NULL; |
| 1056 |
base = strdup(xlookup_bits(mmap_flags, flags)); |
| 1057 |
if (alignstr == NULL) { |
| 1058 |
tmp = base; |
| 1059 |
break; |
| 1060 |
} |
| 1061 |
asprintf(&tmp, "%s|%s", alignstr, base); |
| 1062 |
free(alignstr); |
| 1063 |
free(base); |
| 1064 |
break; |
| 1065 |
} |
| 1066 |
case Whence: |
| 1067 |
tmp = strdup(xlookup(whence_arg, args[sc->offset])); |
| 1068 |
break; |
| 1069 |
case Sockdomain: |
| 1070 |
tmp = strdup(xlookup(sockdomain_arg, args[sc->offset])); |
| 1071 |
break; |
| 1072 |
case Socktype: |
| 1073 |
tmp = strdup(xlookup(socktype_arg, args[sc->offset])); |
| 1074 |
break; |
| 1075 |
case Shutdown: |
| 1076 |
tmp = strdup(xlookup(shutdown_arg, args[sc->offset])); |
| 1077 |
break; |
| 1078 |
case Resource: |
| 1079 |
tmp = strdup(xlookup(resource_arg, args[sc->offset])); |
| 1080 |
break; |
| 1081 |
case Pathconf: |
| 1082 |
tmp = strdup(xlookup(pathconf_arg, args[sc->offset])); |
| 1083 |
break; |
| 1084 |
case Rforkflags: |
| 1085 |
tmp = strdup(xlookup_bits(rfork_flags, args[sc->offset])); |
| 1086 |
break; |
| 1087 |
case Sockaddr: { |
| 1088 |
struct sockaddr_storage ss; |
| 1089 |
char addr[64]; |
| 1090 |
struct sockaddr_in *lsin; |
| 1091 |
struct sockaddr_in6 *lsin6; |
| 1092 |
struct sockaddr_un *sun; |
| 1093 |
struct sockaddr *sa; |
| 1094 |
char *p; |
| 1095 |
u_char *q; |
| 1096 |
int i; |
| 1097 |
|
| 1098 |
if (args[sc->offset] == 0) { |
| 1099 |
asprintf(&tmp, "NULL"); |
| 1100 |
break; |
| 1101 |
} |
| 1102 |
|
| 1103 |
/* yuck: get ss_len */ |
| 1104 |
if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, |
| 1105 |
sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1) |
| 1106 |
err(1, "get_struct %p", (void *)args[sc->offset]); |
| 1107 |
/* |
| 1108 |
* If ss_len is 0, then try to guess from the sockaddr type. |
| 1109 |
* AF_UNIX may be initialized incorrectly, so always frob |
| 1110 |
* it by using the "right" size. |
| 1111 |
*/ |
| 1112 |
if (ss.ss_len == 0 || ss.ss_family == AF_UNIX) { |
| 1113 |
switch (ss.ss_family) { |
| 1114 |
case AF_INET: |
| 1115 |
ss.ss_len = sizeof(*lsin); |
| 1116 |
break; |
| 1117 |
case AF_UNIX: |
| 1118 |
ss.ss_len = sizeof(*sun); |
| 1119 |
break; |
| 1120 |
default: |
| 1121 |
/* hurrrr */ |
| 1122 |
break; |
| 1123 |
} |
| 1124 |
} |
| 1125 |
if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, |
| 1126 |
ss.ss_len) == -1) { |
| 1127 |
err(2, "get_struct %p", (void *)args[sc->offset]); |
| 1128 |
} |
| 1129 |
|
| 1130 |
switch (ss.ss_family) { |
| 1131 |
case AF_INET: |
| 1132 |
lsin = (struct sockaddr_in *)&ss; |
| 1133 |
inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof addr); |
| 1134 |
asprintf(&tmp, "{ AF_INET %s:%d }", addr, |
| 1135 |
htons(lsin->sin_port)); |
| 1136 |
break; |
| 1137 |
case AF_INET6: |
| 1138 |
lsin6 = (struct sockaddr_in6 *)&ss; |
| 1139 |
inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, |
| 1140 |
sizeof addr); |
| 1141 |
asprintf(&tmp, "{ AF_INET6 [%s]:%d }", addr, |
| 1142 |
htons(lsin6->sin6_port)); |
| 1143 |
break; |
| 1144 |
case AF_UNIX: |
| 1145 |
sun = (struct sockaddr_un *)&ss; |
| 1146 |
asprintf(&tmp, "{ AF_UNIX \"%s\" }", sun->sun_path); |
| 1147 |
break; |
| 1148 |
default: |
| 1149 |
sa = (struct sockaddr *)&ss; |
| 1150 |
asprintf(&tmp, "{ sa_len = %d, sa_family = %d, sa_data " |
| 1151 |
"= {%n%*s } }", (int)sa->sa_len, (int)sa->sa_family, |
| 1152 |
&i, 6 * (int)(sa->sa_len - ((char *)&sa->sa_data - |
| 1153 |
(char *)sa)), ""); |
| 1154 |
if (tmp != NULL) { |
| 1155 |
p = tmp + i; |
| 1156 |
for (q = (u_char *)&sa->sa_data; |
| 1157 |
q < (u_char *)sa + sa->sa_len; q++) |
| 1158 |
p += sprintf(p, " %#02x,", *q); |
| 1159 |
} |
| 1160 |
} |
| 1161 |
break; |
| 1162 |
} |
| 1163 |
case Sigaction: { |
| 1164 |
struct sigaction sa; |
| 1165 |
char *hand; |
| 1166 |
const char *h; |
| 1167 |
|
| 1168 |
if (get_struct(pid, (void *)args[sc->offset], &sa, sizeof(sa)) |
| 1169 |
!= -1) { |
| 1170 |
asprintf(&hand, "%p", sa.sa_handler); |
| 1171 |
if (sa.sa_handler == SIG_DFL) |
| 1172 |
h = "SIG_DFL"; |
| 1173 |
else if (sa.sa_handler == SIG_IGN) |
| 1174 |
h = "SIG_IGN"; |
| 1175 |
else |
| 1176 |
h = hand; |
| 1177 |
|
| 1178 |
asprintf(&tmp, "{ %s %s ss_t }", h, |
| 1179 |
xlookup_bits(sigaction_flags, sa.sa_flags)); |
| 1180 |
free(hand); |
| 1181 |
} else |
| 1182 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 1183 |
break; |
| 1184 |
} |
| 1185 |
case Kevent: { |
| 1186 |
/* |
| 1187 |
* XXX XXX: the size of the array is determined by either the |
| 1188 |
* next syscall argument, or by the syscall returnvalue, |
| 1189 |
* depending on which argument number we are. This matches the |
| 1190 |
* kevent syscall, but luckily that's the only syscall that uses |
| 1191 |
* them. |
| 1192 |
*/ |
| 1193 |
struct kevent *ke; |
| 1194 |
int numevents = -1; |
| 1195 |
int bytes = 0; |
| 1196 |
int i, tmpsize, u, used; |
| 1197 |
const int per_ke = 100; |
| 1198 |
|
| 1199 |
if (sc->offset == 1) |
| 1200 |
numevents = args[sc->offset+1]; |
| 1201 |
else if (sc->offset == 3 && retval != -1) |
| 1202 |
numevents = retval; |
| 1203 |
|
| 1204 |
if (numevents >= 0) |
| 1205 |
bytes = sizeof(struct kevent) * numevents; |
| 1206 |
if ((ke = malloc(bytes)) == NULL) |
| 1207 |
err(1, "Cannot malloc %d bytes for kevent array", |
| 1208 |
bytes); |
| 1209 |
if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset], |
| 1210 |
ke, bytes) != -1) { |
| 1211 |
used = 0; |
| 1212 |
tmpsize = 1 + per_ke * numevents + 2; |
| 1213 |
if ((tmp = malloc(tmpsize)) == NULL) |
| 1214 |
err(1, "Cannot alloc %d bytes for kevent " |
| 1215 |
"output", tmpsize); |
| 1216 |
|
| 1217 |
tmp[used++] = '{'; |
| 1218 |
for (i = 0; i < numevents; i++) { |
| 1219 |
u = snprintf(tmp + used, per_ke, |
| 1220 |
"%s%p,%s,%s,%d,%p,%p", |
| 1221 |
i > 0 ? " " : "", |
| 1222 |
(void *)ke[i].ident, |
| 1223 |
xlookup(kevent_filters, ke[i].filter), |
| 1224 |
xlookup_bits(kevent_flags, ke[i].flags), |
| 1225 |
ke[i].fflags, |
| 1226 |
(void *)ke[i].data, |
| 1227 |
(void *)ke[i].udata); |
| 1228 |
if (u > 0) |
| 1229 |
used += u < per_ke ? u : per_ke; |
| 1230 |
} |
| 1231 |
tmp[used++] = '}'; |
| 1232 |
tmp[used++] = '\0'; |
| 1233 |
} else { |
| 1234 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 1235 |
} |
| 1236 |
free(ke); |
| 1237 |
break; |
| 1238 |
} |
| 1239 |
case Stat: { |
| 1240 |
struct stat st; |
| 1241 |
if (get_struct(pid, (void *)args[sc->offset], &st, sizeof(st)) |
| 1242 |
!= -1) { |
| 1243 |
char mode[12]; |
| 1244 |
strmode(st.st_mode, mode); |
| 1245 |
asprintf(&tmp, |
| 1246 |
"{ mode=%s,inode=%jd,size=%jd,blksize=%ld }", mode, |
| 1247 |
(intmax_t)st.st_ino, (intmax_t)st.st_size, |
| 1248 |
(long)st.st_blksize); |
| 1249 |
} else { |
| 1250 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 1251 |
} |
| 1252 |
break; |
| 1253 |
} |
| 1254 |
case Rusage: { |
| 1255 |
struct rusage ru; |
| 1256 |
if (get_struct(pid, (void *)args[sc->offset], &ru, sizeof(ru)) |
| 1257 |
!= -1) { |
| 1258 |
asprintf(&tmp, |
| 1259 |
"{ u=%ld.%06ld,s=%ld.%06ld,in=%ld,out=%ld }", |
| 1260 |
(long)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec, |
| 1261 |
(long)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec, |
| 1262 |
ru.ru_inblock, ru.ru_oublock); |
| 1263 |
} else |
| 1264 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 1265 |
break; |
| 1266 |
} |
| 1267 |
case Rlimit: { |
| 1268 |
struct rlimit rl; |
| 1269 |
if (get_struct(pid, (void *)args[sc->offset], &rl, sizeof(rl)) |
| 1270 |
!= -1) { |
| 1271 |
asprintf(&tmp, "{ cur=%ju,max=%ju }", |
| 1272 |
rl.rlim_cur, rl.rlim_max); |
| 1273 |
} else |
| 1274 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 1275 |
break; |
| 1276 |
} |
| 1277 |
case ExitStatus: { |
| 1278 |
char *signame; |
| 1279 |
int status; |
| 1280 |
signame = NULL; |
| 1281 |
if (get_struct(pid, (void *)args[sc->offset], &status, |
| 1282 |
sizeof(status)) != -1) { |
| 1283 |
if (WIFCONTINUED(status)) |
| 1284 |
tmp = strdup("{ CONTINUED }"); |
| 1285 |
else if (WIFEXITED(status)) |
| 1286 |
asprintf(&tmp, "{ EXITED,val=%d }", |
| 1287 |
WEXITSTATUS(status)); |
| 1288 |
else if (WIFSIGNALED(status)) |
| 1289 |
asprintf(&tmp, "{ SIGNALED,sig=%s%s }", |
| 1290 |
signame = strsig2(WTERMSIG(status)), |
| 1291 |
WCOREDUMP(status) ? ",cored" : ""); |
| 1292 |
else |
| 1293 |
asprintf(&tmp, "{ STOPPED,sig=%s }", |
| 1294 |
signame = strsig2(WTERMSIG(status))); |
| 1295 |
} else |
| 1296 |
asprintf(&tmp, "0x%lx", args[sc->offset]); |
| 1297 |
free(signame); |
| 1298 |
break; |
| 1299 |
} |
| 1300 |
case Waitoptions: |
| 1301 |
tmp = strdup(xlookup_bits(wait_options, args[sc->offset])); |
| 1302 |
break; |
| 1303 |
case Idtype: |
| 1304 |
tmp = strdup(xlookup(idtype_arg, args[sc->offset])); |
| 1305 |
break; |
| 1306 |
case Procctl: |
| 1307 |
tmp = strdup(xlookup(procctl_arg, args[sc->offset])); |
| 1308 |
break; |
| 1309 |
case Umtxop: |
| 1310 |
tmp = strdup(xlookup(umtx_ops, args[sc->offset])); |
| 1311 |
break; |
| 1312 |
default: |
| 1313 |
errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK); |
| 1314 |
} |
| 1315 |
return (tmp); |
| 1316 |
} |
| 1317 |
|
| 1318 |
/* |
| 1319 |
* print_syscall |
| 1320 |
* Print (to outfile) the system call and its arguments. Note that |
| 1321 |
* nargs is the number of arguments (not the number of words; this is |
| 1322 |
* potentially confusing, I know). |
| 1323 |
*/ |
| 1324 |
|
| 1325 |
void |
| 1326 |
print_syscall(struct trussinfo *trussinfo, const char *name, int nargs, |
| 1327 |
char **s_args) |
| 1328 |
{ |
| 1329 |
struct timespec timediff; |
| 1330 |
int i, len; |
| 1331 |
|
| 1332 |
len = 0; |
| 1333 |
if (trussinfo->flags & FOLLOWFORKS) |
| 1334 |
len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid); |
| 1335 |
|
| 1336 |
if (name != NULL && (strcmp(name, "execve") == 0 || |
| 1337 |
strcmp(name, "exit") == 0)) { |
| 1338 |
clock_gettime(CLOCK_REALTIME, &trussinfo->curthread->after); |
| 1339 |
} |
| 1340 |
|
| 1341 |
if (trussinfo->flags & ABSOLUTETIMESTAMPS) { |
| 1342 |
timespecsubt(&trussinfo->curthread->after, |
| 1343 |
&trussinfo->start_time, &timediff); |
| 1344 |
len += fprintf(trussinfo->outfile, "%ld.%09ld ", |
| 1345 |
(long)timediff.tv_sec, timediff.tv_nsec); |
| 1346 |
} |
| 1347 |
|
| 1348 |
if (trussinfo->flags & RELATIVETIMESTAMPS) { |
| 1349 |
timespecsubt(&trussinfo->curthread->after, |
| 1350 |
&trussinfo->curthread->before, &timediff); |
| 1351 |
len += fprintf(trussinfo->outfile, "%ld.%09ld ", |
| 1352 |
(long)timediff.tv_sec, timediff.tv_nsec); |
| 1353 |
} |
| 1354 |
|
| 1355 |
len += fprintf(trussinfo->outfile, "%s(", name); |
| 1356 |
|
| 1357 |
for (i = 0; i < nargs; i++) { |
| 1358 |
if (s_args[i]) |
| 1359 |
len += fprintf(trussinfo->outfile, "%s", s_args[i]); |
| 1360 |
else |
| 1361 |
len += fprintf(trussinfo->outfile, |
| 1362 |
"<missing argument>"); |
| 1363 |
len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? |
| 1364 |
"," : ""); |
| 1365 |
} |
| 1366 |
len += fprintf(trussinfo->outfile, ")"); |
| 1367 |
for (i = 0; i < 6 - (len / 8); i++) |
| 1368 |
fprintf(trussinfo->outfile, "\t"); |
| 1369 |
} |
| 1370 |
|
| 1371 |
void |
| 1372 |
print_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs, |
| 1373 |
char **s_args, int errorp, long retval, struct syscall *sc) |
| 1374 |
{ |
| 1375 |
struct timespec timediff; |
| 1376 |
|
| 1377 |
if (trussinfo->flags & COUNTONLY) { |
| 1378 |
if (!sc) |
| 1379 |
return; |
| 1380 |
clock_gettime(CLOCK_REALTIME, &trussinfo->curthread->after); |
| 1381 |
timespecsubt(&trussinfo->curthread->after, |
| 1382 |
&trussinfo->curthread->before, &timediff); |
| 1383 |
timespecadd(&sc->time, &timediff, &sc->time); |
| 1384 |
sc->ncalls++; |
| 1385 |
if (errorp) |
| 1386 |
sc->nerror++; |
| 1387 |
return; |
| 1388 |
} |
| 1389 |
|
| 1390 |
print_syscall(trussinfo, name, nargs, s_args); |
| 1391 |
fflush(trussinfo->outfile); |
| 1392 |
if (errorp) |
| 1393 |
fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval, |
| 1394 |
strerror(retval)); |
| 1395 |
else { |
| 1396 |
/* |
| 1397 |
* Because pipe(2) has a special assembly glue to provide the |
| 1398 |
* libc API, we have to adjust retval. |
| 1399 |
*/ |
| 1400 |
if (name != NULL && strcmp(name, "pipe") == 0) |
| 1401 |
retval = 0; |
| 1402 |
fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval, retval); |
| 1403 |
} |
| 1404 |
} |
| 1405 |
|
| 1406 |
void |
| 1407 |
print_summary(struct trussinfo *trussinfo) |
| 1408 |
{ |
| 1409 |
struct timespec total = {0, 0}; |
| 1410 |
struct syscall *sc; |
| 1411 |
int ncall, nerror; |
| 1412 |
|
| 1413 |
fprintf(trussinfo->outfile, "%-20s%15s%8s%8s\n", |
| 1414 |
"syscall", "seconds", "calls", "errors"); |
| 1415 |
ncall = nerror = 0; |
| 1416 |
for (sc = syscalls; sc->name != NULL; sc++) |
| 1417 |
if (sc->ncalls) { |
| 1418 |
fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", |
| 1419 |
sc->name, (intmax_t)sc->time.tv_sec, |
| 1420 |
sc->time.tv_nsec, sc->ncalls, sc->nerror); |
| 1421 |
timespecadd(&total, &sc->time, &total); |
| 1422 |
ncall += sc->ncalls; |
| 1423 |
nerror += sc->nerror; |
| 1424 |
} |
| 1425 |
fprintf(trussinfo->outfile, "%20s%15s%8s%8s\n", |
| 1426 |
"", "-------------", "-------", "-------"); |
| 1427 |
fprintf(trussinfo->outfile, "%-20s%5jd.%09ld%8d%8d\n", |
| 1428 |
"", (intmax_t)total.tv_sec, total.tv_nsec, ncall, nerror); |
| 1429 |
} |