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