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