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