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