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