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