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/socket.h> 45 #include <sys/time.h> 46 #include <sys/un.h> 47 #include <netinet/in.h> 48 #include <arpa/inet.h> 49 50 #include <ctype.h> 51 #include <err.h> 52 #include <fcntl.h> 53 #include <poll.h> 54 #include <signal.h> 55 #include <stdint.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <time.h> 60 #include <unistd.h> 61 62 #include "truss.h" 63 #include "extern.h" 64 #include "syscall.h" 65 66 /* 67 * This should probably be in its own file. 68 */ 69 70 struct syscall syscalls[] = { 71 { "fcntl", 1, 3, 72 { { Int, 0 } , { Fcntl, 1 }, { Hex, 2 }}}, 73 { "readlink", 1, 3, 74 { { String, 0 } , { Readlinkres | OUT, 1 }, { Int, 2 }}}, 75 { "lseek", 2, 3, 76 #ifdef __LP64__ 77 { { Int, 0 }, {Quad, 2 }, { Whence, 3 }}}, 78 #else 79 { { Int, 0 }, {Quad, 2 }, { Whence, 4 }}}, 80 #endif 81 { "linux_lseek", 2, 3, 82 { { Int, 0 }, {Int, 1 }, { Whence, 2 }}}, 83 { "mmap", 2, 6, 84 #ifdef __LP64__ 85 { { Ptr, 0 }, {Int, 1}, {Mprot, 2}, {Mmapflags, 3}, {Int, 4}, {Quad, 5}}}, 86 #else 87 { { Ptr, 0 }, {Int, 1}, {Mprot, 2}, {Mmapflags, 3}, {Int, 4}, {Quad, 6}}}, 88 #endif 89 { "mprotect", 1, 3, 90 { { Ptr, 0 }, {Int, 1}, {Mprot, 2}}}, 91 { "open", 1, 3, 92 { { String | IN, 0} , { Hex, 1}, {Octal, 2}}}, 93 { "mkdir", 1, 2, 94 { { String, 0} , {Octal, 1}}}, 95 { "linux_open", 1, 3, 96 { { String, 0 }, { Hex, 1}, { Octal, 2 }}}, 97 { "close", 1, 1, 98 { { Int, 0 } } }, 99 { "link", 0, 2, 100 { { String, 0 }, { String, 1 }}}, 101 { "unlink", 0, 1, 102 { { String, 0 }}}, 103 { "chdir", 0, 1, 104 { { String, 0 }}}, 105 { "chroot", 0, 1, 106 { { String, 0 }}}, 107 { "mknod", 0, 3, 108 { { String, 0 }, { Octal, 1 }, { Int, 3 }}}, 109 { "chmod", 0, 2, 110 { { String, 0 }, { Octal, 1 }}}, 111 { "chown", 0, 3, 112 { { String, 0 }, { Int, 1 }, { Int, 2 }}}, 113 { "mount", 0, 4, 114 { { String, 0 }, { String, 1 }, { Int, 2 }, { Ptr, 3 }}}, 115 { "umount", 0, 2, 116 { { String, 0 }, { Int, 2 }}}, 117 { "fstat", 1, 2, 118 { { Int, 0}, {Ptr | OUT , 1 }}}, 119 { "stat", 1, 2, 120 { { String | IN, 0 }, { Ptr | OUT, 1 }}}, 121 { "lstat", 1, 2, 122 { { String | IN, 0 }, { Ptr | OUT, 1 }}}, 123 { "linux_newstat", 1, 2, 124 { { String | IN, 0 }, { Ptr | OUT, 1 }}}, 125 { "linux_newfstat", 1, 2, 126 { { Int, 0 }, { Ptr | OUT, 1 }}}, 127 { "write", 1, 3, 128 { { Int, 0 }, { Ptr | IN, 1 }, { Int, 2 }}}, 129 { "ioctl", 1, 3, 130 { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 }}}, 131 { "break", 1, 1, { { Hex, 0 }}}, 132 { "exit", 0, 1, { { Hex, 0 }}}, 133 { "access", 1, 2, { { String | IN, 0 }, { Int, 1 }}}, 134 { "sigaction", 1, 3, 135 { { Signal, 0 }, { Sigaction | IN, 1 }, { Sigaction | OUT, 2 }}}, 136 { "accept", 1, 3, 137 { { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 138 { "bind", 1, 3, 139 { { Hex, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, 140 { "connect", 1, 3, 141 { { Hex, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, 142 { "getpeername", 1, 3, 143 { { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 144 { "getsockname", 1, 3, 145 { { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 146 { "recvfrom", 1, 6, 147 { { Hex, 0 }, { Ptr | IN, 1 }, { Int, 3 }, { Hex, 3 }, { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } }, 148 { "sendto", 1, 6, 149 { { Hex, 0 }, { Ptr | IN, 1 }, { Int, 3 }, { Hex, 3 }, { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } }, 150 { "execve", 1, 3, 151 { { String | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } }, 152 { "linux_execve", 1, 3, 153 { { String | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } }, 154 { "kldload", 0, 1, { { String | IN, 0 }}}, 155 { "kldunload", 0, 1, { { Int, 0 }}}, 156 { "kldfind", 0, 1, { { String | IN, 0 }}}, 157 { "kldnext", 0, 1, { { Int, 0 }}}, 158 { "kldstat", 0, 2, { { Int, 0 }, { Ptr, 1 }}}, 159 { "kldfirstmod", 0, 1, { { Int, 0 }}}, 160 { "nanosleep", 0, 1, { { Timespec, 0 }}}, 161 { "select", 1, 5, { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, { Timeval, 4 }}}, 162 { "poll", 1, 3, { { Pollfd, 0 }, { Int, 1 }, { Int, 2 }}}, 163 { "gettimeofday", 1, 2, { { Timeval | OUT, 0 }, { Ptr, 1 }}}, 164 { "clock_gettime", 1, 2, { { Int, 0 }, { Timeval | OUT, 1 }}}, 165 { "recvfrom", 1, 6, { { Int, 0 }, { Ptr | OUT, 1 }, { Int, 2 }, { Int, 3 }, { Sockaddr | OUT, 4}, {Ptr | OUT, 5}}}, 166 { "getitimer", 1, 2, { { Int, 0 }, { Itimerval | OUT, 2 }}}, 167 { "setitimer", 1, 3, { { Int, 0 }, { Itimerval, 1} , { Itimerval | OUT, 2 }}}, 168 { "utimes", 1, 2, 169 { { String | IN, 0 }, { Timeval | IN, 1 }}}, 170 { "lutimes", 1, 2, 171 { { String | IN, 0 }, { Timeval | IN, 1 }}}, 172 { "futimes", 1, 2, 173 { { Int, 0 }, { Timeval | IN, 1 }}}, 174 { "chflags", 1, 2, 175 { { String | IN, 0 }, { Hex, 1 }}}, 176 { "lchflags", 1, 2, 177 { { String | IN, 0 }, { Hex, 1 }}}, 178 { 0, 0, 0, { { 0, 0 }}}, 179 }; 180 181 /* 182 * If/when the list gets big, it might be desirable to do it 183 * as a hash table or binary search. 184 */ 185 186 struct syscall * 187 get_syscall(const char *name) { 188 struct syscall *sc = syscalls; 189 190 if (name == NULL) 191 return (NULL); 192 while (sc->name) { 193 if (!strcmp(name, sc->name)) 194 return sc; 195 sc++; 196 } 197 return NULL; 198 } 199 200 /* 201 * get_struct 202 * 203 * Copy a fixed amount of bytes from the process. 204 */ 205 206 static int 207 get_struct(int procfd, void *offset, void *buf, int len) { 208 209 if (pread(procfd, buf, len, (uintptr_t)offset) != len) 210 return -1; 211 return 0; 212 } 213 214 /* 215 * get_string 216 * Copy a string from the process. Note that it is 217 * expected to be a C string, but if max is set, it will 218 * only get that much. 219 */ 220 221 char * 222 get_string(int procfd, void *offset, int max) { 223 char *buf; 224 int size, len, c, fd; 225 FILE *p; 226 227 if ((fd = dup(procfd)) == -1) 228 err(1, "dup"); 229 if ((p = fdopen(fd, "r")) == NULL) 230 err(1, "fdopen"); 231 buf = malloc( size = (max ? max : 64 ) ); 232 len = 0; 233 buf[0] = 0; 234 if (fseeko(p, (uintptr_t)offset, SEEK_SET) == 0) { 235 while ((c = fgetc(p)) != EOF) { 236 buf[len++] = c; 237 if (c == 0 || len == max) { 238 buf[len] = 0; 239 break; 240 } 241 if (len == size) { 242 char *tmp; 243 tmp = realloc(buf, size+64); 244 if (tmp == NULL) { 245 buf[len] = 0; 246 break; 247 } 248 size += 64; 249 buf = tmp; 250 } 251 } 252 } 253 fclose(p); 254 return (buf); 255 } 256 257 258 /* 259 * Remove a trailing '|' in a string, useful for fixup after decoding 260 * a "flags" argument. 261 */ 262 263 void 264 remove_trailing_or(char *str) 265 { 266 267 if (str != NULL && (str = rindex(str, '|')) != NULL && str[1] == '\0') 268 *str = '\0'; 269 } 270 271 /* 272 * print_arg 273 * Converts a syscall argument into a string. Said string is 274 * allocated via malloc(), so needs to be free()'d. The file 275 * descriptor is for the process' memory (via /proc), and is used 276 * to get any data (where the argument is a pointer). sc is 277 * a pointer to the syscall description (see above); args is 278 * an array of all of the system call arguments. 279 */ 280 281 char * 282 print_arg(int fd, struct syscall_args *sc, unsigned long *args, long retval) { 283 char *tmp = NULL; 284 switch (sc->type & ARG_MASK) { 285 case Hex: 286 asprintf(&tmp, "0x%lx", args[sc->offset]); 287 break; 288 case Octal: 289 asprintf(&tmp, "0%lo", args[sc->offset]); 290 break; 291 case Int: 292 asprintf(&tmp, "%ld", args[sc->offset]); 293 break; 294 case String: 295 { 296 char *tmp2; 297 tmp2 = get_string(fd, (void*)args[sc->offset], 0); 298 asprintf(&tmp, "\"%s\"", tmp2); 299 free(tmp2); 300 } 301 break; 302 case StringArray: 303 { 304 int num, size, i; 305 char *tmp2; 306 char *string; 307 char *strarray[100]; /* XXX This is ugly. */ 308 309 if (get_struct(fd, (void *)args[sc->offset], (void *)&strarray, 310 sizeof(strarray)) == -1) { 311 err(1, "get_struct %p", (void *)args[sc->offset]); 312 } 313 num = 0; 314 size = 0; 315 316 /* Find out how large of a buffer we'll need. */ 317 while (strarray[num] != NULL) { 318 string = get_string(fd, (void*)strarray[num], 0); 319 size += strlen(string); 320 free(string); 321 num++; 322 } 323 size += 4 + (num * 4); 324 tmp = (char *)malloc(size); 325 tmp2 = tmp; 326 327 tmp2 += sprintf(tmp2, " ["); 328 for (i = 0; i < num; i++) { 329 string = get_string(fd, (void*)strarray[i], 0); 330 tmp2 += sprintf(tmp2, " \"%s\"%c", string, (i+1 == num) ? ' ' : ','); 331 free(string); 332 } 333 tmp2 += sprintf(tmp2, "]"); 334 } 335 break; 336 #ifdef __LP64__ 337 case Quad: 338 asprintf(&tmp, "0x%lx", args[sc->offset]); 339 break; 340 #else 341 case Quad: 342 { 343 unsigned long long ll; 344 ll = *(unsigned long long *)(args + sc->offset); 345 asprintf(&tmp, "0x%llx", ll); 346 break; 347 } 348 #endif 349 case Ptr: 350 asprintf(&tmp, "0x%lx", args[sc->offset]); 351 break; 352 case Readlinkres: 353 { 354 char *tmp2; 355 if (retval == -1) { 356 tmp = strdup(""); 357 break; 358 } 359 tmp2 = get_string(fd, (void*)args[sc->offset], retval); 360 asprintf(&tmp, "\"%s\"", tmp2); 361 free(tmp2); 362 } 363 break; 364 case Ioctl: 365 { 366 const char *temp = ioctlname(args[sc->offset]); 367 if (temp) 368 tmp = strdup(temp); 369 else 370 asprintf(&tmp, "0x%lx", args[sc->offset]); 371 } 372 break; 373 case Timespec: 374 { 375 struct timespec ts; 376 if (get_struct(fd, (void *)args[sc->offset], &ts, sizeof(ts)) != -1) 377 asprintf(&tmp, "{%jd %jd}", (intmax_t)ts.tv_sec, (intmax_t)ts.tv_nsec); 378 else 379 asprintf(&tmp, "0x%lx", args[sc->offset]); 380 } 381 break; 382 case Timeval: 383 { 384 struct timeval tv; 385 if (get_struct(fd, (void *)args[sc->offset], &tv, sizeof(tv)) != -1) 386 asprintf(&tmp, "{%jd %jd}", (intmax_t)tv.tv_sec, (intmax_t)tv.tv_usec); 387 else 388 asprintf(&tmp, "0x%lx", args[sc->offset]); 389 } 390 break; 391 case Itimerval: 392 { 393 struct itimerval itv; 394 if (get_struct(fd, (void *)args[sc->offset], &itv, sizeof(itv)) != -1) 395 asprintf(&tmp, "{%jd %jd, %jd %jd}", 396 (intmax_t)itv.it_interval.tv_sec, 397 (intmax_t)itv.it_interval.tv_usec, 398 (intmax_t)itv.it_value.tv_sec, 399 (intmax_t)itv.it_value.tv_usec); 400 else 401 asprintf(&tmp, "0x%lx", args[sc->offset]); 402 } 403 break; 404 case Pollfd: 405 { 406 /* 407 * XXX: A Pollfd argument expects the /next/ syscall argument to be 408 * the number of fds in the array. This matches the poll syscall. 409 */ 410 struct pollfd *pfd; 411 int numfds = args[sc->offset+1]; 412 int bytes = sizeof(struct pollfd) * numfds; 413 int i, tmpsize, u, used; 414 const int per_fd = 100; 415 416 if ((pfd = malloc(bytes)) == NULL) 417 err(1, "Cannot malloc %d bytes for pollfd array", bytes); 418 if (get_struct(fd, (void *)args[sc->offset], pfd, bytes) != -1) { 419 420 used = 0; 421 tmpsize = 1 + per_fd * numfds + 2; 422 if ((tmp = malloc(tmpsize)) == NULL) 423 err(1, "Cannot alloc %d bytes for poll output", tmpsize); 424 425 tmp[used++] = '{'; 426 for (i = 0; i < numfds; i++) { 427 #define POLLKNOWN_EVENTS \ 428 (POLLIN | POLLPRI | POLLOUT | POLLERR | POLLHUP | POLLNVAL | \ 429 POLLRDNORM |POLLRDBAND | POLLWRBAND | POLLINIGNEOF) 430 431 u = snprintf(tmp + used, per_fd, 432 "%s%d 0x%hx%s%s%s%s%s%s%s%s%s ", 433 i > 0 ? " " : "", 434 pfd[i].fd, 435 pfd[i].events & ~POLLKNOWN_EVENTS, 436 pfd[i].events & POLLIN ? "" : "|IN", 437 pfd[i].events & POLLPRI ? "" : "|PRI", 438 pfd[i].events & POLLOUT ? "" : "|OUT", 439 pfd[i].events & POLLERR ? "" : "|ERR", 440 pfd[i].events & POLLHUP ? "" : "|HUP", 441 pfd[i].events & POLLNVAL ? "" : "|NVAL", 442 pfd[i].events & POLLRDNORM ? "" : "|RDNORM", 443 pfd[i].events & POLLRDBAND ? "" : "|RDBAND", 444 pfd[i].events & POLLWRBAND ? "" : "|WRBAND"); 445 if (u > 0) 446 used += u < per_fd ? u : per_fd; 447 } 448 tmp[used++] = '}'; 449 tmp[used++] = '\0'; 450 } else 451 asprintf(&tmp, "0x%lx", args[sc->offset]); 452 free(pfd); 453 } 454 break; 455 case Fd_set: 456 { 457 /* 458 * XXX: A Fd_set argument expects the /first/ syscall argument to be 459 * the number of fds in the array. This matches the select syscall. 460 */ 461 fd_set *fds; 462 int numfds = args[0]; 463 int bytes = _howmany(numfds, _NFDBITS) * _NFDBITS; 464 int i, tmpsize, u, used; 465 const int per_fd = 20; 466 467 if ((fds = malloc(bytes)) == NULL) 468 err(1, "Cannot malloc %d bytes for fd_set array", bytes); 469 if (get_struct(fd, (void *)args[sc->offset], fds, bytes) != -1) { 470 used = 0; 471 tmpsize = 1 + numfds * per_fd + 2; 472 if ((tmp = malloc(tmpsize)) == NULL) 473 err(1, "Cannot alloc %d bytes for fd_set output", tmpsize); 474 475 tmp[used++] = '{'; 476 for (i = 0; i < numfds; i++) { 477 if (FD_ISSET(i, fds)) { 478 u = snprintf(tmp + used, per_fd, "%d ", i); 479 if (u > 0) 480 used += u < per_fd ? u : per_fd; 481 } 482 } 483 if (tmp[used-1] == ' ') 484 used--; 485 tmp[used++] = '}'; 486 tmp[used++] = '\0'; 487 } else 488 asprintf(&tmp, "0x%lx", args[sc->offset]); 489 free(fds); 490 } 491 break; 492 case Signal: 493 { 494 long sig; 495 496 sig = args[sc->offset]; 497 tmp = strsig(sig); 498 if (tmp == NULL) 499 asprintf(&tmp, "%ld", sig); 500 } 501 break; 502 case Fcntl: 503 { 504 switch (args[sc->offset]) { 505 #define S(a) case a: tmp = strdup(#a); break; 506 S(F_DUPFD); 507 S(F_GETFD); 508 S(F_SETFD); 509 S(F_GETFL); 510 S(F_SETFL); 511 S(F_GETOWN); 512 S(F_SETOWN); 513 S(F_GETLK); 514 S(F_SETLK); 515 S(F_SETLKW); 516 #undef S 517 } 518 if (tmp == NULL) 519 asprintf(&tmp, "0x%lx", args[sc->offset]); 520 } 521 break; 522 523 case Mprot: 524 { 525 526 #define S(a) ((args[sc->offset] & a) ? #a "|" : "") 527 asprintf(&tmp, "(0x%lx)%s%s%s%s", args[sc->offset], 528 S(PROT_NONE), S(PROT_READ), S(PROT_WRITE), S(PROT_EXEC)); 529 #undef S 530 remove_trailing_or(tmp); 531 532 } 533 break; 534 535 case Mmapflags: 536 { 537 #define S(a) ((args[sc->offset] & a) ? #a "|" : "") 538 asprintf(&tmp, "(0x%lx)%s%s%s%s%s%s%s%s", args[sc->offset], 539 S(MAP_ANON), S(MAP_FIXED), S(MAP_HASSEMAPHORE), 540 S(MAP_NOCORE), S(MAP_NOSYNC), S(MAP_PRIVATE), 541 S(MAP_SHARED), S(MAP_STACK)); 542 #undef S 543 544 remove_trailing_or(tmp); 545 } 546 break; 547 548 case Whence: 549 { 550 switch (args[sc->offset]) { 551 #define S(a) case a: tmp = strdup(#a); break; 552 S(SEEK_SET); 553 S(SEEK_CUR); 554 S(SEEK_END); 555 #undef S 556 default: asprintf(&tmp, "0x%lx", args[sc->offset]); break; 557 } 558 } 559 break; 560 case Sockaddr: 561 { 562 struct sockaddr_storage ss; 563 char addr[64]; 564 struct sockaddr_in *lsin; 565 struct sockaddr_in6 *lsin6; 566 struct sockaddr_un *sun; 567 struct sockaddr *sa; 568 char *p; 569 u_char *q; 570 int i; 571 572 if (args[sc->offset] == 0) { 573 asprintf(&tmp, "NULL"); 574 break; 575 } 576 577 /* yuck: get ss_len */ 578 if (get_struct(fd, (void *)args[sc->offset], (void *)&ss, 579 sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1) 580 err(1, "get_struct %p", (void *)args[sc->offset]); 581 /* 582 * If ss_len is 0, then try to guess from the sockaddr type. 583 * AF_UNIX may be initialized incorrectly, so always frob 584 * it by using the "right" size. 585 */ 586 if (ss.ss_len == 0 || ss.ss_family == AF_UNIX) { 587 switch (ss.ss_family) { 588 case AF_INET: 589 ss.ss_len = sizeof(*lsin); 590 break; 591 case AF_UNIX: 592 ss.ss_len = sizeof(*sun); 593 break; 594 default: 595 /* hurrrr */ 596 break; 597 } 598 } 599 if (get_struct(fd, (void *)args[sc->offset], (void *)&ss, ss.ss_len) 600 == -1) { 601 err(2, "get_struct %p", (void *)args[sc->offset]); 602 } 603 604 switch (ss.ss_family) { 605 case AF_INET: 606 lsin = (struct sockaddr_in *)&ss; 607 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof addr); 608 asprintf(&tmp, "{ AF_INET %s:%d }", addr, htons(lsin->sin_port)); 609 break; 610 case AF_INET6: 611 lsin6 = (struct sockaddr_in6 *)&ss; 612 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, sizeof addr); 613 asprintf(&tmp, "{ AF_INET6 [%s]:%d }", addr, htons(lsin6->sin6_port)); 614 break; 615 case AF_UNIX: 616 sun = (struct sockaddr_un *)&ss; 617 asprintf(&tmp, "{ AF_UNIX \"%s\" }", sun->sun_path); 618 break; 619 default: 620 sa = (struct sockaddr *)&ss; 621 asprintf(&tmp, "{ sa_len = %d, sa_family = %d, sa_data = {%n%*s } }", 622 (int)sa->sa_len, (int)sa->sa_family, &i, 623 6 * (int)(sa->sa_len - ((char *)&sa->sa_data - (char *)sa)), ""); 624 if (tmp != NULL) { 625 p = tmp + i; 626 for (q = (u_char *)&sa->sa_data; q < (u_char *)sa + sa->sa_len; q++) 627 p += sprintf(p, " %#02x,", *q); 628 } 629 } 630 } 631 break; 632 case Sigaction: 633 { 634 struct sigaction sa; 635 char *hand; 636 const char *h; 637 #define SA_KNOWN_FLAGS \ 638 (SA_ONSTACK | SA_RESTART | SA_RESETHAND | SA_NOCLDSTOP | SA_NODEFER | \ 639 SA_NOCLDWAIT | SA_SIGINFO) 640 641 642 if (get_struct(fd, (void *)args[sc->offset], &sa, sizeof(sa)) != -1) { 643 644 asprintf(&hand, "%p", sa.sa_handler); 645 if (sa.sa_handler == SIG_DFL) 646 h = "SIG_DFL"; 647 else if (sa.sa_handler == SIG_IGN) 648 h = "SIG_IGN"; 649 else 650 h = hand; 651 asprintf(&tmp, "{ %s 0x%x%s%s%s%s%s%s%s ss_t }", 652 h, 653 sa.sa_flags & ~SA_KNOWN_FLAGS, 654 sa.sa_flags & SA_ONSTACK ? "" : "|ONSTACK", 655 sa.sa_flags & SA_RESTART ? "" : "|RESTART", 656 sa.sa_flags & SA_RESETHAND ? "" : "|RESETHAND", 657 sa.sa_flags & SA_NOCLDSTOP ? "" : "|NOCLDSTOP", 658 sa.sa_flags & SA_NODEFER ? "" : "|NODEFER", 659 sa.sa_flags & SA_NOCLDWAIT ? "" : "|NOCLDWAIT", 660 sa.sa_flags & SA_SIGINFO ? "" : "|SIGINFO"); 661 free(hand); 662 } else 663 asprintf(&tmp, "0x%lx", args[sc->offset]); 664 665 } 666 break; 667 } 668 return tmp; 669 } 670 671 #define timespecsubt(tvp, uvp, vvp) \ 672 do { \ 673 (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ 674 (vvp)->tv_nsec = (tvp)->tv_nsec - (uvp)->tv_nsec; \ 675 if ((vvp)->tv_nsec < 0) { \ 676 (vvp)->tv_sec--; \ 677 (vvp)->tv_nsec += 1000000000; \ 678 } \ 679 } while (0) 680 681 /* 682 * print_syscall 683 * Print (to outfile) the system call and its arguments. Note that 684 * nargs is the number of arguments (not the number of words; this is 685 * potentially confusing, I know). 686 */ 687 688 void 689 print_syscall(struct trussinfo *trussinfo, const char *name, int nargs, char **s_args) { 690 int i; 691 int len = 0; 692 struct timespec timediff; 693 694 if (trussinfo->flags & FOLLOWFORKS) 695 len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid); 696 697 if (name != NULL && (!strcmp(name, "execve") || !strcmp(name, "exit"))) { 698 clock_gettime(CLOCK_REALTIME, &trussinfo->after); 699 } 700 701 if (trussinfo->flags & ABSOLUTETIMESTAMPS) { 702 timespecsubt(&trussinfo->after, &trussinfo->start_time, &timediff); 703 len += fprintf(trussinfo->outfile, "%ld.%09ld ", 704 (long)timediff.tv_sec, timediff.tv_nsec); 705 } 706 707 if (trussinfo->flags & RELATIVETIMESTAMPS) { 708 timespecsubt(&trussinfo->after, &trussinfo->before, &timediff); 709 len += fprintf(trussinfo->outfile, "%ld.%09ld ", 710 (long)timediff.tv_sec, timediff.tv_nsec); 711 } 712 713 len += fprintf(trussinfo->outfile, "%s(", name); 714 715 for (i = 0; i < nargs; i++) { 716 if (s_args[i]) 717 len += fprintf(trussinfo->outfile, "%s", s_args[i]); 718 else 719 len += fprintf(trussinfo->outfile, "<missing argument>"); 720 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? "," : ""); 721 } 722 len += fprintf(trussinfo->outfile, ")"); 723 for (i = 0; i < 6 - (len / 8); i++) 724 fprintf(trussinfo->outfile, "\t"); 725 } 726 727 void 728 print_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs, 729 char **s_args, int errorp, long retval) 730 { 731 print_syscall(trussinfo, name, nargs, s_args); 732 if (errorp) { 733 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval, strerror(retval)); 734 } else { 735 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval, retval); 736 } 737 } 738