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 const 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.1 (Berkeley) 6/6/93"; 43 #endif 44 #endif /* not lint */ 45 #include <sys/cdefs.h> 46 __FBSDID("$FreeBSD$"); 47 48 #define _KERNEL 49 extern int errno; 50 #include <sys/errno.h> 51 #undef _KERNEL 52 #include <sys/param.h> 53 #include <sys/errno.h> 54 #define _KERNEL 55 #include <sys/time.h> 56 #undef _KERNEL 57 #include <sys/uio.h> 58 #include <sys/ktrace.h> 59 #include <sys/ioctl.h> 60 #include <sys/ptrace.h> 61 #include <err.h> 62 #include <locale.h> 63 #include <stdio.h> 64 #include <stdlib.h> 65 #include <string.h> 66 #include <unistd.h> 67 #include <vis.h> 68 #include "ktrace.h" 69 70 int fread_tail(void *, int, int); 71 void dumpheader(struct ktr_header *); 72 void ktrsyscall(struct ktr_syscall *); 73 void ktrsysret(struct ktr_sysret *); 74 void ktrnamei(char *, int); 75 void hexdump(char *, int, int); 76 void visdump(char *, int, int); 77 void ktrgenio(struct ktr_genio *, int); 78 void ktrpsig(struct ktr_psig *); 79 void ktrcsw(struct ktr_csw *); 80 void ktruser(int, unsigned char *); 81 void usage(void); 82 83 int timestamp, decimal, fancy = 1, tail, maxdata; 84 const char *tracefile = DEF_TRACEFILE; 85 struct ktr_header ktr_header; 86 87 #define eqs(s1, s2) (strcmp((s1), (s2)) == 0) 88 89 int 90 main(int argc, char *argv[]) 91 { 92 int ch, ktrlen, size; 93 void *m; 94 int trpoints = ALL_POINTS; 95 int drop_logged; 96 pid_t pid = 0; 97 98 (void) setlocale(LC_CTYPE, ""); 99 100 while ((ch = getopt(argc,argv,"f:dElm:np:RTt:")) != -1) 101 switch((char)ch) { 102 case 'f': 103 tracefile = optarg; 104 break; 105 case 'd': 106 decimal = 1; 107 break; 108 case 'l': 109 tail = 1; 110 break; 111 case 'm': 112 maxdata = atoi(optarg); 113 break; 114 case 'n': 115 fancy = 0; 116 break; 117 case 'p': 118 pid = atoi(optarg); 119 break; 120 case 'E': 121 timestamp = 3; /* elapsed timestamp */ 122 break; 123 case 'R': 124 timestamp = 2; /* relative timestamp */ 125 break; 126 case 'T': 127 timestamp = 1; 128 break; 129 case 't': 130 trpoints = getpoints(optarg); 131 if (trpoints < 0) 132 errx(1, "unknown trace point in %s", optarg); 133 break; 134 default: 135 usage(); 136 } 137 138 if (argc > optind) 139 usage(); 140 141 m = (void *)malloc(size = 1025); 142 if (m == NULL) 143 errx(1, "%s", strerror(ENOMEM)); 144 if (!freopen(tracefile, "r", stdin)) 145 err(1, "%s", tracefile); 146 drop_logged = 0; 147 while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) { 148 if (ktr_header.ktr_type & KTR_DROP) { 149 ktr_header.ktr_type &= ~KTR_DROP; 150 if (!drop_logged) { 151 (void)printf("%6d %-8.*s Events dropped.\n", 152 ktr_header.ktr_pid, MAXCOMLEN, 153 ktr_header.ktr_comm); 154 drop_logged = 1; 155 } 156 } 157 if (trpoints & (1<<ktr_header.ktr_type)) 158 if (pid == 0 || ktr_header.ktr_pid == pid) 159 dumpheader(&ktr_header); 160 if ((ktrlen = ktr_header.ktr_len) < 0) 161 errx(1, "bogus length 0x%x", ktrlen); 162 if (ktrlen > size) { 163 m = (void *)realloc(m, ktrlen+1); 164 if (m == NULL) 165 errx(1, "%s", strerror(ENOMEM)); 166 size = ktrlen; 167 } 168 if (ktrlen && fread_tail(m, ktrlen, 1) == 0) 169 errx(1, "data too short"); 170 if (pid && ktr_header.ktr_pid != pid) 171 continue; 172 if ((trpoints & (1<<ktr_header.ktr_type)) == 0) 173 continue; 174 drop_logged = 0; 175 switch (ktr_header.ktr_type) { 176 case KTR_SYSCALL: 177 ktrsyscall((struct ktr_syscall *)m); 178 break; 179 case KTR_SYSRET: 180 ktrsysret((struct ktr_sysret *)m); 181 break; 182 case KTR_NAMEI: 183 ktrnamei(m, ktrlen); 184 break; 185 case KTR_GENIO: 186 ktrgenio((struct ktr_genio *)m, ktrlen); 187 break; 188 case KTR_PSIG: 189 ktrpsig((struct ktr_psig *)m); 190 break; 191 case KTR_CSW: 192 ktrcsw((struct ktr_csw *)m); 193 break; 194 case KTR_USER: 195 ktruser(ktrlen, m); 196 break; 197 default: 198 printf("\n"); 199 break; 200 } 201 if (tail) 202 (void)fflush(stdout); 203 } 204 return 0; 205 } 206 207 int 208 fread_tail(void *buf, int size, int num) 209 { 210 int i; 211 212 while ((i = fread(buf, size, num, stdin)) == 0 && tail) { 213 (void)sleep(1); 214 clearerr(stdin); 215 } 216 return (i); 217 } 218 219 void 220 dumpheader(struct ktr_header *kth) 221 { 222 static char unknown[64]; 223 static struct timeval prevtime, temp; 224 const char *type; 225 226 switch (kth->ktr_type) { 227 case KTR_SYSCALL: 228 type = "CALL"; 229 break; 230 case KTR_SYSRET: 231 type = "RET "; 232 break; 233 case KTR_NAMEI: 234 type = "NAMI"; 235 break; 236 case KTR_GENIO: 237 type = "GIO "; 238 break; 239 case KTR_PSIG: 240 type = "PSIG"; 241 break; 242 case KTR_CSW: 243 type = "CSW"; 244 break; 245 case KTR_USER: 246 type = "USER"; 247 break; 248 default: 249 (void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type); 250 type = unknown; 251 } 252 253 (void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm); 254 if (timestamp) { 255 if (timestamp == 3) { 256 if (prevtime.tv_sec == 0) 257 prevtime = kth->ktr_time; 258 timevalsub(&kth->ktr_time, &prevtime); 259 } 260 if (timestamp == 2) { 261 temp = kth->ktr_time; 262 timevalsub(&kth->ktr_time, &prevtime); 263 prevtime = temp; 264 } 265 (void)printf("%ld.%06ld ", 266 kth->ktr_time.tv_sec, kth->ktr_time.tv_usec); 267 } 268 (void)printf("%s ", type); 269 } 270 271 #include <sys/syscall.h> 272 #define KTRACE 273 #include <sys/kern/syscalls.c> 274 #undef KTRACE 275 int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]); 276 277 static const char *ptrace_ops[] = { 278 "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U", 279 "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE", 280 "PT_KILL", "PT_STEP", "PT_ATTACH", "PT_DETACH", 281 }; 282 283 void 284 ktrsyscall(struct ktr_syscall *ktr) 285 { 286 int narg = ktr->ktr_narg; 287 register_t *ip; 288 const char *ioctlname(u_long); 289 290 if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0) 291 (void)printf("[%d]", ktr->ktr_code); 292 else 293 (void)printf("%s", syscallnames[ktr->ktr_code]); 294 ip = &ktr->ktr_args[0]; 295 if (narg) { 296 char c = '('; 297 if (fancy) { 298 if (ktr->ktr_code == SYS_ioctl) { 299 const char *cp; 300 if (decimal) 301 (void)printf("(%ld", (long)*ip); 302 else 303 (void)printf("(%#lx", (long)*ip); 304 ip++; 305 narg--; 306 if ((cp = ioctlname(*ip)) != NULL) 307 (void)printf(",%s", cp); 308 else { 309 if (decimal) 310 (void)printf(",%ld", (long)*ip); 311 else 312 (void)printf(",%#lx ", (long)*ip); 313 } 314 c = ','; 315 ip++; 316 narg--; 317 } else if (ktr->ktr_code == SYS_ptrace) { 318 if ((size_t)*ip < sizeof(ptrace_ops) / 319 sizeof(ptrace_ops[0]) && *ip >= 0) 320 (void)printf("(%s", ptrace_ops[*ip]); 321 #ifdef PT_GETREGS 322 else if (*ip == PT_GETREGS) 323 (void)printf("(%s", "PT_GETREGS"); 324 #endif 325 #ifdef PT_SETREGS 326 else if (*ip == PT_SETREGS) 327 (void)printf("(%s", "PT_SETREGS"); 328 #endif 329 #ifdef PT_GETFPREGS 330 else if (*ip == PT_GETFPREGS) 331 (void)printf("(%s", "PT_GETFPREGS"); 332 #endif 333 #ifdef PT_SETFPREGS 334 else if (*ip == PT_SETFPREGS) 335 (void)printf("(%s", "PT_SETFPREGS"); 336 #endif 337 #ifdef PT_GETDBREGS 338 else if (*ip == PT_GETDBREGS) 339 (void)printf("(%s", "PT_GETDBREGS"); 340 #endif 341 #ifdef PT_SETDBREGS 342 else if (*ip == PT_SETDBREGS) 343 (void)printf("(%s", "PT_SETDBREGS"); 344 #endif 345 else 346 (void)printf("(%ld", (long)*ip); 347 c = ','; 348 ip++; 349 narg--; 350 } 351 } 352 while (narg) { 353 if (decimal) 354 (void)printf("%c%ld", c, (long)*ip); 355 else 356 (void)printf("%c%#lx", c, (long)*ip); 357 c = ','; 358 ip++; 359 narg--; 360 } 361 (void)putchar(')'); 362 } 363 (void)putchar('\n'); 364 } 365 366 void 367 ktrsysret(struct ktr_sysret *ktr) 368 { 369 register_t ret = ktr->ktr_retval; 370 int error = ktr->ktr_error; 371 int code = ktr->ktr_code; 372 373 if (code >= nsyscalls || code < 0) 374 (void)printf("[%d] ", code); 375 else 376 (void)printf("%s ", syscallnames[code]); 377 378 if (error == 0) { 379 if (fancy) { 380 (void)printf("%d", ret); 381 if (ret < 0 || ret > 9) 382 (void)printf("/%#lx", (long)ret); 383 } else { 384 if (decimal) 385 (void)printf("%ld", (long)ret); 386 else 387 (void)printf("%#lx", (long)ret); 388 } 389 } else if (error == ERESTART) 390 (void)printf("RESTART"); 391 else if (error == EJUSTRETURN) 392 (void)printf("JUSTRETURN"); 393 else { 394 (void)printf("-1 errno %d", ktr->ktr_error); 395 if (fancy) 396 (void)printf(" %s", strerror(ktr->ktr_error)); 397 } 398 (void)putchar('\n'); 399 } 400 401 void 402 ktrnamei(char *cp, int len) 403 { 404 (void)printf("\"%.*s\"\n", len, cp); 405 } 406 407 void 408 hexdump(char *p, int len, int screenwidth) 409 { 410 int n, i; 411 int width; 412 413 width = 0; 414 do { 415 width += 2; 416 i = 13; /* base offset */ 417 i += (width / 2) + 1; /* spaces every second byte */ 418 i += (width * 2); /* width of bytes */ 419 i += 3; /* " |" */ 420 i += width; /* each byte */ 421 i += 1; /* "|" */ 422 } while (i < screenwidth); 423 width -= 2; 424 425 for (n = 0; n < len; n += width) { 426 for (i = n; i < n + width; i++) { 427 if ((i % width) == 0) { /* beginning of line */ 428 printf(" 0x%04x", i); 429 } 430 if ((i % 2) == 0) { 431 printf(" "); 432 } 433 if (i < len) 434 printf("%02x", p[i] & 0xff); 435 else 436 printf(" "); 437 } 438 printf(" |"); 439 for (i = n; i < n + width; i++) { 440 if (i >= len) 441 break; 442 if (p[i] >= ' ' && p[i] <= '~') 443 printf("%c", p[i]); 444 else 445 printf("."); 446 } 447 printf("|\n"); 448 } 449 if ((i % width) != 0) 450 printf("\n"); 451 } 452 453 void 454 visdump(char *dp, int datalen, int screenwidth) 455 { 456 int col = 0; 457 char *cp; 458 int width; 459 char visbuf[5]; 460 461 (void)printf(" \""); 462 col = 8; 463 for (;datalen > 0; datalen--, dp++) { 464 (void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1)); 465 cp = visbuf; 466 /* 467 * Keep track of printables and 468 * space chars (like fold(1)). 469 */ 470 if (col == 0) { 471 (void)putchar('\t'); 472 col = 8; 473 } 474 switch(*cp) { 475 case '\n': 476 col = 0; 477 (void)putchar('\n'); 478 continue; 479 case '\t': 480 width = 8 - (col&07); 481 break; 482 default: 483 width = strlen(cp); 484 } 485 if (col + width > (screenwidth-2)) { 486 (void)printf("\\\n\t"); 487 col = 8; 488 } 489 col += width; 490 do { 491 (void)putchar(*cp++); 492 } while (*cp); 493 } 494 if (col == 0) 495 (void)printf(" "); 496 (void)printf("\"\n"); 497 } 498 499 void 500 ktrgenio(struct ktr_genio *ktr, int len) 501 { 502 int datalen = len - sizeof (struct ktr_genio); 503 char *dp = (char *)ktr + sizeof (struct ktr_genio); 504 static int screenwidth = 0; 505 int i, binary; 506 507 if (screenwidth == 0) { 508 struct winsize ws; 509 510 if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 && 511 ws.ws_col > 8) 512 screenwidth = ws.ws_col; 513 else 514 screenwidth = 80; 515 } 516 printf("fd %d %s %d byte%s\n", ktr->ktr_fd, 517 ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen, 518 datalen == 1 ? "" : "s"); 519 if (maxdata && datalen > maxdata) 520 datalen = maxdata; 521 522 for (i = 0, binary = 0; i < datalen && binary == 0; i++) { 523 if (dp[i] >= 32 && dp[i] < 127) 524 continue; 525 if (dp[i] == 10 || dp[i] == 13 || dp[i] == 0 || dp[i] == 9) 526 continue; 527 binary = 1; 528 } 529 if (binary) 530 hexdump(dp, datalen, screenwidth); 531 else 532 visdump(dp, datalen, screenwidth); 533 } 534 535 const char *signames[] = { 536 "NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", /* 1 - 6 */ 537 "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", /* 7 - 12 */ 538 "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", /* 13 - 18 */ 539 "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", /* 19 - 24 */ 540 "XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1", /* 25 - 30 */ 541 "USR2", NULL, /* 31 - 32 */ 542 }; 543 544 void 545 ktrpsig(struct ktr_psig *psig) 546 { 547 (void)printf("SIG%s ", signames[psig->signo]); 548 if (psig->action == SIG_DFL) 549 (void)printf("SIG_DFL\n"); 550 else { 551 (void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n", 552 (u_long)psig->action, psig->mask.__bits[0], psig->code); 553 } 554 } 555 556 void 557 ktrcsw(struct ktr_csw *cs) 558 { 559 (void)printf("%s %s\n", cs->out ? "stop" : "resume", 560 cs->user ? "user" : "kernel"); 561 } 562 563 void 564 ktruser(int len, unsigned char *p) 565 { 566 (void)printf("%d ", len); 567 while (len--) 568 if (decimal) 569 (void)printf(" %d", *p++); 570 else 571 (void)printf(" %02x", *p++); 572 (void)printf("\n"); 573 574 } 575 576 void 577 usage(void) 578 { 579 (void)fprintf(stderr, 580 "usage: kdump [-dEnlRT] [-f trfile] [-m maxdata] [-p pid] [-t [cnisuw]]\n"); 581 exit(1); 582 } 583