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 } , { String | 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) { 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%qx", t); 336 break; 337 } 338 case Ptr: 339 asprintf(&tmp, "0x%lx", args[sc->offset]); 340 break; 341 case Ioctl: 342 { 343 const char *temp = ioctlname(args[sc->offset]); 344 if (temp) 345 tmp = strdup(temp); 346 else 347 asprintf(&tmp, "0x%lx", args[sc->offset]); 348 } 349 break; 350 case Timespec: 351 { 352 struct timespec ts; 353 if (get_struct(fd, (void *)args[sc->offset], &ts, sizeof(ts)) != -1) 354 asprintf(&tmp, "{%jd %jd}", (intmax_t)ts.tv_sec, (intmax_t)ts.tv_nsec); 355 else 356 asprintf(&tmp, "0x%lx", args[sc->offset]); 357 } 358 break; 359 case Timeval: 360 { 361 struct timeval tv; 362 if (get_struct(fd, (void *)args[sc->offset], &tv, sizeof(tv)) != -1) 363 asprintf(&tmp, "{%jd %jd}", (intmax_t)tv.tv_sec, (intmax_t)tv.tv_usec); 364 else 365 asprintf(&tmp, "0x%lx", args[sc->offset]); 366 } 367 break; 368 case Itimerval: 369 { 370 struct itimerval itv; 371 if (get_struct(fd, (void *)args[sc->offset], &itv, sizeof(itv)) != -1) 372 asprintf(&tmp, "{%jd %jd, %jd %jd}", 373 (intmax_t)itv.it_interval.tv_sec, 374 (intmax_t)itv.it_interval.tv_usec, 375 (intmax_t)itv.it_value.tv_sec, 376 (intmax_t)itv.it_value.tv_usec); 377 else 378 asprintf(&tmp, "0x%lx", args[sc->offset]); 379 } 380 break; 381 case Pollfd: 382 { 383 /* 384 * XXX: A Pollfd argument expects the /next/ syscall argument to be 385 * the number of fds in the array. This matches the poll syscall. 386 */ 387 struct pollfd *pfd; 388 int numfds = args[sc->offset+1]; 389 int bytes = sizeof(struct pollfd) * numfds; 390 int i, tmpsize, u, used; 391 const int per_fd = 100; 392 393 if ((pfd = malloc(bytes)) == NULL) 394 err(1, "Cannot malloc %d bytes for pollfd array", bytes); 395 if (get_struct(fd, (void *)args[sc->offset], pfd, bytes) != -1) { 396 397 used = 0; 398 tmpsize = 1 + per_fd * numfds + 2; 399 if ((tmp = malloc(tmpsize)) == NULL) 400 err(1, "Cannot alloc %d bytes for poll output", tmpsize); 401 402 tmp[used++] = '{'; 403 for (i = 0; i < numfds; i++) { 404 #define POLLKNOWN_EVENTS \ 405 (POLLIN | POLLPRI | POLLOUT | POLLERR | POLLHUP | POLLNVAL | \ 406 POLLRDNORM |POLLRDBAND | POLLWRBAND | POLLINIGNEOF) 407 408 u += snprintf(tmp + used, per_fd, 409 "%s%d 0x%hx%s%s%s%s%s%s%s%s%s ", 410 i > 0 ? " " : "", 411 pfd[i].fd, 412 pfd[i].events & ~POLLKNOWN_EVENTS, 413 pfd[i].events & POLLIN ? "" : "|IN", 414 pfd[i].events & POLLPRI ? "" : "|PRI", 415 pfd[i].events & POLLOUT ? "" : "|OUT", 416 pfd[i].events & POLLERR ? "" : "|ERR", 417 pfd[i].events & POLLHUP ? "" : "|HUP", 418 pfd[i].events & POLLNVAL ? "" : "|NVAL", 419 pfd[i].events & POLLRDNORM ? "" : "|RDNORM", 420 pfd[i].events & POLLRDBAND ? "" : "|RDBAND", 421 pfd[i].events & POLLWRBAND ? "" : "|WRBAND"); 422 if (u > 0) 423 used += u < per_fd ? u : per_fd; 424 } 425 tmp[used++] = '}'; 426 tmp[used++] = '\0'; 427 } else 428 asprintf(&tmp, "0x%lx", args[sc->offset]); 429 free(pfd); 430 } 431 break; 432 case Fd_set: 433 { 434 /* 435 * XXX: A Fd_set argument expects the /first/ syscall argument to be 436 * the number of fds in the array. This matches the select syscall. 437 */ 438 fd_set *fds; 439 int numfds = args[0]; 440 int bytes = _howmany(numfds, _NFDBITS) * _NFDBITS; 441 int i, tmpsize, u, used; 442 const int per_fd = 20; 443 444 if ((fds = malloc(bytes)) == NULL) 445 err(1, "Cannot malloc %d bytes for fd_set array", bytes); 446 if (get_struct(fd, (void *)args[sc->offset], fds, bytes) != -1) { 447 used = 0; 448 tmpsize = 1 + numfds * per_fd + 2; 449 if ((tmp = malloc(tmpsize)) == NULL) 450 err(1, "Cannot alloc %d bytes for fd_set output", tmpsize); 451 452 tmp[used++] = '{'; 453 for (i = 0; i < numfds; i++) { 454 if (FD_ISSET(i, fds)) { 455 u = snprintf(tmp + used, per_fd, "%d ", i); 456 if (u > 0) 457 used += u < per_fd ? u : per_fd; 458 } 459 } 460 if (tmp[used-1] == ' ') 461 used--; 462 tmp[used++] = '}'; 463 tmp[used++] = '\0'; 464 } else 465 asprintf(&tmp, "0x%lx", args[sc->offset]); 466 free(fds); 467 } 468 break; 469 case Signal: 470 { 471 long sig; 472 473 sig = args[sc->offset]; 474 if (sig > 0 && sig < NSIG) { 475 int i; 476 asprintf(&tmp, "sig%s", sys_signame[sig]); 477 for (i = 0; tmp[i] != '\0'; ++i) 478 tmp[i] = toupper(tmp[i]); 479 } else 480 asprintf(&tmp, "%ld", sig); 481 } 482 break; 483 case Fcntl: 484 { 485 switch (args[sc->offset]) { 486 #define S(a) case a: tmp = strdup(#a); break; 487 S(F_DUPFD); 488 S(F_GETFD); 489 S(F_SETFD); 490 S(F_GETFL); 491 S(F_SETFL); 492 S(F_GETOWN); 493 S(F_SETOWN); 494 S(F_GETLK); 495 S(F_SETLK); 496 S(F_SETLKW); 497 #undef S 498 } 499 if (tmp == NULL) 500 asprintf(&tmp, "0x%lx", args[sc->offset]); 501 } 502 break; 503 504 case Mprot: 505 { 506 507 #define S(a) ((args[sc->offset] & a) ? #a "|" : "") 508 asprintf(&tmp, "(0x%lx)%s%s%s%s", args[sc->offset], 509 S(PROT_NONE), S(PROT_READ), S(PROT_WRITE), S(PROT_EXEC)); 510 #undef S 511 remove_trailing_or(tmp); 512 513 } 514 break; 515 516 case Mmapflags: 517 { 518 #define S(a) ((args[sc->offset] & a) ? #a "|" : "") 519 asprintf(&tmp, "(0x%lx)%s%s%s%s%s%s%s%s", args[sc->offset], 520 S(MAP_ANON), S(MAP_FIXED), S(MAP_HASSEMAPHORE), 521 S(MAP_NOCORE), S(MAP_NOSYNC), S(MAP_PRIVATE), 522 S(MAP_SHARED), S(MAP_STACK)); 523 #undef S 524 525 remove_trailing_or(tmp); 526 } 527 break; 528 529 case Whence: 530 { 531 switch (args[sc->offset]) { 532 #define S(a) case a: tmp = strdup(#a); break; 533 S(SEEK_SET); 534 S(SEEK_CUR); 535 S(SEEK_END); 536 #undef S 537 default: asprintf(&tmp, "0x%lx", args[sc->offset]); break; 538 } 539 } 540 break; 541 case Sockaddr: 542 { 543 struct sockaddr_storage ss; 544 char addr[64]; 545 struct sockaddr_in *lsin; 546 struct sockaddr_in6 *lsin6; 547 struct sockaddr_un *sun; 548 struct sockaddr *sa; 549 char *p; 550 u_char *q; 551 int i; 552 553 if (args[sc->offset] == 0) { 554 asprintf(&tmp, "NULL"); 555 break; 556 } 557 558 /* yuck: get ss_len */ 559 if (get_struct(fd, (void *)args[sc->offset], (void *)&ss, 560 sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1) 561 err(1, "get_struct %p", (void *)args[sc->offset]); 562 /* sockaddr_un never have the length filled in! */ 563 if (ss.ss_family == AF_UNIX) { 564 if (get_struct(fd, (void *)args[sc->offset], (void *)&ss, 565 sizeof(*sun)) 566 == -1) 567 err(2, "get_struct %p", (void *)args[sc->offset]); 568 } else { 569 if (get_struct(fd, (void *)args[sc->offset], (void *)&ss, ss.ss_len) 570 == -1) 571 err(2, "get_struct %p", (void *)args[sc->offset]); 572 } 573 574 switch (ss.ss_family) { 575 case AF_INET: 576 lsin = (struct sockaddr_in *)&ss; 577 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof addr); 578 asprintf(&tmp, "{ AF_INET %s:%d }", addr, htons(lsin->sin_port)); 579 break; 580 case AF_INET6: 581 lsin6 = (struct sockaddr_in6 *)&ss; 582 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, sizeof addr); 583 asprintf(&tmp, "{ AF_INET6 [%s]:%d }", addr, htons(lsin6->sin6_port)); 584 break; 585 case AF_UNIX: 586 sun = (struct sockaddr_un *)&ss; 587 asprintf(&tmp, "{ AF_UNIX \"%s\" }", sun->sun_path); 588 break; 589 default: 590 sa = (struct sockaddr *)&ss; 591 asprintf(&tmp, "{ sa_len = %d, sa_family = %d, sa_data = {%n%*s } }", 592 (int)sa->sa_len, (int)sa->sa_family, &i, 593 6 * (int)(sa->sa_len - ((char *)&sa->sa_data - (char *)sa)), ""); 594 if (tmp != NULL) { 595 p = tmp + i; 596 for (q = (u_char *)&sa->sa_data; q < (u_char *)sa + sa->sa_len; q++) 597 p += sprintf(p, " %#02x,", *q); 598 } 599 } 600 } 601 break; 602 case Sigaction: 603 { 604 struct sigaction sa; 605 char *hand; 606 const char *h; 607 #define SA_KNOWN_FLAGS \ 608 (SA_ONSTACK | SA_RESTART | SA_RESETHAND | SA_NOCLDSTOP | SA_NODEFER | \ 609 SA_NOCLDWAIT | SA_SIGINFO) 610 611 612 if (get_struct(fd, (void *)args[sc->offset], &sa, sizeof(sa)) != -1) { 613 614 asprintf(&hand, "%p", sa.sa_handler); 615 if (sa.sa_handler == SIG_DFL) 616 h = "SIG_DFL"; 617 else if (sa.sa_handler == SIG_IGN) 618 h = "SIG_IGN"; 619 else 620 h = hand; 621 asprintf(&tmp, "{ %s 0x%x%s%s%s%s%s%s%s ss_t }", 622 h, 623 sa.sa_flags & ~SA_KNOWN_FLAGS, 624 sa.sa_flags & SA_ONSTACK ? "" : "|ONSTACK", 625 sa.sa_flags & SA_RESTART ? "" : "|RESTART", 626 sa.sa_flags & SA_RESETHAND ? "" : "|RESETHAND", 627 sa.sa_flags & SA_NOCLDSTOP ? "" : "|NOCLDSTOP", 628 sa.sa_flags & SA_NODEFER ? "" : "|NODEFER", 629 sa.sa_flags & SA_NOCLDWAIT ? "" : "|NOCLDWAIT", 630 sa.sa_flags & SA_SIGINFO ? "" : "|SIGINFO"); 631 free(hand); 632 } else 633 asprintf(&tmp, "0x%lx", args[sc->offset]); 634 635 } 636 break; 637 } 638 return tmp; 639 } 640 641 #define timespecsubt(tvp, uvp, vvp) \ 642 do { \ 643 (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ 644 (vvp)->tv_nsec = (tvp)->tv_nsec - (uvp)->tv_nsec; \ 645 if ((vvp)->tv_nsec < 0) { \ 646 (vvp)->tv_sec--; \ 647 (vvp)->tv_nsec += 1000000000; \ 648 } \ 649 } while (0) 650 651 /* 652 * print_syscall 653 * Print (to outfile) the system call and its arguments. Note that 654 * nargs is the number of arguments (not the number of words; this is 655 * potentially confusing, I know). 656 */ 657 658 void 659 print_syscall(struct trussinfo *trussinfo, const char *name, int nargs, char **s_args) { 660 int i; 661 int len = 0; 662 struct timespec timediff; 663 664 if (trussinfo->flags & FOLLOWFORKS) 665 len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid); 666 667 if (name != NULL && (!strcmp(name, "execve") || !strcmp(name, "exit"))) { 668 clock_gettime(CLOCK_REALTIME, &trussinfo->after); 669 } 670 671 if (trussinfo->flags & ABSOLUTETIMESTAMPS) { 672 timespecsubt(&trussinfo->after, &trussinfo->start_time, &timediff); 673 len += fprintf(trussinfo->outfile, "%ld.%09ld ", 674 (long)timediff.tv_sec, timediff.tv_nsec); 675 } 676 677 if (trussinfo->flags & RELATIVETIMESTAMPS) { 678 timespecsubt(&trussinfo->after, &trussinfo->before, &timediff); 679 len += fprintf(trussinfo->outfile, "%ld.%09ld ", 680 (long)timediff.tv_sec, timediff.tv_nsec); 681 } 682 683 len += fprintf(trussinfo->outfile, "%s(", name); 684 685 for (i = 0; i < nargs; i++) { 686 if (s_args[i]) 687 len += fprintf(trussinfo->outfile, "%s", s_args[i]); 688 else 689 len += fprintf(trussinfo->outfile, "<missing argument>"); 690 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? "," : ""); 691 } 692 len += fprintf(trussinfo->outfile, ")"); 693 for (i = 0; i < 6 - (len / 8); i++) 694 fprintf(trussinfo->outfile, "\t"); 695 } 696 697 void 698 print_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs, 699 char **s_args, int errorp, long retval) 700 { 701 print_syscall(trussinfo, name, nargs, s_args); 702 if (errorp) { 703 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval, strerror(retval)); 704 } else { 705 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval, retval); 706 } 707 } 708