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