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