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