1 /* $OpenBSD: kdump.c,v 1.39 2007/05/29 02:01:03 deraadt Exp $ */ 2 3 /*- 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 copyright[] = 34 "@(#) Copyright (c) 1988, 1993\n\ 35 The Regents of the University of California. All rights reserved.\n"; 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)kdump.c 8.4 (Berkeley) 4/28/95"; 41 #endif 42 static const char rcsid[] = "$OpenBSD: kdump.c,v 1.39 2007/05/29 02:01:03 deraadt Exp $"; 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #include <sys/time.h> 47 #include <sys/uio.h> 48 #include <sys/ktrace.h> 49 #include <sys/ioctl.h> 50 #include <sys/ptrace.h> 51 #include <sys/sysctl.h> 52 #define _KERNEL 53 #include <sys/errno.h> 54 #undef _KERNEL 55 56 #include <ctype.h> 57 #include <err.h> 58 #include <signal.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <unistd.h> 63 #include <vis.h> 64 65 #include "ktrace.h" 66 #include "kdump.h" 67 #include "extern.h" 68 69 int timestamp, decimal, iohex, fancy = 1, tail, maxdata; 70 char *tracefile = DEF_TRACEFILE; 71 struct ktr_header ktr_header; 72 pid_t pid = -1; 73 74 #define eqs(s1, s2) (strcmp((s1), (s2)) == 0) 75 76 #include <sys/syscall.h> 77 78 #include <compat/bsdos/bsdos_syscall.h> 79 #include <compat/freebsd/freebsd_syscall.h> 80 #if defined(__hppa__) || defined(__m68k__) 81 #include <compat/hpux/hpux_syscall.h> 82 #endif 83 #include <compat/ibcs2/ibcs2_syscall.h> 84 #include <compat/linux/linux_syscall.h> 85 #include <compat/osf1/osf1_syscall.h> 86 #include <compat/sunos/sunos_syscall.h> 87 #include <compat/svr4/svr4_syscall.h> 88 #include <compat/ultrix/ultrix_syscall.h> 89 90 #define KTRACE 91 #define PTRACE 92 #define NFSCLIENT 93 #define NFSSERVER 94 #define SYSVSEM 95 #define SYSVMSG 96 #define SYSVSHM 97 #define LFS 98 #define RTHREADS 99 #include <kern/syscalls.c> 100 101 #include <compat/bsdos/bsdos_syscalls.c> 102 #include <compat/freebsd/freebsd_syscalls.c> 103 #if defined(__hppa__) || defined(__m68k__) 104 #include <compat/hpux/hpux_syscalls.c> 105 #endif 106 #include <compat/ibcs2/ibcs2_syscalls.c> 107 #include <compat/linux/linux_syscalls.c> 108 #include <compat/osf1/osf1_syscalls.c> 109 #include <compat/sunos/sunos_syscalls.c> 110 #include <compat/svr4/svr4_syscalls.c> 111 #include <compat/ultrix/ultrix_syscalls.c> 112 #undef KTRACE 113 #undef PTRACE 114 #undef NFSCLIENT 115 #undef NFSSERVER 116 #undef SYSVSEM 117 #undef SYSVMSG 118 #undef SYSVSHM 119 #undef LFS 120 #undef RTHREADS 121 122 struct emulation { 123 char *name; /* Emulation name */ 124 char **sysnames; /* Array of system call names */ 125 int nsysnames; /* Number of */ 126 }; 127 128 static struct emulation emulations[] = { 129 { "native", syscallnames, SYS_MAXSYSCALL }, 130 #if defined(__hppa__) || defined(__m68k__) 131 { "hpux", hpux_syscallnames, HPUX_SYS_MAXSYSCALL }, 132 #endif 133 { "ibcs2", ibcs2_syscallnames, IBCS2_SYS_MAXSYSCALL }, 134 { "linux", linux_syscallnames, LINUX_SYS_MAXSYSCALL }, 135 { "osf1", osf1_syscallnames, OSF1_SYS_MAXSYSCALL }, 136 { "sunos", sunos_syscallnames, SUNOS_SYS_MAXSYSCALL }, 137 { "svr4", svr4_syscallnames, SVR4_SYS_MAXSYSCALL }, 138 { "ultrix", ultrix_syscallnames, ULTRIX_SYS_MAXSYSCALL }, 139 { "bsdos", bsdos_syscallnames, BSDOS_SYS_MAXSYSCALL }, 140 { "freebsd", freebsd_syscallnames, FREEBSD_SYS_MAXSYSCALL }, 141 { NULL, NULL, NULL } 142 }; 143 144 struct emulation *current; 145 146 147 static char *ptrace_ops[] = { 148 "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U", 149 "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE", 150 "PT_KILL", "PT_ATTACH", "PT_DETACH", "PT_IO", 151 }; 152 153 static int fread_tail(void *, size_t, size_t); 154 static void dumpheader(struct ktr_header *); 155 static void ktrcsw(struct ktr_csw *); 156 static void ktremul(char *, size_t); 157 static void ktrgenio(struct ktr_genio *, size_t); 158 static void ktrnamei(const char *, size_t); 159 static void ktrpsig(struct ktr_psig *); 160 static void ktrsyscall(struct ktr_syscall *); 161 static void ktrsysret(struct ktr_sysret *); 162 static void setemul(const char *); 163 static void usage(void); 164 165 int 166 main(int argc, char *argv[]) 167 { 168 int ch, silent; 169 size_t ktrlen, size; 170 int trpoints = ALL_POINTS; 171 void *m; 172 173 current = &emulations[0]; /* native */ 174 175 while ((ch = getopt(argc, argv, "e:f:dlm:nRp:Tt:xX")) != -1) 176 switch (ch) { 177 case 'e': 178 setemul(optarg); 179 break; 180 case 'f': 181 tracefile = optarg; 182 break; 183 case 'd': 184 decimal = 1; 185 break; 186 case 'l': 187 tail = 1; 188 break; 189 case 'm': 190 maxdata = atoi(optarg); 191 break; 192 case 'n': 193 fancy = 0; 194 break; 195 case 'p': 196 pid = atoi(optarg); 197 break; 198 case 'R': 199 timestamp = 2; /* relative timestamp */ 200 break; 201 case 'T': 202 timestamp = 1; 203 break; 204 case 't': 205 trpoints = getpoints(optarg); 206 if (trpoints < 0) 207 errx(1, "unknown trace point in %s", optarg); 208 break; 209 case 'x': 210 iohex = 1; 211 break; 212 case 'X': 213 iohex = 2; 214 break; 215 default: 216 usage(); 217 } 218 if (argc > optind) 219 usage(); 220 221 m = malloc(size = 1025); 222 if (m == NULL) 223 err(1, NULL); 224 if (!freopen(tracefile, "r", stdin)) 225 err(1, "%s", tracefile); 226 while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) { 227 silent = 0; 228 if (pid != -1 && pid != ktr_header.ktr_pid) 229 silent = 1; 230 if (silent == 0 && trpoints & (1<<ktr_header.ktr_type)) 231 dumpheader(&ktr_header); 232 ktrlen = ktr_header.ktr_len; 233 if (ktrlen > size) { 234 void *newm; 235 236 newm = realloc(m, ktrlen+1); 237 if (newm == NULL) 238 err(1, NULL); 239 m = newm; 240 size = ktrlen; 241 } 242 if (ktrlen && fread_tail(m, ktrlen, 1) == 0) 243 errx(1, "data too short"); 244 if (silent) 245 continue; 246 if ((trpoints & (1<<ktr_header.ktr_type)) == 0) 247 continue; 248 switch (ktr_header.ktr_type) { 249 case KTR_SYSCALL: 250 ktrsyscall((struct ktr_syscall *)m); 251 break; 252 case KTR_SYSRET: 253 ktrsysret((struct ktr_sysret *)m); 254 break; 255 case KTR_NAMEI: 256 ktrnamei(m, ktrlen); 257 break; 258 case KTR_GENIO: 259 ktrgenio((struct ktr_genio *)m, ktrlen); 260 break; 261 case KTR_PSIG: 262 ktrpsig((struct ktr_psig *)m); 263 break; 264 case KTR_CSW: 265 ktrcsw((struct ktr_csw *)m); 266 break; 267 case KTR_EMUL: 268 ktremul(m, ktrlen); 269 break; 270 } 271 if (tail) 272 (void)fflush(stdout); 273 } 274 exit(0); 275 } 276 277 static int 278 fread_tail(void *buf, size_t size, size_t num) 279 { 280 int i; 281 282 while ((i = fread(buf, size, num, stdin)) == 0 && tail) { 283 (void)sleep(1); 284 clearerr(stdin); 285 } 286 return (i); 287 } 288 289 static void 290 dumpheader(struct ktr_header *kth) 291 { 292 static struct timeval prevtime; 293 char unknown[64], *type; 294 struct timeval temp; 295 296 switch (kth->ktr_type) { 297 case KTR_SYSCALL: 298 type = "CALL"; 299 break; 300 case KTR_SYSRET: 301 type = "RET "; 302 break; 303 case KTR_NAMEI: 304 type = "NAMI"; 305 break; 306 case KTR_GENIO: 307 type = "GIO "; 308 break; 309 case KTR_PSIG: 310 type = "PSIG"; 311 break; 312 case KTR_CSW: 313 type = "CSW"; 314 break; 315 case KTR_EMUL: 316 type = "EMUL"; 317 break; 318 default: 319 (void)snprintf(unknown, sizeof unknown, "UNKNOWN(%d)", 320 kth->ktr_type); 321 type = unknown; 322 } 323 324 (void)printf("%6ld %-8.*s ", (long)kth->ktr_pid, MAXCOMLEN, 325 kth->ktr_comm); 326 if (timestamp) { 327 if (timestamp == 2) { 328 timersub(&kth->ktr_time, &prevtime, &temp); 329 prevtime = kth->ktr_time; 330 } else 331 temp = kth->ktr_time; 332 (void)printf("%ld.%06ld ", temp.tv_sec, temp.tv_usec); 333 } 334 (void)printf("%s ", type); 335 } 336 337 static void 338 ioctldecode(u_long cmd) 339 { 340 char dirbuf[4], *dir = dirbuf; 341 342 if (cmd & IOC_IN) 343 *dir++ = 'W'; 344 if (cmd & IOC_OUT) 345 *dir++ = 'R'; 346 *dir = '\0'; 347 348 printf(decimal ? ",_IO%s('%c',%lu" : ",_IO%s('%c',%#lx", 349 dirbuf, (int)((cmd >> 8) & 0xff), cmd & 0xff); 350 if ((cmd & IOC_VOID) == 0) 351 printf(decimal ? ",%lu)" : ",%#lx)", (cmd >> 16) & 0xff); 352 else 353 printf(")"); 354 } 355 356 static void 357 ktrsyscall(struct ktr_syscall *ktr) 358 { 359 int argsize = ktr->ktr_argsize; 360 register_t *ap; 361 362 if (ktr->ktr_code >= current->nsysnames || ktr->ktr_code < 0) 363 (void)printf("[%d]", ktr->ktr_code); 364 else 365 (void)printf("%s", current->sysnames[ktr->ktr_code]); 366 ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall)); 367 (void)putchar('('); 368 if (argsize) { 369 char c = '\0'; 370 if (fancy) { 371 if (ktr->ktr_code == SYS_ioctl) { 372 const char *cp; 373 374 if (decimal) 375 (void)printf("%ld", (long)*ap); 376 else 377 (void)printf("%#lx", (long)*ap); 378 ap++; 379 argsize -= sizeof(register_t); 380 if ((cp = ioctlname(*ap)) != NULL) 381 (void)printf(",%s", cp); 382 else 383 ioctldecode(*ap); 384 c = ','; 385 ap++; 386 argsize -= sizeof(register_t); 387 } else if (ktr->ktr_code == SYS___sysctl) { 388 int *np, n; 389 390 n = ap[1]; 391 if (n > CTL_MAXNAME) 392 n = CTL_MAXNAME; 393 np = (int *)(ap + 6); 394 for (; n--; np++) { 395 if (c) 396 putchar(c); 397 printf("%d", *np); 398 c = '.'; 399 } 400 401 c = ','; 402 ap += 2; 403 argsize -= 2 * sizeof(register_t); 404 } else if (ktr->ktr_code == SYS_ptrace) { 405 if (*ap >= 0 && *ap < 406 sizeof(ptrace_ops) / sizeof(ptrace_ops[0])) 407 (void)printf("%s", ptrace_ops[*ap]); 408 else switch(*ap) { 409 #ifdef PT_GETFPREGS 410 case PT_GETFPREGS: 411 (void)printf("PT_GETFPREGS"); 412 break; 413 #endif 414 case PT_GETREGS: 415 (void)printf("PT_GETREGS"); 416 break; 417 #ifdef PT_SETFPREGS 418 case PT_SETFPREGS: 419 (void)printf("PT_SETFPREGS"); 420 break; 421 #endif 422 case PT_SETREGS: 423 (void)printf("PT_SETREGS"); 424 break; 425 #ifdef PT_STEP 426 case PT_STEP: 427 (void)printf("PT_STEP"); 428 break; 429 #endif 430 #ifdef PT_WCOOKIE 431 case PT_WCOOKIE: 432 (void)printf("PT_WCOOKIE"); 433 break; 434 #endif 435 default: 436 (void)printf("%ld", (long)*ap); 437 break; 438 } 439 c = ','; 440 ap++; 441 argsize -= sizeof(register_t); 442 } 443 } 444 while (argsize) { 445 if (c) 446 putchar(c); 447 if (decimal) 448 (void)printf("%ld", (long)*ap); 449 else 450 (void)printf("%#lx", (long)*ap); 451 c = ','; 452 ap++; 453 argsize -= sizeof(register_t); 454 } 455 } 456 (void)printf(")\n"); 457 } 458 459 static void 460 ktrsysret(struct ktr_sysret *ktr) 461 { 462 int ret = ktr->ktr_retval; 463 int error = ktr->ktr_error; 464 int code = ktr->ktr_code; 465 466 if (code >= current->nsysnames || code < 0) 467 (void)printf("[%d] ", code); 468 else 469 (void)printf("%s ", current->sysnames[code]); 470 471 if (error == 0) { 472 if (fancy) { 473 (void)printf("%d", ret); 474 if (ret < 0 || ret > 9) 475 (void)printf("/%#x", ret); 476 } else { 477 if (decimal) 478 (void)printf("%d", ret); 479 else 480 (void)printf("%#x", ret); 481 } 482 } else if (error == ERESTART) 483 (void)printf("RESTART"); 484 else if (error == EJUSTRETURN) 485 (void)printf("JUSTRETURN"); 486 else { 487 (void)printf("-1 errno %d", ktr->ktr_error); 488 if (fancy) 489 (void)printf(" %s", strerror(ktr->ktr_error)); 490 } 491 (void)putchar('\n'); 492 } 493 494 static void 495 ktrnamei(const char *cp, size_t len) 496 { 497 (void)printf("\"%.*s\"\n", (int)len, cp); 498 } 499 500 static void 501 ktremul(char *cp, size_t len) 502 { 503 char name[1024]; 504 505 if (len >= sizeof(name)) 506 errx(1, "Emulation name too long"); 507 508 strncpy(name, cp, len); 509 name[len] = '\0'; 510 (void)printf("\"%s\"\n", name); 511 512 setemul(name); 513 } 514 515 static void 516 ktrgenio(struct ktr_genio *ktr, size_t len) 517 { 518 unsigned char *dp = (unsigned char *)ktr + sizeof(struct ktr_genio); 519 int i, j; 520 size_t datalen = len - sizeof(struct ktr_genio); 521 static int screenwidth = 0; 522 int col = 0, width, bpl; 523 unsigned char visbuf[5], *cp, c; 524 525 if (screenwidth == 0) { 526 struct winsize ws; 527 528 if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 && 529 ws.ws_col > 8) 530 screenwidth = ws.ws_col; 531 else 532 screenwidth = 80; 533 } 534 printf("fd %d %s %zu bytes\n", ktr->ktr_fd, 535 ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen); 536 if (maxdata && datalen > maxdata) 537 datalen = maxdata; 538 if (iohex && !datalen) 539 return; 540 if (iohex == 1) { 541 putchar('\t'); 542 col = 8; 543 for (i = 0; i < datalen; i++) { 544 printf("%02x", dp[i]); 545 col += 3; 546 if (i < datalen - 1) { 547 if (col + 3 > screenwidth) { 548 printf("\n\t"); 549 col = 8; 550 } else 551 putchar(' '); 552 } 553 } 554 putchar('\n'); 555 return; 556 } 557 if (iohex == 2) { 558 bpl = (screenwidth - 13)/4; 559 if (bpl <= 0) 560 bpl = 1; 561 for (i = 0; i < datalen; i += bpl) { 562 printf(" %04x: ", i); 563 for (j = 0; j < bpl; j++) { 564 if (i+j >= datalen) 565 printf(" "); 566 else 567 printf("%02x ", dp[i+j]); 568 } 569 putchar(' '); 570 for (j = 0; j < bpl; j++) { 571 if (i+j >= datalen) 572 break; 573 c = dp[i+j]; 574 if (!isprint(c)) 575 c = '.'; 576 putchar(c); 577 } 578 putchar('\n'); 579 } 580 return; 581 } 582 (void)printf(" \""); 583 col = 8; 584 for (; datalen > 0; datalen--, dp++) { 585 (void)vis(visbuf, *dp, VIS_CSTYLE, *(dp+1)); 586 cp = visbuf; 587 588 /* 589 * Keep track of printables and 590 * space chars (like fold(1)). 591 */ 592 if (col == 0) { 593 (void)putchar('\t'); 594 col = 8; 595 } 596 switch (*cp) { 597 case '\n': 598 col = 0; 599 (void)putchar('\n'); 600 continue; 601 case '\t': 602 width = 8 - (col&07); 603 break; 604 default: 605 width = strlen(cp); 606 } 607 if (col + width > (screenwidth-2)) { 608 (void)printf("\\\n\t"); 609 col = 8; 610 } 611 col += width; 612 do { 613 (void)putchar(*cp++); 614 } while (*cp); 615 } 616 if (col == 0) 617 (void)printf(" "); 618 (void)printf("\"\n"); 619 } 620 621 static void 622 ktrpsig(struct ktr_psig *psig) 623 { 624 (void)printf("SIG%s ", sys_signame[psig->signo]); 625 if (psig->action == SIG_DFL) 626 (void)printf("SIG_DFL code %d", psig->code); 627 else 628 (void)printf("caught handler=0x%lx mask=0x%x", 629 (u_long)psig->action, psig->mask); 630 switch (psig->signo) { 631 case SIGSEGV: 632 case SIGILL: 633 case SIGBUS: 634 case SIGFPE: 635 printf(" addr=%p trapno=%d", psig->si.si_addr, 636 psig->si.si_trapno); 637 break; 638 default: 639 break; 640 } 641 printf("\n"); 642 } 643 644 static void 645 ktrcsw(struct ktr_csw *cs) 646 { 647 (void)printf("%s %s\n", cs->out ? "stop" : "resume", 648 cs->user ? "user" : "kernel"); 649 } 650 651 static void 652 usage(void) 653 { 654 655 extern char *__progname; 656 fprintf(stderr, "usage: %s " 657 "[-dlnRTXx] [-e emulation] [-p pid] [-f trfile] [-m maxdata] " 658 "[-t [ceinsw]]\n", __progname); 659 exit(1); 660 } 661 662 static void 663 setemul(const char *name) 664 { 665 int i; 666 667 for (i = 0; emulations[i].name != NULL; i++) 668 if (strcmp(emulations[i].name, name) == 0) { 669 current = &emulations[i]; 670 return; 671 } 672 warnx("Emulation `%s' unknown", name); 673 } 674