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