1 /* $NetBSD: kdump.c,v 1.25 1999/12/31 22:27:59 eeh 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __COPYRIGHT("@(#) Copyright (c) 1988, 1993\n\ 39 The Regents of the University of California. All rights reserved.\n"); 40 #endif /* not lint */ 41 42 #ifndef lint 43 #if 0 44 static char sccsid[] = "@(#)kdump.c 8.4 (Berkeley) 4/28/95"; 45 #else 46 __RCSID("$NetBSD: kdump.c,v 1.25 1999/12/31 22:27:59 eeh Exp $"); 47 #endif 48 #endif /* not lint */ 49 50 #include <sys/param.h> 51 #define _KERNEL 52 #include <sys/errno.h> 53 #undef _KERNEL 54 #include <sys/time.h> 55 #include <sys/uio.h> 56 #include <sys/ktrace.h> 57 #include <sys/ioctl.h> 58 #include <sys/ptrace.h> 59 60 #include <err.h> 61 #include <signal.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <unistd.h> 66 #include <vis.h> 67 68 #include "ktrace.h" 69 70 int timestamp, decimal, fancy = 1, tail, maxdata; 71 char *tracefile = DEF_TRACEFILE; 72 struct ktr_header ktr_header; 73 74 #define eqs(s1, s2) (strcmp((s1), (s2)) == 0) 75 76 #include <sys/syscall.h> 77 78 #include "../../sys/compat/netbsd32/netbsd32_syscall.h" 79 #include "../../sys/compat/freebsd/freebsd_syscall.h" 80 #include "../../sys/compat/hpux/hpux_syscall.h" 81 #include "../../sys/compat/ibcs2/ibcs2_syscall.h" 82 #include "../../sys/compat/linux/linux_syscall.h" 83 #include "../../sys/compat/osf1/osf1_syscall.h" 84 #include "../../sys/compat/sunos/sunos_syscall.h" 85 #include "../../sys/compat/svr4/svr4_syscall.h" 86 #include "../../sys/compat/ultrix/ultrix_syscall.h" 87 88 #define KTRACE 89 #include "../../sys/kern/syscalls.c" 90 91 #include "../../sys/compat/netbsd32/netbsd32_syscalls.c" 92 #include "../../sys/compat/freebsd/freebsd_syscalls.c" 93 #include "../../sys/compat/hpux/hpux_syscalls.c" 94 #include "../../sys/compat/ibcs2/ibcs2_syscalls.c" 95 #include "../../sys/compat/linux/linux_syscalls.c" 96 #include "../../sys/compat/osf1/osf1_syscalls.c" 97 #include "../../sys/compat/sunos/sunos_syscalls.c" 98 #include "../../sys/compat/svr4/svr4_syscalls.c" 99 #include "../../sys/compat/ultrix/ultrix_syscalls.c" 100 101 #include "../../sys/compat/hpux/hpux_errno.c" 102 #include "../../sys/compat/svr4/svr4_errno.c" 103 #include "../../sys/compat/ibcs2/ibcs2_errno.c" 104 #include "../../sys/compat/linux/common/linux_errno.c" 105 #undef KTRACE 106 107 struct emulation { 108 char *name; /* Emulation name */ 109 char **sysnames; /* Array of system call names */ 110 int nsysnames; /* Number of */ 111 int *errno; /* Array of error number mapping */ 112 int nerrno; /* number of elements in array */ 113 }; 114 115 #define NELEM(a) (sizeof(a) / sizeof(a[0])) 116 117 static struct emulation emulations[] = { 118 { "netbsd", syscallnames, SYS_MAXSYSCALL, 119 NULL, 0 }, 120 { "netbsd32", netbsd32_syscallnames, SYS_MAXSYSCALL, 121 NULL, 0 }, 122 { "freebsd", freebsd_syscallnames, FREEBSD_SYS_MAXSYSCALL, 123 NULL, 0 }, 124 { "hpux", hpux_syscallnames, HPUX_SYS_MAXSYSCALL, 125 native_to_hpux_errno, NELEM(native_to_hpux_errno) }, 126 { "ibcs2", ibcs2_syscallnames, IBCS2_SYS_MAXSYSCALL, 127 native_to_ibcs2_errno, NELEM(native_to_ibcs2_errno) }, 128 { "linux", linux_syscallnames, LINUX_SYS_MAXSYSCALL, 129 native_to_linux_errno, NELEM(native_to_linux_errno) }, 130 { "osf1", osf1_syscallnames, OSF1_SYS_MAXSYSCALL, 131 NULL, 0 }, 132 { "sunos", sunos_syscallnames, SUNOS_SYS_MAXSYSCALL, 133 NULL, 0 }, 134 { "svr4", svr4_syscallnames, SVR4_SYS_MAXSYSCALL, 135 native_to_svr4_errno, NELEM(native_to_svr4_errno) }, 136 { "ultrix", ultrix_syscallnames, ULTRIX_SYS_MAXSYSCALL, 137 NULL, 0 }, 138 { NULL, NULL, 0, 139 NULL, 0 } 140 }; 141 142 struct emulation *current; 143 144 static const char *ptrace_ops[] = { 145 "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U", 146 "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE", 147 "PT_KILL", "PT_ATTACH", "PT_DETACH", 148 }; 149 150 int main __P((int, char **)); 151 int fread_tail __P((char *, int, int)); 152 void dumpheader __P((struct ktr_header *)); 153 void ioctldecode __P((u_long)); 154 void ktrsyscall __P((struct ktr_syscall *)); 155 void ktrsysret __P((struct ktr_sysret *)); 156 void ktrnamei __P((char *, int)); 157 void ktremul __P((char *, int)); 158 void ktrgenio __P((struct ktr_genio *, int)); 159 void ktrpsig __P((struct ktr_psig *)); 160 void ktrcsw __P((struct ktr_csw *)); 161 void usage __P((void)); 162 void setemul __P((char *)); 163 void eprint __P((int)); 164 char *ioctlname __P((long)); 165 166 int 167 main(argc, argv) 168 int argc; 169 char *argv[]; 170 { 171 int ch, ktrlen, size; 172 void *m; 173 int trpoints = ALL_POINTS; 174 175 current = &emulations[0]; /* NetBSD */ 176 177 while ((ch = getopt(argc, argv, "e:f:dlm:nRTt:")) != -1) 178 switch (ch) { 179 case 'e': 180 setemul(optarg); 181 break; 182 case 'f': 183 tracefile = optarg; 184 break; 185 case 'd': 186 decimal = 1; 187 break; 188 case 'l': 189 tail = 1; 190 break; 191 case 'm': 192 maxdata = atoi(optarg); 193 break; 194 case 'n': 195 fancy = 0; 196 break; 197 case 'R': 198 timestamp = 2; /* relative timestamp */ 199 break; 200 case 'T': 201 timestamp = 1; 202 break; 203 case 't': 204 trpoints = getpoints(optarg); 205 if (trpoints < 0) 206 errx(1, "unknown trace point in %s", optarg); 207 break; 208 default: 209 usage(); 210 } 211 argv += optind; 212 argc -= optind; 213 214 if (argc > 1) 215 usage(); 216 217 m = malloc(size = 1025); 218 if (m == NULL) 219 errx(1, "%s", strerror(ENOMEM)); 220 if (!freopen(tracefile, "r", stdin)) 221 err(1, "%s", tracefile); 222 while (fread_tail((char *)&ktr_header, sizeof(struct ktr_header), 1)) { 223 if (trpoints & (1<<ktr_header.ktr_type)) 224 dumpheader(&ktr_header); 225 if ((ktrlen = ktr_header.ktr_len) < 0) 226 errx(1, "bogus length 0x%x", ktrlen); 227 if (ktrlen > size) { 228 m = (void *)realloc(m, ktrlen+1); 229 if (m == NULL) 230 errx(1, "%s", strerror(ENOMEM)); 231 size = ktrlen; 232 } 233 if (ktrlen && fread_tail(m, ktrlen, 1) == 0) 234 errx(1, "data too short"); 235 if ((trpoints & (1<<ktr_header.ktr_type)) == 0) 236 continue; 237 switch (ktr_header.ktr_type) { 238 case KTR_SYSCALL: 239 ktrsyscall((struct ktr_syscall *)m); 240 break; 241 case KTR_SYSRET: 242 ktrsysret((struct ktr_sysret *)m); 243 break; 244 case KTR_NAMEI: 245 ktrnamei(m, ktrlen); 246 break; 247 case KTR_GENIO: 248 ktrgenio((struct ktr_genio *)m, ktrlen); 249 break; 250 case KTR_PSIG: 251 ktrpsig((struct ktr_psig *)m); 252 break; 253 case KTR_CSW: 254 ktrcsw((struct ktr_csw *)m); 255 break; 256 case KTR_EMUL: 257 ktremul(m, ktrlen); 258 break; 259 } 260 if (tail) 261 (void)fflush(stdout); 262 } 263 return (0); 264 } 265 266 int 267 fread_tail(buf, size, num) 268 char *buf; 269 int num, size; 270 { 271 int i; 272 273 while ((i = fread(buf, size, num, stdin)) == 0 && tail) { 274 (void)sleep(1); 275 clearerr(stdin); 276 } 277 return (i); 278 } 279 280 void 281 dumpheader(kth) 282 struct ktr_header *kth; 283 { 284 char unknown[64], *type; 285 static struct timeval prevtime; 286 struct timeval temp; 287 288 switch (kth->ktr_type) { 289 case KTR_SYSCALL: 290 type = "CALL"; 291 break; 292 case KTR_SYSRET: 293 type = "RET "; 294 break; 295 case KTR_NAMEI: 296 type = "NAMI"; 297 break; 298 case KTR_GENIO: 299 type = "GIO "; 300 break; 301 case KTR_PSIG: 302 type = "PSIG"; 303 break; 304 case KTR_CSW: 305 type = "CSW"; 306 break; 307 case KTR_EMUL: 308 type = "EMUL"; 309 break; 310 default: 311 (void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type); 312 type = unknown; 313 } 314 315 (void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm); 316 if (timestamp) { 317 if (timestamp == 2) { 318 timersub(&kth->ktr_time, &prevtime, &temp); 319 prevtime = kth->ktr_time; 320 } else 321 temp = kth->ktr_time; 322 (void)printf("%ld.%06ld ", temp.tv_sec, temp.tv_usec); 323 } 324 (void)printf("%s ", type); 325 } 326 327 void 328 ioctldecode(cmd) 329 u_long cmd; 330 { 331 char dirbuf[4], *dir = dirbuf; 332 333 if (cmd & IOC_IN) 334 *dir++ = 'W'; 335 if (cmd & IOC_OUT) 336 *dir++ = 'R'; 337 *dir = '\0'; 338 339 printf(decimal ? ",_IO%s('%c',%ld" : ",_IO%s('%c',%#lx", 340 dirbuf, (cmd >> 8) & 0xff, cmd & 0xff); 341 if ((cmd & IOC_VOID) == 0) 342 printf(decimal ? ",%ld)" : ",%#lx)", (cmd >> 16) & 0xff); 343 else 344 printf(")"); 345 } 346 347 void 348 ktrsyscall(ktr) 349 struct ktr_syscall *ktr; 350 { 351 int argsize = ktr->ktr_argsize; 352 register_t *ap; 353 354 if (ktr->ktr_code >= current->nsysnames || ktr->ktr_code < 0) 355 (void)printf("[%d]", ktr->ktr_code); 356 else 357 (void)printf("%s", current->sysnames[ktr->ktr_code]); 358 ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall)); 359 if (argsize) { 360 char c = '('; 361 if (fancy) { 362 if (ktr->ktr_code == SYS_ioctl) { 363 char *cp; 364 if (decimal) 365 (void)printf("(%ld", (long)*ap); 366 else 367 (void)printf("(%#lx", (long)*ap); 368 ap++; 369 argsize -= sizeof(register_t); 370 if ((cp = ioctlname(*ap)) != NULL) 371 (void)printf(",%s", cp); 372 else 373 ioctldecode(*ap); 374 c = ','; 375 ap++; 376 argsize -= sizeof(register_t); 377 } else if (ktr->ktr_code == SYS_ptrace) { 378 if (*ap >= 0 && *ap <= 379 sizeof(ptrace_ops) / sizeof(ptrace_ops[0])) 380 (void)printf("(%s", ptrace_ops[*ap]); 381 else 382 (void)printf("(%ld", (long)*ap); 383 c = ','; 384 ap++; 385 argsize -= sizeof(register_t); 386 } 387 } 388 while (argsize) { 389 if (decimal) 390 (void)printf("%c%ld", c, (long)*ap); 391 else 392 (void)printf("%c%#lx", c, (long)*ap); 393 c = ','; 394 ap++; 395 argsize -= sizeof(register_t); 396 } 397 (void)putchar(')'); 398 } 399 (void)putchar('\n'); 400 } 401 402 void 403 ktrsysret(ktr) 404 struct ktr_sysret *ktr; 405 { 406 register_t ret = ktr->ktr_retval; 407 int error = ktr->ktr_error; 408 int code = ktr->ktr_code; 409 410 if (code >= current->nsysnames || code < 0) 411 (void)printf("[%d] ", code); 412 else 413 (void)printf("%s ", current->sysnames[code]); 414 415 switch (error) { 416 case 0: 417 if (fancy) { 418 (void)printf("%ld", (long)ret); 419 if (ret < 0 || ret > 9) 420 (void)printf("/%#lx", (long)ret); 421 } else { 422 if (decimal) 423 (void)printf("%ld", (long)ret); 424 else 425 (void)printf("%#lx", (long)ret); 426 } 427 break; 428 429 default: 430 eprint(error); 431 break; 432 } 433 (void)putchar('\n'); 434 435 } 436 437 /* 438 * We print the original emulation's error numerically, but we 439 * translate it to netbsd to print it symbolically. 440 */ 441 void 442 eprint(e) 443 int e; 444 { 445 int i = e; 446 447 if (current->errno) { 448 449 /* No remapping for ERESTART and EJUSTRETURN */ 450 /* Kludge for linux that has negative error numbers */ 451 if (current->errno[2] > 0 && e < 0) 452 goto normal; 453 454 for (i = 0; i < current->nerrno; i++) 455 if (e == current->errno[i]) 456 break; 457 458 if (i == current->nerrno) { 459 printf("-1 unknown errno %d", e); 460 return; 461 } 462 } 463 464 normal: 465 switch (i) { 466 case ERESTART: 467 (void)printf("RESTART"); 468 break; 469 470 case EJUSTRETURN: 471 (void)printf("JUSTRETURN"); 472 break; 473 474 default: 475 (void)printf("-1 errno %d", e); 476 if (fancy) 477 (void)printf(" %s", strerror(i)); 478 } 479 } 480 481 void 482 ktrnamei(cp, len) 483 char *cp; 484 int len; 485 { 486 487 (void)printf("\"%.*s\"\n", len, cp); 488 } 489 490 void 491 ktremul(cp, len) 492 char *cp; 493 int len; 494 { 495 char name[1024]; 496 497 if (len >= sizeof(name)) 498 errx(1, "Emulation name too long"); 499 500 strncpy(name, cp, len); 501 name[len] = '\0'; 502 (void)printf("\"%s\"\n", name); 503 504 setemul(name); 505 } 506 507 void 508 ktrgenio(ktr, len) 509 struct ktr_genio *ktr; 510 int len; 511 { 512 int datalen = len - sizeof (struct ktr_genio); 513 char *dp = (char *)ktr + sizeof (struct ktr_genio); 514 char *cp; 515 int col = 0; 516 int width; 517 char visbuf[5]; 518 static int screenwidth = 0; 519 520 if (screenwidth == 0) { 521 struct winsize ws; 522 523 if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 && 524 ws.ws_col > 8) 525 screenwidth = ws.ws_col; 526 else 527 screenwidth = 80; 528 } 529 printf("fd %d %s %d bytes\n", ktr->ktr_fd, 530 ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen); 531 if (maxdata && datalen > maxdata) 532 datalen = maxdata; 533 (void)printf(" \""); 534 col = 8; 535 for (; datalen > 0; datalen--, dp++) { 536 (void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1)); 537 cp = visbuf; 538 /* 539 * Keep track of printables and 540 * space chars (like fold(1)). 541 */ 542 if (col == 0) { 543 (void)putchar('\t'); 544 col = 8; 545 } 546 switch(*cp) { 547 case '\n': 548 col = 0; 549 (void)putchar('\n'); 550 continue; 551 case '\t': 552 width = 8 - (col&07); 553 break; 554 default: 555 width = strlen(cp); 556 } 557 if (col + width > (screenwidth-2)) { 558 (void)printf("\\\n\t"); 559 col = 8; 560 } 561 col += width; 562 do { 563 (void)putchar(*cp++); 564 } while (*cp); 565 } 566 if (col == 0) 567 (void)printf(" "); 568 (void)printf("\"\n"); 569 } 570 571 void 572 ktrpsig(psig) 573 struct ktr_psig *psig; 574 { 575 int signo, first; 576 577 (void)printf("SIG%s ", sys_signame[psig->signo]); 578 if (psig->action == SIG_DFL) 579 (void)printf("SIG_DFL\n"); 580 else { 581 (void)printf("caught handler=0x%lx mask=(", 582 (u_long)psig->action); 583 first = 1; 584 for (signo = 1; signo < NSIG; signo++) { 585 if (sigismember(&psig->mask, signo)) { 586 if (first) 587 first = 0; 588 else 589 (void)printf(","); 590 (void)printf("%d", signo); 591 } 592 } 593 (void)printf(") code=0x%x\n", psig->code); 594 } 595 } 596 597 void 598 ktrcsw(cs) 599 struct ktr_csw *cs; 600 { 601 602 (void)printf("%s %s\n", cs->out ? "stop" : "resume", 603 cs->user ? "user" : "kernel"); 604 } 605 606 void 607 usage() 608 { 609 610 (void)fprintf(stderr, 611 "usage: kdump [-dnlRT] [-e emulation] [-f trfile] [-m maxdata] [-t [cnis]]\n"); 612 exit(1); 613 } 614 615 void 616 setemul(name) 617 char *name; 618 { 619 int i; 620 621 for (i = 0; emulations[i].name != NULL; i++) 622 if (strcmp(emulations[i].name, name) == 0) { 623 current = &emulations[i]; 624 return; 625 } 626 warnx("Emulation `%s' unknown", name); 627 } 628