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