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