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