kdump.c revision 152331
1/*- 2 * Copyright (c) 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static const char copyright[] = 36"@(#) Copyright (c) 1988, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static char sccsid[] = "@(#)kdump.c 8.1 (Berkeley) 6/6/93"; 43#endif 44#endif /* not lint */ 45#include <sys/cdefs.h> 46__FBSDID("$FreeBSD: head/usr.bin/kdump/kdump.c 152331 2005-11-12 14:21:48Z rwatson $"); 47 48#define _KERNEL 49extern int errno; 50#include <sys/errno.h> 51#undef _KERNEL 52#include <sys/param.h> 53#include <sys/errno.h> 54#define _KERNEL 55#include <sys/time.h> 56#undef _KERNEL 57#include <sys/uio.h> 58#include <sys/ktrace.h> 59#include <sys/ioctl.h> 60#include <sys/ptrace.h> 61#include <err.h> 62#include <locale.h> 63#include <stdio.h> 64#include <stdlib.h> 65#include <string.h> 66#include <unistd.h> 67#include <vis.h> 68#include "ktrace.h" 69 70int fread_tail(void *, int, int); 71void dumpheader(struct ktr_header *); 72void ktrsyscall(struct ktr_syscall *); 73void ktrsysret(struct ktr_sysret *); 74void ktrnamei(char *, int); 75void hexdump(char *, int, int); 76void visdump(char *, int, int); 77void ktrgenio(struct ktr_genio *, int); 78void ktrpsig(struct ktr_psig *); 79void ktrcsw(struct ktr_csw *); 80void ktruser(int, unsigned char *); 81void usage(void); 82const char *ioctlname(u_long); 83 84int timestamp, decimal, fancy = 1, suppressdata, tail, threads, maxdata; 85const char *tracefile = DEF_TRACEFILE; 86struct ktr_header ktr_header; 87 88#define eqs(s1, s2) (strcmp((s1), (s2)) == 0) 89 90int 91main(int argc, char *argv[]) 92{ 93 int ch, ktrlen, size; 94 void *m; 95 int trpoints = ALL_POINTS; 96 int drop_logged; 97 pid_t pid = 0; 98 99 (void) setlocale(LC_CTYPE, ""); 100 101 while ((ch = getopt(argc,argv,"f:dElm:np:HRsTt:")) != -1) 102 switch((char)ch) { 103 case 'f': 104 tracefile = optarg; 105 break; 106 case 'd': 107 decimal = 1; 108 break; 109 case 'l': 110 tail = 1; 111 break; 112 case 'm': 113 maxdata = atoi(optarg); 114 break; 115 case 'n': 116 fancy = 0; 117 break; 118 case 'p': 119 pid = atoi(optarg); 120 break; 121 case 's': 122 suppressdata = 1; 123 break; 124 case 'E': 125 timestamp = 3; /* elapsed timestamp */ 126 break; 127 case 'H': 128 threads = 1; 129 break; 130 case 'R': 131 timestamp = 2; /* relative timestamp */ 132 break; 133 case 'T': 134 timestamp = 1; 135 break; 136 case 't': 137 trpoints = getpoints(optarg); 138 if (trpoints < 0) 139 errx(1, "unknown trace point in %s", optarg); 140 break; 141 default: 142 usage(); 143 } 144 145 if (argc > optind) 146 usage(); 147 148 m = (void *)malloc(size = 1025); 149 if (m == NULL) 150 errx(1, "%s", strerror(ENOMEM)); 151 if (!freopen(tracefile, "r", stdin)) 152 err(1, "%s", tracefile); 153 drop_logged = 0; 154 while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) { 155 if (ktr_header.ktr_type & KTR_DROP) { 156 ktr_header.ktr_type &= ~KTR_DROP; 157 if (!drop_logged && threads) { 158 (void)printf("%6d %6d %-8.*s Events dropped.\n", 159 ktr_header.ktr_pid, ktr_header.ktr_tid > 160 0 ? ktr_header.ktr_tid : 0, MAXCOMLEN, 161 ktr_header.ktr_comm); 162 drop_logged = 1; 163 } else if (!drop_logged) { 164 (void)printf("%6d %-8.*s Events dropped.\n", 165 ktr_header.ktr_pid, MAXCOMLEN, 166 ktr_header.ktr_comm); 167 drop_logged = 1; 168 } 169 } 170 if (trpoints & (1<<ktr_header.ktr_type)) 171 if (pid == 0 || ktr_header.ktr_pid == pid) 172 dumpheader(&ktr_header); 173 if ((ktrlen = ktr_header.ktr_len) < 0) 174 errx(1, "bogus length 0x%x", ktrlen); 175 if (ktrlen > size) { 176 m = (void *)realloc(m, ktrlen+1); 177 if (m == NULL) 178 errx(1, "%s", strerror(ENOMEM)); 179 size = ktrlen; 180 } 181 if (ktrlen && fread_tail(m, ktrlen, 1) == 0) 182 errx(1, "data too short"); 183 if (pid && ktr_header.ktr_pid != pid) 184 continue; 185 if ((trpoints & (1<<ktr_header.ktr_type)) == 0) 186 continue; 187 drop_logged = 0; 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_USER: 208 ktruser(ktrlen, m); 209 break; 210 default: 211 printf("\n"); 212 break; 213 } 214 if (tail) 215 (void)fflush(stdout); 216 } 217 return 0; 218} 219 220int 221fread_tail(void *buf, int size, int num) 222{ 223 int i; 224 225 while ((i = fread(buf, size, num, stdin)) == 0 && tail) { 226 (void)sleep(1); 227 clearerr(stdin); 228 } 229 return (i); 230} 231 232void 233dumpheader(struct ktr_header *kth) 234{ 235 static char unknown[64]; 236 static struct timeval prevtime, temp; 237 const char *type; 238 239 switch (kth->ktr_type) { 240 case KTR_SYSCALL: 241 type = "CALL"; 242 break; 243 case KTR_SYSRET: 244 type = "RET "; 245 break; 246 case KTR_NAMEI: 247 type = "NAMI"; 248 break; 249 case KTR_GENIO: 250 type = "GIO "; 251 break; 252 case KTR_PSIG: 253 type = "PSIG"; 254 break; 255 case KTR_CSW: 256 type = "CSW"; 257 break; 258 case KTR_USER: 259 type = "USER"; 260 break; 261 default: 262 (void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type); 263 type = unknown; 264 } 265 266 /* 267 * The ktr_tid field was previously the ktr_buffer field, which held 268 * the kernel pointer value for the buffer associated with data 269 * following the record header. It now holds a threadid, but only 270 * for trace files after the change. Older trace files still contain 271 * kernel pointers. Detect this and suppress the results by printing 272 * negative tid's as 0. 273 */ 274 if (threads) 275 (void)printf("%6d %6d %-8.*s ", kth->ktr_pid, kth->ktr_tid > 276 0 ? kth->ktr_tid : 0, MAXCOMLEN, kth->ktr_comm); 277 else 278 (void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, 279 kth->ktr_comm); 280 if (timestamp) { 281 if (timestamp == 3) { 282 if (prevtime.tv_sec == 0) 283 prevtime = kth->ktr_time; 284 timevalsub(&kth->ktr_time, &prevtime); 285 } 286 if (timestamp == 2) { 287 temp = kth->ktr_time; 288 timevalsub(&kth->ktr_time, &prevtime); 289 prevtime = temp; 290 } 291 (void)printf("%ld.%06ld ", 292 kth->ktr_time.tv_sec, kth->ktr_time.tv_usec); 293 } 294 (void)printf("%s ", type); 295} 296 297#include <sys/syscall.h> 298#define KTRACE 299#include <sys/kern/syscalls.c> 300#undef KTRACE 301int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]); 302 303static const char *ptrace_ops[] = { 304 "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U", 305 "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE", 306 "PT_KILL", "PT_STEP", "PT_ATTACH", "PT_DETACH", 307}; 308 309void 310ktrsyscall(struct ktr_syscall *ktr) 311{ 312 int narg = ktr->ktr_narg; 313 register_t *ip; 314 315 if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0) 316 (void)printf("[%d]", ktr->ktr_code); 317 else 318 (void)printf("%s", syscallnames[ktr->ktr_code]); 319 ip = &ktr->ktr_args[0]; 320 if (narg) { 321 char c = '('; 322 if (fancy) { 323 if (ktr->ktr_code == SYS_ioctl) { 324 const char *cp; 325 if (decimal) 326 (void)printf("(%ld", (long)*ip); 327 else 328 (void)printf("(%#lx", (long)*ip); 329 ip++; 330 narg--; 331 if ((cp = ioctlname(*ip)) != NULL) 332 (void)printf(",%s", cp); 333 else { 334 if (decimal) 335 (void)printf(",%ld", (long)*ip); 336 else 337 (void)printf(",%#lx ", (long)*ip); 338 } 339 c = ','; 340 ip++; 341 narg--; 342 } else if (ktr->ktr_code == SYS_ptrace) { 343 if ((size_t)*ip < sizeof(ptrace_ops) / 344 sizeof(ptrace_ops[0]) && *ip >= 0) 345 (void)printf("(%s", ptrace_ops[*ip]); 346#ifdef PT_GETREGS 347 else if (*ip == PT_GETREGS) 348 (void)printf("(%s", "PT_GETREGS"); 349#endif 350#ifdef PT_SETREGS 351 else if (*ip == PT_SETREGS) 352 (void)printf("(%s", "PT_SETREGS"); 353#endif 354#ifdef PT_GETFPREGS 355 else if (*ip == PT_GETFPREGS) 356 (void)printf("(%s", "PT_GETFPREGS"); 357#endif 358#ifdef PT_SETFPREGS 359 else if (*ip == PT_SETFPREGS) 360 (void)printf("(%s", "PT_SETFPREGS"); 361#endif 362#ifdef PT_GETDBREGS 363 else if (*ip == PT_GETDBREGS) 364 (void)printf("(%s", "PT_GETDBREGS"); 365#endif 366#ifdef PT_SETDBREGS 367 else if (*ip == PT_SETDBREGS) 368 (void)printf("(%s", "PT_SETDBREGS"); 369#endif 370 else 371 (void)printf("(%ld", (long)*ip); 372 c = ','; 373 ip++; 374 narg--; 375 } 376 } 377 while (narg) { 378 if (decimal) 379 (void)printf("%c%ld", c, (long)*ip); 380 else 381 (void)printf("%c%#lx", c, (long)*ip); 382 c = ','; 383 ip++; 384 narg--; 385 } 386 (void)putchar(')'); 387 } 388 (void)putchar('\n'); 389} 390 391void 392ktrsysret(struct ktr_sysret *ktr) 393{ 394 register_t ret = ktr->ktr_retval; 395 int error = ktr->ktr_error; 396 int code = ktr->ktr_code; 397 398 if (code >= nsyscalls || code < 0) 399 (void)printf("[%d] ", code); 400 else 401 (void)printf("%s ", syscallnames[code]); 402 403 if (error == 0) { 404 if (fancy) { 405 (void)printf("%d", ret); 406 if (ret < 0 || ret > 9) 407 (void)printf("/%#lx", (long)ret); 408 } else { 409 if (decimal) 410 (void)printf("%ld", (long)ret); 411 else 412 (void)printf("%#lx", (long)ret); 413 } 414 } else if (error == ERESTART) 415 (void)printf("RESTART"); 416 else if (error == EJUSTRETURN) 417 (void)printf("JUSTRETURN"); 418 else { 419 (void)printf("-1 errno %d", ktr->ktr_error); 420 if (fancy) 421 (void)printf(" %s", strerror(ktr->ktr_error)); 422 } 423 (void)putchar('\n'); 424} 425 426void 427ktrnamei(char *cp, int len) 428{ 429 (void)printf("\"%.*s\"\n", len, cp); 430} 431 432void 433hexdump(char *p, int len, int screenwidth) 434{ 435 int n, i; 436 int width; 437 438 width = 0; 439 do { 440 width += 2; 441 i = 13; /* base offset */ 442 i += (width / 2) + 1; /* spaces every second byte */ 443 i += (width * 2); /* width of bytes */ 444 i += 3; /* " |" */ 445 i += width; /* each byte */ 446 i += 1; /* "|" */ 447 } while (i < screenwidth); 448 width -= 2; 449 450 for (n = 0; n < len; n += width) { 451 for (i = n; i < n + width; i++) { 452 if ((i % width) == 0) { /* beginning of line */ 453 printf(" 0x%04x", i); 454 } 455 if ((i % 2) == 0) { 456 printf(" "); 457 } 458 if (i < len) 459 printf("%02x", p[i] & 0xff); 460 else 461 printf(" "); 462 } 463 printf(" |"); 464 for (i = n; i < n + width; i++) { 465 if (i >= len) 466 break; 467 if (p[i] >= ' ' && p[i] <= '~') 468 printf("%c", p[i]); 469 else 470 printf("."); 471 } 472 printf("|\n"); 473 } 474 if ((i % width) != 0) 475 printf("\n"); 476} 477 478void 479visdump(char *dp, int datalen, int screenwidth) 480{ 481 int col = 0; 482 char *cp; 483 int width; 484 char visbuf[5]; 485 486 (void)printf(" \""); 487 col = 8; 488 for (;datalen > 0; datalen--, dp++) { 489 (void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1)); 490 cp = visbuf; 491 /* 492 * Keep track of printables and 493 * space chars (like fold(1)). 494 */ 495 if (col == 0) { 496 (void)putchar('\t'); 497 col = 8; 498 } 499 switch(*cp) { 500 case '\n': 501 col = 0; 502 (void)putchar('\n'); 503 continue; 504 case '\t': 505 width = 8 - (col&07); 506 break; 507 default: 508 width = strlen(cp); 509 } 510 if (col + width > (screenwidth-2)) { 511 (void)printf("\\\n\t"); 512 col = 8; 513 } 514 col += width; 515 do { 516 (void)putchar(*cp++); 517 } while (*cp); 518 } 519 if (col == 0) 520 (void)printf(" "); 521 (void)printf("\"\n"); 522} 523 524void 525ktrgenio(struct ktr_genio *ktr, int len) 526{ 527 int datalen = len - sizeof (struct ktr_genio); 528 char *dp = (char *)ktr + sizeof (struct ktr_genio); 529 static int screenwidth = 0; 530 int i, binary; 531 532 if (screenwidth == 0) { 533 struct winsize ws; 534 535 if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 && 536 ws.ws_col > 8) 537 screenwidth = ws.ws_col; 538 else 539 screenwidth = 80; 540 } 541 printf("fd %d %s %d byte%s\n", ktr->ktr_fd, 542 ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen, 543 datalen == 1 ? "" : "s"); 544 if (suppressdata) 545 return; 546 if (maxdata && datalen > maxdata) 547 datalen = maxdata; 548 549 for (i = 0, binary = 0; i < datalen && binary == 0; i++) { 550 if (dp[i] >= 32 && dp[i] < 127) 551 continue; 552 if (dp[i] == 10 || dp[i] == 13 || dp[i] == 0 || dp[i] == 9) 553 continue; 554 binary = 1; 555 } 556 if (binary) 557 hexdump(dp, datalen, screenwidth); 558 else 559 visdump(dp, datalen, screenwidth); 560} 561 562const char *signames[] = { 563 "NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", /* 1 - 6 */ 564 "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", /* 7 - 12 */ 565 "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", /* 13 - 18 */ 566 "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", /* 19 - 24 */ 567 "XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1", /* 25 - 30 */ 568 "USR2", NULL, /* 31 - 32 */ 569}; 570 571void 572ktrpsig(struct ktr_psig *psig) 573{ 574 (void)printf("SIG%s ", signames[psig->signo]); 575 if (psig->action == SIG_DFL) 576 (void)printf("SIG_DFL\n"); 577 else { 578 (void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n", 579 (u_long)psig->action, psig->mask.__bits[0], psig->code); 580 } 581} 582 583void 584ktrcsw(struct ktr_csw *cs) 585{ 586 (void)printf("%s %s\n", cs->out ? "stop" : "resume", 587 cs->user ? "user" : "kernel"); 588} 589 590void 591ktruser(int len, unsigned char *p) 592{ 593 (void)printf("%d ", len); 594 while (len--) 595 if (decimal) 596 (void)printf(" %d", *p++); 597 else 598 (void)printf(" %02x", *p++); 599 (void)printf("\n"); 600 601} 602 603void 604usage(void) 605{ 606 (void)fprintf(stderr, 607 "usage: kdump [-dEnlHRsT] [-f trfile] [-m maxdata] [-p pid] [-t [cnisuw]]\n"); 608 exit(1); 609} 610