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