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