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 #include <sys/ioccom.h> 50 #include <machine/atomic.h> 51 #include <errno.h> 52 #include <sys/umtx.h> 53 #include <sys/event.h> 54 #include <sys/stat.h> 55 #include <sys/resource.h> 56 57 #include <ctype.h> 58 #include <err.h> 59 #include <fcntl.h> 60 #include <poll.h> 61 #include <signal.h> 62 #include <stdint.h> 63 #include <stdio.h> 64 #include <stdlib.h> 65 #include <string.h> 66 #include <time.h> 67 #include <unistd.h> 68 #include <vis.h> 69 70 #include "truss.h" 71 #include "extern.h" 72 #include "syscall.h" 73 74 /* 75 * This should probably be in its own file, sorted alphabetically. 76 */ 77 78 struct syscall syscalls[] = { 79 { "fcntl", 1, 3, 80 { { Int, 0 } , { Fcntl, 1 }, { Fcntlflag | OUT, 2 }}}, 81 { "readlink", 1, 3, 82 { { Name, 0 } , { Readlinkres | OUT, 1 }, { Int, 2 }}}, 83 { "lseek", 2, 3, 84 #ifdef __LP64__ 85 { { Int, 0 }, {Quad, 2 }, { Whence, 3 }}}, 86 #else 87 { { Int, 0 }, {Quad, 2 }, { Whence, 4 }}}, 88 #endif 89 { "linux_lseek", 2, 3, 90 { { Int, 0 }, {Int, 1 }, { Whence, 2 }}}, 91 { "mmap", 2, 6, 92 #ifdef __LP64__ 93 { { Ptr, 0 }, {Int, 1}, {Mprot, 2}, {Mmapflags, 3}, {Int, 4}, {Quad, 5}}}, 94 #else 95 { { Ptr, 0 }, {Int, 1}, {Mprot, 2}, {Mmapflags, 3}, {Int, 4}, {Quad, 6}}}, 96 #endif 97 { "mprotect", 1, 3, 98 { { Ptr, 0 }, {Int, 1}, {Mprot, 2}}}, 99 { "open", 1, 3, 100 { { Name | IN, 0} , { Open, 1}, {Octal, 2}}}, 101 { "mkdir", 1, 2, 102 { { Name, 0} , {Octal, 1}}}, 103 { "linux_open", 1, 3, 104 { { Name, 0 }, { Hex, 1}, { Octal, 2 }}}, 105 { "close", 1, 1, 106 { { Int, 0 } } }, 107 { "link", 0, 2, 108 { { Name, 0 }, { Name, 1 }}}, 109 { "unlink", 0, 1, 110 { { Name, 0 }}}, 111 { "chdir", 0, 1, 112 { { Name, 0 }}}, 113 { "chroot", 0, 1, 114 { { Name, 0 }}}, 115 { "mknod", 0, 3, 116 { { Name, 0 }, { Octal, 1 }, { Int, 3 }}}, 117 { "chmod", 0, 2, 118 { { Name, 0 }, { Octal, 1 }}}, 119 { "chown", 0, 3, 120 { { Name, 0 }, { Int, 1 }, { Int, 2 }}}, 121 { "mount", 0, 4, 122 { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 }}}, 123 { "umount", 0, 2, 124 { { Name, 0 }, { Int, 2 }}}, 125 { "fstat", 1, 2, 126 { { Int, 0}, { Stat | OUT , 1 }}}, 127 { "stat", 1, 2, 128 { { Name | IN, 0 }, { Stat | OUT, 1 }}}, 129 { "lstat", 1, 2, 130 { { Name | IN, 0 }, { Stat | OUT, 1 }}}, 131 { "linux_newstat", 1, 2, 132 { { Name | IN, 0 }, { Ptr | OUT, 1 }}}, 133 { "linux_newfstat", 1, 2, 134 { { Int, 0 }, { Ptr | OUT, 1 }}}, 135 { "write", 1, 3, 136 { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }}}, 137 { "ioctl", 1, 3, 138 { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 }}}, 139 { "break", 1, 1, { { Hex, 0 }}}, 140 { "exit", 0, 1, { { Hex, 0 }}}, 141 { "access", 1, 2, { { Name | IN, 0 }, { Int, 1 }}}, 142 { "sigaction", 1, 3, 143 { { Signal, 0 }, { Sigaction | IN, 1 }, { Sigaction | OUT, 2 }}}, 144 { "accept", 1, 3, 145 { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 146 { "bind", 1, 3, 147 { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, 148 { "connect", 1, 3, 149 { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, 150 { "getpeername", 1, 3, 151 { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 152 { "getsockname", 1, 3, 153 { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, 154 { "recvfrom", 1, 6, 155 { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } }, 156 { "sendto", 1, 6, 157 { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } }, 158 { "execve", 1, 3, 159 { { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } }, 160 { "linux_execve", 1, 3, 161 { { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } }, 162 { "kldload", 0, 1, { { Name | IN, 0 }}}, 163 { "kldunload", 0, 1, { { Int, 0 }}}, 164 { "kldfind", 0, 1, { { Name | IN, 0 }}}, 165 { "kldnext", 0, 1, { { Int, 0 }}}, 166 { "kldstat", 0, 2, { { Int, 0 }, { Ptr, 1 }}}, 167 { "kldfirstmod", 0, 1, { { Int, 0 }}}, 168 { "nanosleep", 0, 1, { { Timespec, 0 }}}, 169 { "select", 1, 5, { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, { Timeval, 4 }}}, 170 { "poll", 1, 3, { { Pollfd, 0 }, { Int, 1 }, { Int, 2 }}}, 171 { "gettimeofday", 1, 2, { { Timeval | OUT, 0 }, { Ptr, 1 }}}, 172 { "clock_gettime", 1, 2, { { Int, 0 }, { Timespec | OUT, 1 }}}, 173 { "getitimer", 1, 2, { { Int, 0 }, { Itimerval | OUT, 2 }}}, 174 { "setitimer", 1, 3, { { Int, 0 }, { Itimerval, 1} , { Itimerval | OUT, 2 }}}, 175 { "kse_release", 0, 1, { { Timespec, 0 }}}, 176 { "kevent", 0, 6, { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 }, { Int, 4 }, { Timespec, 5 }}}, 177 { "_umtx_lock", 0, 1, { { Umtx, 0 }}}, 178 { "_umtx_unlock", 0, 1, { { Umtx, 0 }}}, 179 { "sigprocmask", 0, 3, { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 }}}, 180 { "unmount", 1, 2, { { Name, 0 }, { Int, 1 }}}, 181 { "socket", 1, 3, { { Sockdomain, 0}, { Socktype, 1}, {Int, 2 }}}, 182 { "getrusage", 1, 2, { { Int, 0 }, { Rusage | OUT, 1 }}}, 183 { "__getcwd", 1, 2, { { Name | OUT, 0}, { Int, 1 }}}, 184 { "shutdown", 1, 2, { { Int, 0}, { Shutdown, 1}}}, 185 { "getrlimit", 1, 2, { { Resource, 0}, {Rlimit | OUT, 1}}}, 186 { "setrlimit", 1, 2, { { Resource, 0}, {Rlimit | IN, 1}}}, 187 { "utimes", 1, 2, 188 { { Name | IN, 0 }, { Timeval2 | IN, 1 }}}, 189 { "lutimes", 1, 2, 190 { { Name | IN, 0 }, { Timeval2 | IN, 1 }}}, 191 { "futimes", 1, 2, 192 { { Int, 0 }, { Timeval | IN, 1 }}}, 193 { "chflags", 1, 2, 194 { { Name | IN, 0 }, { Hex, 1 }}}, 195 { "lchflags", 1, 2, 196 { { Name | IN, 0 }, { Hex, 1 }}}, 197 { "pathconf", 1, 2, 198 { { Name | IN, 0 }, { Pathconf, 1 }}}, 199 { "truncate", 1, 3, 200 { { Name | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 }}}, 201 { "ftruncate", 1, 3, 202 { { Int | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 }}}, 203 { "kill", 1, 2, 204 { { Int | IN, 0 }, { Signal | IN, 1}}}, 205 { "munmap", 1, 2, 206 { { Ptr, 0 }, { Int, 1 }}}, 207 { "read", 1, 3, 208 { { Int, 0}, { BinString | OUT, 1}, { Int, 2}}}, 209 { "rename", 1, 2, 210 { { Name , 0} , { Name, 1}}}, 211 { "symlink", 1, 2, 212 { { Name , 0} , { Name, 1}}}, 213 { 0, 0, 0, { { 0, 0 }}}, 214 }; 215 216 /* Xlat idea taken from strace */ 217 struct xlat { 218 int val; 219 char *str; 220 }; 221 222 #define X(a) { a, #a }, 223 #define XEND { 0, NULL } 224 225 static struct xlat kevent_filters[] = { 226 X(EVFILT_READ) X(EVFILT_WRITE) X(EVFILT_AIO) X(EVFILT_VNODE) 227 X(EVFILT_PROC) X(EVFILT_SIGNAL) X(EVFILT_TIMER) 228 X(EVFILT_NETDEV) X(EVFILT_FS) X(EVFILT_READ) XEND 229 }; 230 231 static struct xlat kevent_flags[] = { 232 X(EV_ADD) X(EV_DELETE) X(EV_ENABLE) X(EV_DISABLE) X(EV_ONESHOT) 233 X(EV_CLEAR) X(EV_FLAG1) X(EV_ERROR) X(EV_EOF) XEND 234 }; 235 236 struct xlat poll_flags[] = { 237 X(POLLSTANDARD) X(POLLIN) X(POLLPRI) X(POLLOUT) X(POLLERR) 238 X(POLLHUP) X(POLLNVAL) X(POLLRDNORM) X(POLLRDBAND) 239 X(POLLWRBAND) X(POLLINIGNEOF) XEND 240 }; 241 242 static struct xlat mmap_flags[] = { 243 X(MAP_SHARED) X(MAP_PRIVATE) X(MAP_FIXED) X(MAP_RENAME) 244 X(MAP_NORESERVE) X(MAP_RESERVED0080) X(MAP_RESERVED0100) 245 X(MAP_HASSEMAPHORE) X(MAP_STACK) X(MAP_NOSYNC) X(MAP_ANON) 246 X(MAP_NOCORE) XEND 247 }; 248 249 static struct xlat mprot_flags[] = { 250 X(PROT_NONE) X(PROT_READ) X(PROT_WRITE) X(PROT_EXEC) XEND 251 }; 252 253 static struct xlat whence_arg[] = { 254 X(SEEK_SET) X(SEEK_CUR) X(SEEK_END) XEND 255 }; 256 257 static struct xlat sigaction_flags[] = { 258 X(SA_ONSTACK) X(SA_RESTART) X(SA_RESETHAND) X(SA_NOCLDSTOP) 259 X(SA_NODEFER) X(SA_NOCLDWAIT) X(SA_SIGINFO) XEND 260 }; 261 262 static struct xlat fcntl_arg[] = { 263 X(F_DUPFD) X(F_GETFD) X(F_SETFD) X(F_GETFL) X(F_SETFL) 264 X(F_GETOWN) X(F_SETOWN) X(F_GETLK) X(F_SETLK) X(F_SETLKW) XEND 265 }; 266 267 static struct xlat fcntlfd_arg[] = { 268 X(FD_CLOEXEC) XEND 269 }; 270 271 static struct xlat fcntlfl_arg[] = { 272 X(O_APPEND) X(O_ASYNC) X(O_FSYNC) X(O_NONBLOCK) X(O_NOFOLLOW) 273 X(O_DIRECT) XEND 274 }; 275 276 static struct xlat sockdomain_arg[] = { 277 X(PF_UNSPEC) X(PF_LOCAL) X(PF_UNIX) X(PF_INET) X(PF_IMPLINK) 278 X(PF_PUP) X(PF_CHAOS) X(PF_NETBIOS) X(PF_ISO) X(PF_OSI) 279 X(PF_ECMA) X(PF_DATAKIT) X(PF_CCITT) X(PF_SNA) X(PF_DECnet) 280 X(PF_DLI) X(PF_LAT) X(PF_HYLINK) X(PF_APPLETALK) X(PF_ROUTE) 281 X(PF_LINK) X(PF_XTP) X(PF_COIP) X(PF_CNT) X(PF_SIP) X(PF_IPX) 282 X(PF_RTIP) X(PF_PIP) X(PF_ISDN) X(PF_KEY) X(PF_INET6) 283 X(PF_NATM) X(PF_ATM) X(PF_NETGRAPH) X(PF_SLOW) X(PF_SCLUSTER) 284 X(PF_ARP) X(PF_BLUETOOTH) XEND 285 }; 286 287 static struct xlat socktype_arg[] = { 288 X(SOCK_STREAM) X(SOCK_DGRAM) X(SOCK_RAW) X(SOCK_RDM) 289 X(SOCK_SEQPACKET) XEND 290 }; 291 292 static struct xlat open_flags[] = { 293 X(O_RDONLY) X(O_WRONLY) X(O_RDWR) X(O_ACCMODE) X(O_NONBLOCK) 294 X(O_APPEND) X(O_SHLOCK) X(O_EXLOCK) X(O_ASYNC) X(O_FSYNC) 295 X(O_NOFOLLOW) X(O_CREAT) X(O_TRUNC) X(O_EXCL) X(O_NOCTTY) 296 X(O_DIRECT) XEND 297 }; 298 299 static struct xlat shutdown_arg[] = { 300 X(SHUT_RD) X(SHUT_WR) X(SHUT_RDWR) XEND 301 }; 302 303 static struct xlat resource_arg[] = { 304 X(RLIMIT_CPU) X(RLIMIT_FSIZE) X(RLIMIT_DATA) X(RLIMIT_STACK) 305 X(RLIMIT_CORE) X(RLIMIT_RSS) X(RLIMIT_MEMLOCK) X(RLIMIT_NPROC) 306 X(RLIMIT_NOFILE) X(RLIMIT_SBSIZE) X(RLIMIT_VMEM) XEND 307 }; 308 309 static struct xlat pathconf_arg[] = { 310 X(_PC_LINK_MAX) X(_PC_MAX_CANON) X(_PC_MAX_INPUT) 311 X(_PC_NAME_MAX) X(_PC_PATH_MAX) X(_PC_PIPE_BUF) 312 X(_PC_CHOWN_RESTRICTED) X(_PC_NO_TRUNC) X(_PC_VDISABLE) 313 X(_PC_ASYNC_IO) X(_PC_PRIO_IO) X(_PC_SYNC_IO) 314 X(_PC_ALLOC_SIZE_MIN) X(_PC_FILESIZEBITS) 315 X(_PC_REC_INCR_XFER_SIZE) X(_PC_REC_MAX_XFER_SIZE) 316 X(_PC_REC_MIN_XFER_SIZE) X(_PC_REC_XFER_ALIGN) 317 X(_PC_SYMLINK_MAX) X(_PC_ACL_EXTENDED) X(_PC_ACL_PATH_MAX) 318 X(_PC_CAP_PRESENT) X(_PC_INF_PRESENT) X(_PC_MAC_PRESENT) 319 XEND 320 }; 321 322 #undef X 323 #undef XEND 324 325 /* Searches an xlat array for a value, and returns it if found. Otherwise 326 return a string representation. */ 327 char *lookup(struct xlat *xlat, int val, int base) 328 { 329 static char tmp[16]; 330 for (; xlat->str != NULL; xlat++) 331 if (xlat->val == val) 332 return xlat->str; 333 switch (base) { 334 case 8: 335 sprintf(tmp, "0%o", val); 336 break; 337 case 16: 338 sprintf(tmp, "0x%x", val); 339 break; 340 case 10: 341 sprintf(tmp, "%u", val); 342 break; 343 default: 344 errx(1,"Unknown lookup base"); 345 break; 346 } 347 return tmp; 348 } 349 350 char *xlookup(struct xlat *xlat, int val) 351 { 352 return lookup(xlat, val, 16); 353 } 354 355 /* Searches an xlat array containing bitfield values. Remaining bits 356 set after removing the known ones are printed at the end: 357 IN|0x400 */ 358 char *xlookup_bits(struct xlat *xlat, int val) 359 { 360 static char str[512]; 361 int len = 0; 362 int rem = val; 363 364 for (; xlat->str != NULL; xlat++) 365 { 366 if ((xlat->val & rem) == xlat->val) 367 { 368 /* don't print the "all-bits-zero" string unless all 369 bits are really zero */ 370 if (xlat->val == 0 && val != 0) 371 continue; 372 len += sprintf(str + len, "%s|", xlat->str); 373 rem &= ~(xlat->val); 374 } 375 } 376 /* if we have leftover bits or didn't match anything */ 377 if (rem || len == 0) 378 len += sprintf(str + len, "0x%x", rem); 379 if (len && str[len - 1] == '|') 380 len--; 381 str[len] = 0; 382 return str; 383 } 384 385 /* 386 * If/when the list gets big, it might be desirable to do it 387 * as a hash table or binary search. 388 */ 389 390 struct syscall * 391 get_syscall(const char *name) { 392 struct syscall *sc = syscalls; 393 394 if (name == NULL) 395 return (NULL); 396 while (sc->name) { 397 if (!strcmp(name, sc->name)) 398 return sc; 399 sc++; 400 } 401 return NULL; 402 } 403 404 /* 405 * get_struct 406 * 407 * Copy a fixed amount of bytes from the process. 408 */ 409 410 static int 411 get_struct(int procfd, void *offset, void *buf, int len) { 412 413 if (pread(procfd, buf, len, (uintptr_t)offset) != len) 414 return -1; 415 return 0; 416 } 417 418 /* 419 * get_string 420 * Copy a string from the process. Note that it is 421 * expected to be a C string, but if max is set, it will 422 * only get that much. 423 */ 424 425 char * 426 get_string(int procfd, void *offset, int max) { 427 char *buf; 428 int size, len, c, fd; 429 FILE *p; 430 431 if ((fd = dup(procfd)) == -1) 432 err(1, "dup"); 433 if ((p = fdopen(fd, "r")) == NULL) 434 err(1, "fdopen"); 435 buf = malloc( size = (max ? max + 1 : 64 ) ); 436 len = 0; 437 buf[0] = 0; 438 if (fseeko(p, (uintptr_t)offset, SEEK_SET) == 0) { 439 while ((c = fgetc(p)) != EOF) { 440 buf[len++] = c; 441 if (c == 0 || len == max) 442 break; 443 if (len == size) { 444 char *tmp; 445 tmp = realloc(buf, size+64); 446 if (tmp == NULL) { 447 buf[len] = 0; 448 break; 449 } 450 size += 64; 451 buf = tmp; 452 } 453 } 454 buf[len] = 0; 455 } 456 fclose(p); 457 return (buf); 458 } 459 460 461 /* 462 * print_arg 463 * Converts a syscall argument into a string. Said string is 464 * allocated via malloc(), so needs to be free()'d. The file 465 * descriptor is for the process' memory (via /proc), and is used 466 * to get any data (where the argument is a pointer). sc is 467 * a pointer to the syscall description (see above); args is 468 * an array of all of the system call arguments. 469 */ 470 471 char * 472 print_arg(int fd, struct syscall_args *sc, unsigned long *args, long retval, struct trussinfo *trussinfo) { 473 char *tmp = NULL; 474 475 switch (sc->type & ARG_MASK) { 476 case Hex: 477 asprintf(&tmp, "0x%lx", args[sc->offset]); 478 break; 479 case Octal: 480 asprintf(&tmp, "0%lo", args[sc->offset]); 481 break; 482 case Int: 483 asprintf(&tmp, "%ld", args[sc->offset]); 484 break; 485 case Name: 486 { 487 /* NULL-terminated string. */ 488 char *tmp2; 489 tmp2 = get_string(fd, (void*)args[sc->offset], 0); 490 asprintf(&tmp, "\"%s\"", tmp2); 491 free(tmp2); 492 } 493 break; 494 case BinString: 495 { 496 /* Binary block of data that might have printable characters. 497 XXX If type|OUT, assume that the length is the syscall's 498 return value. Otherwise, assume that the length of the block 499 is in the next syscall argument. */ 500 int max_string = trussinfo->strsize; 501 char tmp2[max_string+1], *tmp3; 502 int len; 503 int truncated = 0; 504 505 if (sc->type & OUT) 506 len = retval; 507 else 508 len = args[sc->offset + 1]; 509 510 /* Don't print more than max_string characters, to avoid word 511 wrap. If we have to truncate put some ... after the string. 512 */ 513 if (len > max_string) { 514 len = max_string; 515 truncated = 1; 516 } 517 if (len && get_struct(fd, (void*)args[sc->offset], &tmp2, len) != -1) { 518 tmp3 = malloc(len * 4 + 1); 519 while (len) { 520 if (strvisx(tmp3, tmp2, len, VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string) 521 break; 522 len--; 523 truncated = 1; 524 }; 525 asprintf(&tmp, "\"%s\"%s", tmp3, truncated?"...":""); 526 free(tmp3); 527 } else 528 asprintf(&tmp, "0x%lx", args[sc->offset]); 529 } 530 break; 531 case StringArray: 532 { 533 int num, size, i; 534 char *tmp2; 535 char *string; 536 char *strarray[100]; /* XXX This is ugly. */ 537 538 if (get_struct(fd, (void *)args[sc->offset], (void *)&strarray, 539 sizeof(strarray)) == -1) { 540 err(1, "get_struct %p", (void *)args[sc->offset]); 541 } 542 num = 0; 543 size = 0; 544 545 /* Find out how large of a buffer we'll need. */ 546 while (strarray[num] != NULL) { 547 string = get_string(fd, (void*)strarray[num], 0); 548 size += strlen(string); 549 free(string); 550 num++; 551 } 552 size += 4 + (num * 4); 553 tmp = (char *)malloc(size); 554 tmp2 = tmp; 555 556 tmp2 += sprintf(tmp2, " ["); 557 for (i = 0; i < num; i++) { 558 string = get_string(fd, (void*)strarray[i], 0); 559 tmp2 += sprintf(tmp2, " \"%s\"%c", string, (i+1 == num) ? ' ' : ','); 560 free(string); 561 } 562 tmp2 += sprintf(tmp2, "]"); 563 } 564 break; 565 #ifdef __LP64__ 566 case Quad: 567 asprintf(&tmp, "0x%lx", args[sc->offset]); 568 break; 569 #else 570 case Quad: 571 { 572 unsigned long long ll; 573 ll = *(unsigned long long *)(args + sc->offset); 574 asprintf(&tmp, "0x%llx", ll); 575 break; 576 } 577 #endif 578 case Ptr: 579 asprintf(&tmp, "0x%lx", args[sc->offset]); 580 break; 581 case Readlinkres: 582 { 583 char *tmp2; 584 if (retval == -1) { 585 tmp = strdup(""); 586 break; 587 } 588 tmp2 = get_string(fd, (void*)args[sc->offset], retval); 589 asprintf(&tmp, "\"%s\"", tmp2); 590 free(tmp2); 591 } 592 break; 593 case Ioctl: 594 { 595 const char *temp = ioctlname(args[sc->offset]); 596 if (temp) 597 tmp = strdup(temp); 598 else 599 { 600 unsigned long arg = args[sc->offset]; 601 asprintf(&tmp, "0x%lx { IO%s%s 0x%lx('%c'), %lu, %lu}", arg, 602 arg&IOC_OUT?"R":"", arg&IOC_IN?"W":"", 603 IOCGROUP(arg), isprint(IOCGROUP(arg))?(char)IOCGROUP(arg):'?', 604 arg & 0xFF, IOCPARM_LEN(arg)); 605 } 606 } 607 break; 608 case Umtx: 609 { 610 struct umtx umtx; 611 if (get_struct(fd, (void *)args[sc->offset], &umtx, sizeof(umtx)) != -1) 612 asprintf(&tmp, "{0x%lx}", (long)umtx.u_owner); 613 else 614 asprintf(&tmp, "0x%lx", args[sc->offset]); 615 } 616 break; 617 case Timespec: 618 { 619 struct timespec ts; 620 if (get_struct(fd, (void *)args[sc->offset], &ts, sizeof(ts)) != -1) 621 asprintf(&tmp, "{%ld.%09ld}", (long)ts.tv_sec, ts.tv_nsec); 622 else 623 asprintf(&tmp, "0x%lx", args[sc->offset]); 624 } 625 break; 626 case Timeval: 627 { 628 struct timeval tv; 629 if (get_struct(fd, (void *)args[sc->offset], &tv, sizeof(tv)) != -1) 630 asprintf(&tmp, "{%ld.%06ld}", (long)tv.tv_sec, tv.tv_usec); 631 else 632 asprintf(&tmp, "0x%lx", args[sc->offset]); 633 } 634 break; 635 case Timeval2: 636 { 637 struct timeval tv[2]; 638 if (get_struct(fd, (void *)args[sc->offset], &tv, sizeof(tv)) != -1) 639 asprintf(&tmp, "{%ld.%06ld, %ld.%06ld}", 640 (long)tv[0].tv_sec, tv[0].tv_usec, 641 (long)tv[1].tv_sec, tv[1].tv_usec); 642 else 643 asprintf(&tmp, "0x%lx", args[sc->offset]); 644 } 645 break; 646 case Itimerval: 647 { 648 struct itimerval itv; 649 if (get_struct(fd, (void *)args[sc->offset], &itv, sizeof(itv)) != -1) 650 asprintf(&tmp, "{%ld.%06ld, %ld.%06ld}", 651 (long)itv.it_interval.tv_sec, 652 itv.it_interval.tv_usec, 653 (long)itv.it_value.tv_sec, 654 itv.it_value.tv_usec); 655 else 656 asprintf(&tmp, "0x%lx", args[sc->offset]); 657 } 658 break; 659 case Pollfd: 660 { 661 /* 662 * XXX: A Pollfd argument expects the /next/ syscall argument to be 663 * the number of fds in the array. This matches the poll syscall. 664 */ 665 struct pollfd *pfd; 666 int numfds = args[sc->offset+1]; 667 int bytes = sizeof(struct pollfd) * numfds; 668 int i, tmpsize, u, used; 669 const int per_fd = 100; 670 671 if ((pfd = malloc(bytes)) == NULL) 672 err(1, "Cannot malloc %d bytes for pollfd array", bytes); 673 if (get_struct(fd, (void *)args[sc->offset], pfd, bytes) != -1) { 674 675 used = 0; 676 tmpsize = 1 + per_fd * numfds + 2; 677 if ((tmp = malloc(tmpsize)) == NULL) 678 err(1, "Cannot alloc %d bytes for poll output", tmpsize); 679 680 tmp[used++] = '{'; 681 for (i = 0; i < numfds; i++) { 682 683 u = snprintf(tmp + used, per_fd, 684 "%s%d/%s", 685 i > 0 ? " " : "", 686 pfd[i].fd, 687 xlookup_bits(poll_flags, pfd[i].events) ); 688 if (u > 0) 689 used += u < per_fd ? u : per_fd; 690 } 691 tmp[used++] = '}'; 692 tmp[used++] = '\0'; 693 } else 694 asprintf(&tmp, "0x%lx", args[sc->offset]); 695 free(pfd); 696 } 697 break; 698 case Fd_set: 699 { 700 /* 701 * XXX: A Fd_set argument expects the /first/ syscall argument to be 702 * the number of fds in the array. This matches the select syscall. 703 */ 704 fd_set *fds; 705 int numfds = args[0]; 706 int bytes = _howmany(numfds, _NFDBITS) * _NFDBITS; 707 int i, tmpsize, u, used; 708 const int per_fd = 20; 709 710 if ((fds = malloc(bytes)) == NULL) 711 err(1, "Cannot malloc %d bytes for fd_set array", bytes); 712 if (get_struct(fd, (void *)args[sc->offset], fds, bytes) != -1) { 713 used = 0; 714 tmpsize = 1 + numfds * per_fd + 2; 715 if ((tmp = malloc(tmpsize)) == NULL) 716 err(1, "Cannot alloc %d bytes for fd_set output", tmpsize); 717 718 tmp[used++] = '{'; 719 for (i = 0; i < numfds; i++) { 720 if (FD_ISSET(i, fds)) { 721 u = snprintf(tmp + used, per_fd, "%d ", i); 722 if (u > 0) 723 used += u < per_fd ? u : per_fd; 724 } 725 } 726 if (tmp[used-1] == ' ') 727 used--; 728 tmp[used++] = '}'; 729 tmp[used++] = '\0'; 730 } else 731 asprintf(&tmp, "0x%lx", args[sc->offset]); 732 free(fds); 733 } 734 break; 735 case Signal: 736 { 737 long sig; 738 739 sig = args[sc->offset]; 740 tmp = strsig(sig); 741 if (tmp == NULL) 742 asprintf(&tmp, "%ld", sig); 743 } 744 break; 745 case Sigset: 746 { 747 long sig; 748 sigset_t ss; 749 int i, used; 750 751 sig = args[sc->offset]; 752 if (get_struct(fd, (void *)args[sc->offset], (void *)&ss, 753 sizeof(ss)) == -1) 754 { 755 asprintf(&tmp, "0x%lx", args[sc->offset]); 756 break; 757 } 758 tmp = malloc(sys_nsig * 8); /* 7 bytes avg per signal name */ 759 used = 0; 760 for (i = 1; i < sys_nsig; i++) 761 { 762 if (sigismember(&ss, i)) 763 { 764 used += sprintf(tmp + used, "%s|", strsig(i)); 765 } 766 } 767 if(used) 768 tmp[used-1] = 0; 769 else 770 strcpy(tmp, "0x0"); 771 } 772 break; 773 case Sigprocmask: 774 { 775 switch (args[sc->offset]) { 776 #define S(a) case a: tmp = strdup(#a); break; 777 S(SIG_BLOCK); 778 S(SIG_UNBLOCK); 779 S(SIG_SETMASK); 780 #undef S 781 } 782 if (tmp == NULL) 783 asprintf(&tmp, "0x%lx", args[sc->offset]); 784 } 785 break; 786 787 case Fcntlflag: 788 { 789 /* XXX output depends on the value of the previous argument */ 790 switch (args[sc->offset-1]) { 791 case F_SETFD: 792 tmp = strdup(xlookup_bits(fcntlfd_arg, args[sc->offset])); 793 break; 794 case F_SETFL: 795 tmp = strdup(xlookup_bits(fcntlfl_arg, args[sc->offset])); 796 break; 797 case F_GETFD: 798 case F_GETFL: 799 case F_GETOWN: 800 tmp = strdup(""); 801 break; 802 default: 803 asprintf(&tmp, "0x%lx", args[sc->offset]); 804 break; 805 } 806 } 807 break; 808 case Open: 809 tmp = strdup(xlookup_bits(open_flags, args[sc->offset])); 810 break; 811 case Fcntl: 812 tmp = strdup(xlookup(fcntl_arg, args[sc->offset])); 813 break; 814 case Mprot: 815 tmp = strdup(xlookup_bits(mprot_flags, args[sc->offset])); 816 break; 817 case Mmapflags: 818 tmp = strdup(xlookup_bits(mmap_flags, args[sc->offset])); 819 break; 820 case Whence: 821 tmp = strdup(xlookup(whence_arg, args[sc->offset])); 822 break; 823 case Sockdomain: 824 tmp = strdup(xlookup(sockdomain_arg, args[sc->offset])); 825 break; 826 case Socktype: 827 tmp = strdup(xlookup(socktype_arg, args[sc->offset])); 828 break; 829 case Shutdown: 830 tmp = strdup(xlookup(shutdown_arg, args[sc->offset])); 831 break; 832 case Resource: 833 tmp = strdup(xlookup(resource_arg, args[sc->offset])); 834 break; 835 case Pathconf: 836 tmp = strdup(xlookup(pathconf_arg, args[sc->offset])); 837 break; 838 case Sockaddr: 839 { 840 struct sockaddr_storage ss; 841 char addr[64]; 842 struct sockaddr_in *lsin; 843 struct sockaddr_in6 *lsin6; 844 struct sockaddr_un *sun; 845 struct sockaddr *sa; 846 char *p; 847 u_char *q; 848 int i; 849 850 if (args[sc->offset] == 0) { 851 asprintf(&tmp, "NULL"); 852 break; 853 } 854 855 /* yuck: get ss_len */ 856 if (get_struct(fd, (void *)args[sc->offset], (void *)&ss, 857 sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1) 858 err(1, "get_struct %p", (void *)args[sc->offset]); 859 /* 860 * If ss_len is 0, then try to guess from the sockaddr type. 861 * AF_UNIX may be initialized incorrectly, so always frob 862 * it by using the "right" size. 863 */ 864 if (ss.ss_len == 0 || ss.ss_family == AF_UNIX) { 865 switch (ss.ss_family) { 866 case AF_INET: 867 ss.ss_len = sizeof(*lsin); 868 break; 869 case AF_UNIX: 870 ss.ss_len = sizeof(*sun); 871 break; 872 default: 873 /* hurrrr */ 874 break; 875 } 876 } 877 if (get_struct(fd, (void *)args[sc->offset], (void *)&ss, ss.ss_len) 878 == -1) { 879 err(2, "get_struct %p", (void *)args[sc->offset]); 880 } 881 882 switch (ss.ss_family) { 883 case AF_INET: 884 lsin = (struct sockaddr_in *)&ss; 885 inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof addr); 886 asprintf(&tmp, "{ AF_INET %s:%d }", addr, htons(lsin->sin_port)); 887 break; 888 case AF_INET6: 889 lsin6 = (struct sockaddr_in6 *)&ss; 890 inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, sizeof addr); 891 asprintf(&tmp, "{ AF_INET6 [%s]:%d }", addr, htons(lsin6->sin6_port)); 892 break; 893 case AF_UNIX: 894 sun = (struct sockaddr_un *)&ss; 895 asprintf(&tmp, "{ AF_UNIX \"%s\" }", sun->sun_path); 896 break; 897 default: 898 sa = (struct sockaddr *)&ss; 899 asprintf(&tmp, "{ sa_len = %d, sa_family = %d, sa_data = {%n%*s } }", 900 (int)sa->sa_len, (int)sa->sa_family, &i, 901 6 * (int)(sa->sa_len - ((char *)&sa->sa_data - (char *)sa)), ""); 902 if (tmp != NULL) { 903 p = tmp + i; 904 for (q = (u_char *)&sa->sa_data; q < (u_char *)sa + sa->sa_len; q++) 905 p += sprintf(p, " %#02x,", *q); 906 } 907 } 908 } 909 break; 910 case Sigaction: 911 { 912 struct sigaction sa; 913 char *hand; 914 const char *h; 915 916 if (get_struct(fd, (void *)args[sc->offset], &sa, sizeof(sa)) != -1) { 917 918 asprintf(&hand, "%p", sa.sa_handler); 919 if (sa.sa_handler == SIG_DFL) 920 h = "SIG_DFL"; 921 else if (sa.sa_handler == SIG_IGN) 922 h = "SIG_IGN"; 923 else 924 h = hand; 925 926 asprintf(&tmp, "{ %s %s ss_t }", 927 h, 928 xlookup_bits(sigaction_flags, sa.sa_flags)); 929 free(hand); 930 } else 931 asprintf(&tmp, "0x%lx", args[sc->offset]); 932 933 } 934 break; 935 case Kevent: 936 { 937 /* 938 * XXX XXX: the size of the array is determined by either the 939 * next syscall argument, or by the syscall returnvalue, 940 * depending on which argument number we are. This matches the 941 * kevent syscall, but luckily that's the only syscall that uses 942 * them. 943 */ 944 struct kevent *ke; 945 int numevents = -1; 946 int bytes = 0; 947 int i, tmpsize, u, used; 948 const int per_ke = 100; 949 950 if (sc->offset == 1) 951 numevents = args[sc->offset+1]; 952 else if (sc->offset == 3 && retval != -1) 953 numevents = retval; 954 955 if (numevents >= 0) 956 bytes = sizeof(struct kevent) * numevents; 957 if ((ke = malloc(bytes)) == NULL) 958 err(1, "Cannot malloc %d bytes for kevent array", bytes); 959 if (numevents >= 0 && get_struct(fd, (void *)args[sc->offset], ke, bytes) != -1) { 960 used = 0; 961 tmpsize = 1 + per_ke * numevents + 2; 962 if ((tmp = malloc(tmpsize)) == NULL) 963 err(1, "Cannot alloc %d bytes for kevent output", tmpsize); 964 965 tmp[used++] = '{'; 966 for (i = 0; i < numevents; i++) { 967 u = snprintf(tmp + used, per_ke, 968 "%s%p,%s,%s,%d,%p,%p", 969 i > 0 ? " " : "", 970 (void *)ke[i].ident, 971 xlookup(kevent_filters, ke[i].filter), 972 xlookup_bits(kevent_flags, ke[i].flags), 973 ke[i].fflags, 974 (void *)ke[i].data, 975 (void *)ke[i].udata); 976 if (u > 0) 977 used += u < per_ke ? u : per_ke; 978 } 979 tmp[used++] = '}'; 980 tmp[used++] = '\0'; 981 } else 982 asprintf(&tmp, "0x%lx", args[sc->offset]); 983 free(ke); 984 } 985 break; 986 case Stat: 987 { 988 struct stat st; 989 if (get_struct(fd, (void *)args[sc->offset], &st, sizeof(st)) != -1) { 990 char mode[12]; 991 strmode(st.st_mode, mode); 992 asprintf(&tmp, "{mode=%s,inode=%jd,size=%jd,blksize=%ld}", 993 mode, 994 (intmax_t)st.st_ino,(intmax_t)st.st_size,(long)st.st_blksize); 995 } else 996 asprintf(&tmp, "0x%lx", args[sc->offset]); 997 } 998 break; 999 case Rusage: 1000 { 1001 struct rusage ru; 1002 if (get_struct(fd, (void *)args[sc->offset], &ru, sizeof(ru)) != -1) 1003 asprintf(&tmp, "{u=%ld.%06ld,s=%ld.%06ld,in=%ld,out=%ld}", 1004 (long)ru.ru_utime.tv_sec, ru.ru_utime.tv_usec, 1005 (long)ru.ru_stime.tv_sec, ru.ru_stime.tv_usec, 1006 ru.ru_inblock, ru.ru_oublock); 1007 else 1008 asprintf(&tmp, "0x%lx", args[sc->offset]); 1009 } 1010 break; 1011 case Rlimit: 1012 { 1013 struct rlimit rl; 1014 if (get_struct(fd, (void *)args[sc->offset], &rl, sizeof(rl)) != -1) 1015 asprintf(&tmp, "{cur=%ju,max=%ju}", 1016 rl.rlim_cur, rl.rlim_max); 1017 else 1018 asprintf(&tmp, "0x%lx", args[sc->offset]); 1019 } 1020 break; 1021 default: 1022 errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK); 1023 } 1024 return tmp; 1025 } 1026 1027 1028 /* 1029 * print_syscall 1030 * Print (to outfile) the system call and its arguments. Note that 1031 * nargs is the number of arguments (not the number of words; this is 1032 * potentially confusing, I know). 1033 */ 1034 1035 void 1036 print_syscall(struct trussinfo *trussinfo, const char *name, int nargs, char **s_args) { 1037 int i; 1038 int len = 0; 1039 struct timespec timediff; 1040 1041 if (trussinfo->flags & FOLLOWFORKS) 1042 len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid); 1043 1044 if (name != NULL && (!strcmp(name, "execve") || !strcmp(name, "exit"))) { 1045 clock_gettime(CLOCK_REALTIME, &trussinfo->after); 1046 } 1047 1048 if (trussinfo->flags & ABSOLUTETIMESTAMPS) { 1049 timespecsubt(&trussinfo->after, &trussinfo->start_time, &timediff); 1050 len += fprintf(trussinfo->outfile, "%ld.%09ld ", 1051 (long)timediff.tv_sec, timediff.tv_nsec); 1052 } 1053 1054 if (trussinfo->flags & RELATIVETIMESTAMPS) { 1055 timespecsubt(&trussinfo->after, &trussinfo->before, &timediff); 1056 len += fprintf(trussinfo->outfile, "%ld.%09ld ", 1057 (long)timediff.tv_sec, timediff.tv_nsec); 1058 } 1059 1060 len += fprintf(trussinfo->outfile, "%s(", name); 1061 1062 for (i = 0; i < nargs; i++) { 1063 if (s_args[i]) 1064 len += fprintf(trussinfo->outfile, "%s", s_args[i]); 1065 else 1066 len += fprintf(trussinfo->outfile, "<missing argument>"); 1067 len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? "," : ""); 1068 } 1069 len += fprintf(trussinfo->outfile, ")"); 1070 for (i = 0; i < 6 - (len / 8); i++) 1071 fprintf(trussinfo->outfile, "\t"); 1072 } 1073 1074 void 1075 print_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs, 1076 char **s_args, int errorp, long retval) 1077 { 1078 print_syscall(trussinfo, name, nargs, s_args); 1079 fflush(trussinfo->outfile); 1080 if (errorp) { 1081 fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval, strerror(retval)); 1082 } else { 1083 fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval, retval); 1084 } 1085 } 1086