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