1 /* $NetBSD: kdump.c,v 1.40 2002/08/04 14:26:21 jdolecek 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.40 2002/08/04 14:26:21 jdolecek 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 #include "setemul.h" 70 71 #include <sys/syscall.h> 72 73 int timestamp, decimal, plain, tail, maxdata; 74 pid_t do_pid = -1; 75 const char *tracefile = DEF_TRACEFILE; 76 struct ktr_header ktr_header; 77 int emul_changed = 0; 78 79 #define eqs(s1, s2) (strcmp((s1), (s2)) == 0) 80 81 static const char *ptrace_ops[] = { 82 "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U", 83 "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE", 84 "PT_KILL", "PT_ATTACH", "PT_DETACH", 85 }; 86 87 static const char *linux_ptrace_ops[] = { 88 "PTRACE_TRACEME", 89 "PTRACE_PEEKTEXT", "PTRACE_PEEKDATA", "PTRACE_PEEKUSER", 90 "PTRACE_POKETEXT", "PTRACE_POKEDATA", "PTRACE_POKEUSER", 91 "PTRACE_CONT", "PTRACE_KILL", "PTRACE_SINGLESTEP", 92 NULL, NULL, 93 "PTRACE_GETREGS", "PTRACE_SETREGS", "PTRACE_GETFPREGS", 94 "PTRACE_SETFPREGS", "PTRACE_ATTACH", "PTRACE_DETACH", 95 "PTRACE_SYSCALL", 96 }; 97 98 int main __P((int, char **)); 99 int fread_tail __P((char *, int, int)); 100 void dumpheader __P((struct ktr_header *)); 101 void ioctldecode __P((u_long)); 102 void ktrsyscall __P((struct ktr_syscall *)); 103 void ktrsysret __P((struct ktr_sysret *)); 104 void ktrnamei __P((char *, int)); 105 void ktremul __P((char *, int, int)); 106 void ktrgenio __P((struct ktr_genio *, int)); 107 void ktrpsig __P((struct ktr_psig *)); 108 void ktrcsw __P((struct ktr_csw *)); 109 void ktruser __P((struct ktr_user *, int)); 110 void usage __P((void)); 111 void eprint __P((int)); 112 char *ioctlname __P((long)); 113 static const char *signame __P((long, int)); 114 115 int 116 main(argc, argv) 117 int argc; 118 char *argv[]; 119 { 120 int ch, ktrlen, size; 121 void *m; 122 int trpoints = ALL_POINTS; 123 const char *emul_name = "netbsd"; 124 125 while ((ch = getopt(argc, argv, "e:f:dlm:np:RTt:")) != -1) 126 switch (ch) { 127 case 'e': 128 emul_name = strdup(optarg); /* it's safer to copy it */ 129 break; 130 case 'f': 131 tracefile = optarg; 132 break; 133 case 'd': 134 decimal = 1; 135 break; 136 case 'l': 137 tail = 1; 138 break; 139 case 'p': 140 do_pid = atoi(optarg); 141 break; 142 case 'm': 143 maxdata = atoi(optarg); 144 break; 145 case 'n': 146 plain++; 147 break; 148 case 'R': 149 timestamp = 2; /* relative timestamp */ 150 break; 151 case 'T': 152 timestamp = 1; 153 break; 154 case 't': 155 trpoints = getpoints(optarg); 156 if (trpoints < 0) 157 errx(1, "unknown trace point in %s", optarg); 158 break; 159 default: 160 usage(); 161 } 162 argv += optind; 163 argc -= optind; 164 165 if (argc > 1) 166 usage(); 167 168 setemul(emul_name, 0, 0); 169 170 m = malloc(size = 1024); 171 if (m == NULL) 172 errx(1, "malloc: %s", strerror(ENOMEM)); 173 if (!freopen(tracefile, "r", stdin)) 174 err(1, "%s", tracefile); 175 while (fread_tail((char *)&ktr_header, sizeof(struct ktr_header), 1)) { 176 if (trpoints & (1<<ktr_header.ktr_type)) 177 if (do_pid == -1 || ktr_header.ktr_pid == do_pid) 178 dumpheader(&ktr_header); 179 if ((ktrlen = ktr_header.ktr_len) < 0) 180 errx(1, "bogus length 0x%x", ktrlen); 181 if (ktrlen > size) { 182 while(ktrlen > size) size *= 2; 183 m = (void *)realloc(m, size); 184 if (m == NULL) 185 errx(1, "realloc: %s", strerror(ENOMEM)); 186 } 187 if (ktrlen && fread_tail(m, ktrlen, 1) == 0) 188 errx(1, "data too short"); 189 if ((trpoints & (1<<ktr_header.ktr_type)) == 0) 190 continue; 191 192 /* update context to match currently processed record */ 193 if (do_pid != -1 && ktr_header.ktr_pid != do_pid) 194 continue; 195 ectx_sanify(ktr_header.ktr_pid); 196 197 switch (ktr_header.ktr_type) { 198 case KTR_SYSCALL: 199 ktrsyscall((struct ktr_syscall *)m); 200 break; 201 case KTR_SYSRET: 202 ktrsysret((struct ktr_sysret *)m); 203 break; 204 case KTR_NAMEI: 205 ktrnamei(m, ktrlen); 206 break; 207 case KTR_GENIO: 208 ktrgenio((struct ktr_genio *)m, ktrlen); 209 break; 210 case KTR_PSIG: 211 ktrpsig((struct ktr_psig *)m); 212 break; 213 case KTR_CSW: 214 ktrcsw((struct ktr_csw *)m); 215 break; 216 case KTR_EMUL: 217 ktremul(m, ktrlen, size); 218 break; 219 case KTR_USER: 220 ktruser((struct ktr_user *)m, ktrlen); 221 break; 222 } 223 if (tail) 224 (void)fflush(stdout); 225 } 226 return (0); 227 } 228 229 int 230 fread_tail(buf, size, num) 231 char *buf; 232 int num, size; 233 { 234 int i; 235 236 while ((i = fread(buf, size, num, stdin)) == 0 && tail) { 237 (void)sleep(1); 238 clearerr(stdin); 239 } 240 return (i); 241 } 242 243 void 244 dumpheader(kth) 245 struct ktr_header *kth; 246 { 247 char unknown[64], *type; 248 static struct timeval prevtime; 249 struct timeval temp; 250 251 switch (kth->ktr_type) { 252 case KTR_SYSCALL: 253 type = "CALL"; 254 break; 255 case KTR_SYSRET: 256 type = "RET "; 257 break; 258 case KTR_NAMEI: 259 type = "NAMI"; 260 break; 261 case KTR_GENIO: 262 type = "GIO "; 263 break; 264 case KTR_PSIG: 265 type = "PSIG"; 266 break; 267 case KTR_CSW: 268 type = "CSW"; 269 break; 270 case KTR_EMUL: 271 type = "EMUL"; 272 break; 273 case KTR_USER: 274 type = "USER"; 275 break; 276 default: 277 (void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type); 278 type = unknown; 279 } 280 281 (void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm); 282 if (timestamp) { 283 if (timestamp == 2) { 284 timersub(&kth->ktr_time, &prevtime, &temp); 285 prevtime = kth->ktr_time; 286 } else 287 temp = kth->ktr_time; 288 (void)printf("%ld.%06ld ", 289 (long int)temp.tv_sec, (long int)temp.tv_usec); 290 } 291 (void)printf("%s ", type); 292 } 293 294 void 295 ioctldecode(cmd) 296 u_long cmd; 297 { 298 char dirbuf[4], *dir = dirbuf; 299 300 if (cmd & IOC_IN) 301 *dir++ = 'W'; 302 if (cmd & IOC_OUT) 303 *dir++ = 'R'; 304 *dir = '\0'; 305 306 printf(decimal ? ",_IO%s('%c',%ld" : ",_IO%s('%c',%#lx", 307 dirbuf, (int) ((cmd >> 8) & 0xff), cmd & 0xff); 308 if ((cmd & IOC_VOID) == 0) 309 printf(decimal ? ",%ld)" : ",%#lx)", (cmd >> 16) & 0xff); 310 else 311 printf(")"); 312 } 313 314 void 315 ktrsyscall(ktr) 316 struct ktr_syscall *ktr; 317 { 318 int argsize = ktr->ktr_argsize; 319 register_t *ap; 320 321 if (ktr->ktr_code >= current->nsysnames || ktr->ktr_code < 0) 322 (void)printf("[%d]", ktr->ktr_code); 323 else 324 (void)printf("%s", current->sysnames[ktr->ktr_code]); 325 ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall)); 326 if (argsize) { 327 char c = '('; 328 if (!plain) { 329 char *cp; 330 331 switch (ktr->ktr_code) { 332 case SYS_ioctl: 333 if (decimal) 334 (void)printf("(%ld", (long)*ap); 335 else 336 (void)printf("(%#lx", (long)*ap); 337 ap++; 338 argsize -= sizeof(register_t); 339 if ((cp = ioctlname(*ap)) != NULL) 340 (void)printf(",%s", cp); 341 else 342 ioctldecode(*ap); 343 c = ','; 344 ap++; 345 argsize -= sizeof(register_t); 346 break; 347 348 case SYS_ptrace: 349 if (strcmp(current->name, "linux") == 0) { 350 if (*ap >= 0 && *ap <= 351 sizeof(linux_ptrace_ops) / 352 sizeof(linux_ptrace_ops[0])) 353 (void)printf("(%s", 354 linux_ptrace_ops[*ap]); 355 else 356 (void)printf("(%ld", (long)*ap); 357 } else { 358 if (*ap >= 0 && *ap <= 359 sizeof(ptrace_ops) / sizeof(ptrace_ops[0])) 360 (void)printf("(%s", ptrace_ops[*ap]); 361 else 362 (void)printf("(%ld", (long)*ap); 363 } 364 c = ','; 365 ap++; 366 argsize -= sizeof(register_t); 367 break; 368 369 case SYS_kill: 370 if (decimal) 371 (void)printf("(%ld, SIG%s", 372 (long)ap[0], signame(ap[1], 1)); 373 else 374 (void)printf("(%#lx, SIG%s", 375 (long)ap[0], signame(ap[1], 1)); 376 ap += 2; 377 argsize -= 2 * sizeof(register_t); 378 break; 379 380 default: 381 /* No special handling */ 382 break; 383 } 384 } 385 while (argsize) { 386 if (decimal) 387 (void)printf("%c%ld", c, (long)*ap); 388 else 389 (void)printf("%c%#lx", c, (long)*ap); 390 c = ','; 391 ap++; 392 argsize -= sizeof(register_t); 393 } 394 (void)putchar(')'); 395 } 396 (void)putchar('\n'); 397 } 398 399 void 400 ktrsysret(ktr) 401 struct ktr_sysret *ktr; 402 { 403 const struct emulation *revelant; 404 register_t ret = ktr->ktr_retval; 405 int error = ktr->ktr_error; 406 int code = ktr->ktr_code; 407 408 if (emul_changed) 409 revelant = previous; 410 else 411 revelant = current; 412 emul_changed = 0; 413 414 if (code >= revelant->nsysnames || code < 0 || plain > 1) 415 (void)printf("[%d] ", code); 416 else 417 (void)printf("%s ", revelant->sysnames[code]); 418 419 switch (error) { 420 case 0: 421 if (!plain) { 422 (void)printf("%ld", (long)ret); 423 if (ret < 0 || ret > 9) 424 (void)printf("/%#lx", (long)ret); 425 } else { 426 if (decimal) 427 (void)printf("%ld", (long)ret); 428 else 429 (void)printf("%#lx", (long)ret); 430 } 431 break; 432 433 default: 434 eprint(error); 435 break; 436 } 437 (void)putchar('\n'); 438 439 } 440 441 /* 442 * We print the original emulation's error numerically, but we 443 * translate it to netbsd to print it symbolically. 444 */ 445 void 446 eprint(e) 447 int e; 448 { 449 int i = e; 450 451 if (current->errnomap) { 452 453 /* No remapping for ERESTART and EJUSTRETURN */ 454 /* Kludge for linux that has negative error numbers */ 455 if (current->errnomap[2] > 0 && e < 0) 456 goto normal; 457 458 for (i = 0; i < current->nerrnomap; i++) 459 if (e == current->errnomap[i]) 460 break; 461 462 if (i == current->nerrnomap) { 463 printf("-1 unknown errno %d", e); 464 return; 465 } 466 } 467 468 normal: 469 switch (i) { 470 case ERESTART: 471 (void)printf("RESTART"); 472 break; 473 474 case EJUSTRETURN: 475 (void)printf("JUSTRETURN"); 476 break; 477 478 default: 479 (void)printf("-1 errno %d", e); 480 if (!plain) 481 (void)printf(" %s", strerror(i)); 482 } 483 } 484 485 void 486 ktrnamei(cp, len) 487 char *cp; 488 int len; 489 { 490 491 (void)printf("\"%.*s\"\n", len, cp); 492 } 493 494 void 495 ktremul(name, len, bufsize) 496 char *name; 497 int len, bufsize; 498 { 499 if (len >= bufsize) 500 len = bufsize - 1; 501 502 name[len] = '\0'; 503 setemul(name, ktr_header.ktr_pid, 1); 504 emul_changed = 1; 505 506 (void)printf("\"%s\"\n", name); 507 } 508 509 void 510 ktrgenio(ktr, len) 511 struct ktr_genio *ktr; 512 int len; 513 { 514 int datalen = len - sizeof (struct ktr_genio); 515 char *dp = (char *)ktr + sizeof (struct ktr_genio); 516 char *cp; 517 int col = 0; 518 int width; 519 char visbuf[5]; 520 static int screenwidth = 0; 521 522 if (screenwidth == 0) { 523 struct winsize ws; 524 525 if (!plain && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 && 526 ws.ws_col > 8) 527 screenwidth = ws.ws_col; 528 else 529 screenwidth = 80; 530 } 531 printf("fd %d %s %d bytes\n", ktr->ktr_fd, 532 ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen); 533 if (maxdata && datalen > maxdata) 534 datalen = maxdata; 535 (void)printf(" \""); 536 col = 8; 537 for (; datalen > 0; datalen--, dp++) { 538 (void) vis(visbuf, *dp, VIS_CSTYLE, datalen>1?*(dp+1):0); 539 cp = visbuf; 540 /* 541 * Keep track of printables and 542 * space chars (like fold(1)). 543 */ 544 if (col == 0) { 545 (void)putchar('\t'); 546 col = 8; 547 } 548 switch(*cp) { 549 case '\n': 550 col = 0; 551 (void)putchar('\n'); 552 continue; 553 case '\t': 554 width = 8 - (col&07); 555 break; 556 default: 557 width = strlen(cp); 558 } 559 if (col + width > (screenwidth-2)) { 560 (void)printf("\\\n\t"); 561 col = 8; 562 } 563 col += width; 564 do { 565 (void)putchar(*cp++); 566 } while (*cp); 567 } 568 if (col == 0) 569 (void)printf(" "); 570 (void)printf("\"\n"); 571 } 572 573 void 574 ktrpsig(psig) 575 struct ktr_psig *psig; 576 { 577 int signo, first; 578 579 (void)printf("SIG%s ", signame(psig->signo, 0)); 580 if (psig->action == SIG_DFL) 581 (void)printf("SIG_DFL\n"); 582 else { 583 (void)printf("caught handler=0x%lx mask=(", 584 (u_long)psig->action); 585 first = 1; 586 for (signo = 1; signo < NSIG; signo++) { 587 if (sigismember(&psig->mask, signo)) { 588 if (first) 589 first = 0; 590 else 591 (void)printf(","); 592 (void)printf("%d", signo); 593 } 594 } 595 (void)printf(") code=0x%x\n", psig->code); 596 } 597 } 598 599 void 600 ktrcsw(cs) 601 struct ktr_csw *cs; 602 { 603 604 (void)printf("%s %s\n", cs->out ? "stop" : "resume", 605 cs->user ? "user" : "kernel"); 606 } 607 608 void 609 ktruser(usr, len) 610 struct ktr_user *usr; 611 int len; 612 { 613 int i; 614 unsigned char *dta; 615 616 printf("\"%.*s: %d, ", KTR_USER_MAXIDLEN, usr->ktr_id, len); 617 dta = (unsigned char *)usr; 618 for(i=sizeof(struct ktr_user); i < len; i++) 619 printf("%02x", (unsigned int) dta[i]); 620 printf("\"\n"); 621 } 622 623 static const char * 624 signame(long sig, int xlat) 625 { 626 static char buf[64]; 627 if (sig <= 0 || sig >= NSIG) { 628 (void)snprintf(buf, sizeof(buf), "*unknown %ld*", sig); 629 return buf; 630 } else 631 return sys_signame[(xlat && current->signalmap != NULL) ? 632 current->signalmap[sig] : sig]; 633 } 634 635 void 636 usage() 637 { 638 639 (void)fprintf(stderr, 640 "usage: kdump [-dnlRT] [-e emulation] [-f trfile] [-m maxdata] [-t [cnis]]\n"); 641 exit(1); 642 } 643