1 /* $NetBSD: dump.c,v 1.15 2003/08/07 11:14:15 agc Exp $ */ 2 3 /*- 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1988, 1993\n\ 35 The Regents of the University of California. All rights reserved.\n"); 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)kdump.c 8.4 (Berkeley) 4/28/95"; 41 #endif 42 __RCSID("$NetBSD: dump.c,v 1.15 2003/08/07 11:14:15 agc Exp $"); 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #define _KERNEL 47 #include <sys/errno.h> 48 #undef _KERNEL 49 #include <sys/time.h> 50 #include <sys/uio.h> 51 #include <sys/ktrace.h> 52 #include <sys/ioctl.h> 53 #include <sys/ptrace.h> 54 #define _KERNEL 55 #include <sys/errno.h> 56 #undef _KERNEL 57 58 #include <err.h> 59 #include <signal.h> 60 #include <stdio.h> 61 #include <stdlib.h> 62 #include <string.h> 63 #include <unistd.h> 64 #include <vis.h> 65 66 #include "ktrace.h" 67 #include "misc.h" 68 #include "setemul.h" 69 70 int timestamp, decimal, fancy = 1, tail, maxdata; 71 72 #define eqs(s1, s2) (strcmp((s1), (s2)) == 0) 73 74 #include <sys/syscall.h> 75 76 static const char * const ptrace_ops[] = { 77 "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U", 78 "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE", 79 "PT_KILL", "PT_ATTACH", "PT_DETACH", 80 }; 81 82 83 void dumprecord __P((struct ktr_header *, int, int *, void **, FILE *)); 84 void dumpheader __P((struct ktr_header *, char *, int, int *)); 85 int fread_tail __P((char *, int, int, FILE *)); 86 void ioctldecode __P((u_long)); 87 int ktrsyscall __P((struct ktr_syscall *, int, char *, int, int *)); 88 void ktrsysret __P((struct ktr_sysret *, char *, int, int *)); 89 void ktrnamei __P((char *, int, char *, int, int *)); 90 void ktremul __P((struct ktr_header *, char *, int, char *, int, int *)); 91 void ktrgenio __P((struct ktr_genio *, int, char *, int, int *)); 92 void ktrpsig __P((struct ktr_psig *)); 93 void ktrcsw __P((struct ktr_csw *)); 94 95 #define KTR_BUFSZ 512 96 #define BLEFT (bufsz - (bp - buff)) 97 98 99 void 100 dumprecord(ktr, trpoints, sizep, mp, fp) 101 register struct ktr_header *ktr; 102 int trpoints; 103 int *sizep; 104 void **mp; 105 FILE *fp; 106 { 107 static void *mcopy = NULL; 108 static int linelen = 0, iolinelen = 0; 109 char buff[KTR_BUFSZ], iobuff[KTR_BUFSZ], *bp; 110 int ktrlen, *lenp; 111 void *m; 112 113 if (ktr->ktr_type == KTR_GENIO || ktr->ktr_type == KTR_EMUL) { 114 bp = iobuff; 115 lenp = &iolinelen; 116 } else { 117 bp = buff; 118 lenp = &linelen; 119 } 120 if (!mcopy && (trpoints & (1<<ktr->ktr_type))) 121 dumpheader(ktr, bp, KTR_BUFSZ, lenp); 122 123 if ((ktrlen = ktr->ktr_len) < 0) 124 errx(1, "bogus length 0x%x", ktrlen); 125 m = *mp; 126 if (ktrlen >= *sizep) { 127 while(ktrlen > *sizep) *sizep *= 2; 128 *mp = m = (void *)realloc(m, *sizep); 129 if (m == NULL) 130 errx(1, "realloc: %s", strerror(ENOMEM)); 131 } 132 if (ktrlen && fread_tail(m, ktrlen, 1, fp) == 0) 133 errx(1, "data too short"); 134 if ((trpoints & (1<<ktr->ktr_type)) == 0) 135 return; 136 137 /* update context to match currently processed record */ 138 ectx_sanify(ktr->ktr_pid); 139 140 switch (ktr->ktr_type) 141 { 142 case KTR_SYSCALL: 143 if (ktrsyscall((struct ktr_syscall *)m, 0, bp, KTR_BUFSZ, 144 lenp) == 0) { 145 mcopy = (void *)malloc(ktrlen + 1); 146 bcopy(m, mcopy, ktrlen); 147 return; 148 } 149 break; 150 case KTR_SYSRET: 151 ktrsysret((struct ktr_sysret *)m, bp, KTR_BUFSZ, lenp); 152 if (*iobuff || iolinelen) { 153 fputs(iobuff, stdout); 154 *iobuff = '\0'; 155 iolinelen = 0; 156 } 157 break; 158 case KTR_NAMEI: 159 ktrnamei(m, ktrlen, bp, sizeof(buff), lenp); 160 if (mcopy) { 161 (void) ktrsyscall((struct ktr_syscall *)mcopy, 1, bp, 162 KTR_BUFSZ, lenp); 163 free(mcopy); 164 mcopy = NULL; 165 } 166 break; 167 case KTR_GENIO: 168 ktrgenio((struct ktr_genio *)m, ktrlen, bp, KTR_BUFSZ, lenp); 169 break; 170 case KTR_PSIG: 171 ktrpsig((struct ktr_psig *)m); 172 break; 173 case KTR_CSW: 174 ktrcsw((struct ktr_csw *)m); 175 break; 176 case KTR_EMUL: 177 ktremul(ktr, m, ktrlen, bp, sizeof(buff), lenp); 178 break; 179 } 180 181 if (mcopy) { 182 free(mcopy); 183 mcopy = NULL; 184 } 185 } 186 187 void 188 dumpfile(file, fd, trpoints) 189 const char *file; 190 int fd; 191 int trpoints; 192 { 193 struct ktr_header ktr_header; 194 void *m; 195 FILE *fp; 196 int size; 197 198 m = (void *)malloc(size = 1024); 199 if (m == NULL) 200 errx(1, "malloc: %s", strerror(ENOMEM)); 201 if (!file || !*file) { 202 if (!(fp = fdopen(fd, "r"))) 203 err(1, "fdopen(%d)", fd); 204 } else if (!strcmp(file, "-")) 205 fp = stdin; 206 else if (!(fp = fopen(file, "r"))) 207 err(1, "%s", file); 208 209 while (fread_tail((char *)&ktr_header,sizeof(struct ktr_header),1,fp)) { 210 dumprecord(&ktr_header, trpoints, &size, &m, fp); 211 if (tail) 212 (void)fflush(stdout); 213 } 214 } 215 216 217 int 218 fread_tail(buf, size, num, fp) 219 char *buf; 220 int num, size; 221 FILE *fp; 222 { 223 int i; 224 225 while ((i = fread(buf, size, num, fp)) == 0 && tail) { 226 (void)sleep(1); 227 clearerr(fp); 228 } 229 return (i); 230 } 231 232 void 233 dumpheader(kth, buff, buffsz, lenp) 234 struct ktr_header *kth; 235 char *buff; 236 int buffsz, *lenp; 237 { 238 static struct timeval prevtime; 239 char *bp = buff + *lenp; 240 struct timeval temp; 241 242 if (kth->ktr_type == KTR_SYSRET || kth->ktr_type == KTR_GENIO) 243 return; 244 *lenp = 0; 245 (void)snprintf(bp, buffsz - *lenp, "%6d %-8.*s ", 246 kth->ktr_pid, MAXCOMLEN, kth->ktr_comm); 247 *lenp += strlen(bp); 248 bp = buff + *lenp; 249 250 if (timestamp) { 251 if (timestamp == 2) { 252 timersub(&kth->ktr_time, &prevtime, &temp); 253 prevtime = kth->ktr_time; 254 } else 255 temp = kth->ktr_time; 256 (void)snprintf(bp, buffsz - *lenp, "%ld.%06ld ", 257 (long int)temp.tv_sec, 258 (long int)temp.tv_usec); 259 *lenp += strlen(bp); 260 } 261 } 262 263 void 264 ioctldecode(cmd) 265 u_long cmd; 266 { 267 char dirbuf[4], *dir = dirbuf; 268 269 if (cmd & IOC_OUT) 270 *dir++ = 'W'; 271 if (cmd & IOC_IN) 272 *dir++ = 'R'; 273 *dir = '\0'; 274 275 printf(decimal ? ",_IO%s('%c',%ld" : ",_IO%s('%c',%#lx", 276 dirbuf, (int) ((cmd >> 8) & 0xff), cmd & 0xff); 277 if ((cmd & IOC_VOID) == 0) 278 printf(decimal ? ",%ld)" : ",%#lx)", (cmd >> 16) & 0xff); 279 else 280 printf(")"); 281 } 282 283 int 284 ktrsyscall(ktr, nohdr, buff, bufsz, lenp) 285 register struct ktr_syscall *ktr; 286 int nohdr, bufsz, *lenp; 287 char *buff; 288 { 289 register int argsize = ktr->ktr_argsize; 290 register register_t *ap; 291 char *bp = buff; 292 int eol = 1; 293 294 if (*lenp < bufsz) { 295 bp += *lenp; 296 bzero(bp, BLEFT); 297 } 298 if (!nohdr) { 299 if (ktr->ktr_code >= current->nsysnames || ktr->ktr_code < 0) 300 (void)snprintf(bp, BLEFT, "[%d]", ktr->ktr_code); 301 else 302 (void)snprintf(bp, BLEFT, 303 "%s", current->sysnames[ktr->ktr_code]); 304 bp += strlen(bp); 305 } 306 ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall)); 307 if (argsize) { 308 char *s = "("; 309 if (fancy && !nohdr) { 310 switch (ktr->ktr_code) { 311 /* 312 * All these have a path as the first param. 313 * The order is same as syscalls.master. 314 */ 315 case SYS_open: 316 case SYS_link: 317 case SYS_unlink: 318 case SYS_chdir: 319 case SYS_mknod: 320 case SYS_chmod: 321 case SYS_chown: 322 case SYS_unmount: 323 case SYS_access: 324 case SYS_chflags: 325 case SYS_acct: 326 case SYS_revoke: 327 case SYS_symlink: 328 case SYS_readlink: 329 case SYS_execve: 330 case SYS_chroot: 331 case SYS_rename: 332 case SYS_mkfifo: 333 case SYS_mkdir: 334 case SYS_rmdir: 335 case SYS_utimes: 336 case SYS_quotactl: 337 case SYS_statfs: 338 case SYS_getfh: 339 case SYS_pathconf: 340 case SYS_truncate: 341 case SYS_undelete: 342 case SYS___posix_rename: 343 case SYS_lchmod: 344 case SYS_lchown: 345 case SYS_lutimes: 346 case SYS___stat13: 347 case SYS___lstat13: 348 case SYS___posix_chown: 349 case SYS___posix_lchown: 350 case SYS_lchflags: 351 if (BLEFT > 1) 352 *bp++ = '('; 353 eol = 0; 354 break; 355 case SYS___sigaction14 : 356 (void)snprintf(bp, BLEFT, "(%s", 357 signals[(int)*ap].name); 358 s = ", "; 359 argsize -= sizeof(register_t); 360 ap++; 361 break; 362 case SYS_ioctl : 363 if (decimal) 364 (void)snprintf(bp, BLEFT, "(%ld", 365 (long)*ap); 366 else 367 (void)snprintf(bp, BLEFT, "(%#lx", 368 (long)*ap); 369 bp += strlen(bp); 370 ap++; 371 argsize -= sizeof(register_t); 372 if ((s = ioctlname(*ap)) != NULL) 373 (void)snprintf(bp, BLEFT, ", %s", s); 374 else 375 ioctldecode(*ap); 376 s = ", "; 377 ap++; 378 argsize -= sizeof(register_t); 379 break; 380 case SYS_ptrace : 381 if (*ap >= 0 && *ap <= 382 sizeof(ptrace_ops) / sizeof(ptrace_ops[0])) 383 (void)snprintf(bp, BLEFT, "(%s", 384 ptrace_ops[*ap]); 385 else 386 (void)snprintf(bp, BLEFT, "(%ld", 387 (long)*ap); 388 s = ", "; 389 ap++; 390 argsize -= sizeof(register_t); 391 break; 392 default : 393 break; 394 } 395 bp += strlen(bp); 396 } 397 if (eol) { 398 while (argsize) { 399 if (!nohdr || strcmp(s, "(")) { 400 if (decimal) 401 (void)snprintf(bp, BLEFT, 402 "%s%ld", s, 403 (long)*ap); 404 else 405 (void)snprintf(bp, BLEFT, 406 "%s%#lx", s, 407 (long)*ap); 408 bp += strlen(bp); 409 } 410 s = ", "; 411 ap++; 412 argsize -= sizeof(register_t); 413 } 414 if (BLEFT > 1) 415 *bp++ = ')'; 416 } 417 } 418 *bp = '\0'; 419 420 *lenp = bp - buff; 421 return eol; 422 } 423 424 void 425 ktrsysret(ktr, buff, buffsz, lenp) 426 struct ktr_sysret *ktr; 427 int buffsz, *lenp; 428 char *buff; 429 { 430 register register_t ret = ktr->ktr_retval; 431 register int error = ktr->ktr_error; 432 433 while (*lenp < 50) 434 buff[(*lenp)++] = ' '; 435 if (error == EJUSTRETURN) 436 strcpy(buff + *lenp, " JUSTRETURN"); 437 else if (error == ERESTART) 438 strcpy(buff + *lenp, " RESTART"); 439 else if (error) { 440 sprintf(buff + *lenp, " Err#%d", error); 441 if (error < MAXERRNOS && error >= -2) 442 sprintf(buff + strlen(buff), " %s",errnos[error].name); 443 } else 444 sprintf(buff + *lenp, " = %ld", (long)ret); 445 strcat(buff + *lenp, "\n"); 446 *lenp = 0; 447 fputs(buff, stdout); 448 *buff = '\0'; 449 } 450 451 void 452 ktrnamei(cp, len, buff, buffsz, lenp) 453 int buffsz, *lenp; 454 char *cp, *buff; 455 { 456 snprintf(buff + *lenp, buffsz - *lenp, "\"%.*s\"", len, cp); 457 *lenp += strlen(buff + *lenp); 458 } 459 460 void 461 ktremul(ktr_header, cp, len, buff, buffsz, lenp) 462 struct ktr_header *ktr_header; 463 int buffsz, *lenp; 464 char *cp, *buff; 465 { 466 bzero(buff + *lenp, buffsz - *lenp); 467 cp[len] = '\0'; 468 snprintf(buff + *lenp, buffsz - *lenp, "emul(%s)\n", cp); 469 *lenp += strlen(buff + *lenp); 470 471 setemul(cp, ktr_header->ktr_pid, 1); 472 } 473 474 void 475 ktrgenio(ktr, len, buff, bufsz, lenp) 476 struct ktr_genio *ktr; 477 int len; 478 char *buff; 479 int bufsz, *lenp; 480 { 481 static int screenwidth = 0; 482 register int datalen = len - sizeof (struct ktr_genio); 483 register char *dp = (char *)ktr + sizeof (struct ktr_genio); 484 register int col = 0; 485 register int width; 486 char visbuf[5], *bp = buff; 487 488 if (*lenp < bufsz) { 489 bp += *lenp; 490 bzero(buff, BLEFT); 491 } else 492 *lenp = 0; 493 if (screenwidth == 0) { 494 struct winsize ws; 495 496 if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 && 497 ws.ws_col > 8) 498 screenwidth = ws.ws_col; 499 else 500 screenwidth = 80; 501 } 502 503 if (maxdata && datalen > maxdata) 504 datalen = maxdata; 505 strcpy(bp, " \""); 506 col = *lenp; 507 col += 8; 508 bp += 8; 509 for (; datalen > 0; datalen--, dp++) { 510 (void) vis(visbuf, *dp, VIS_NL|VIS_TAB|VIS_CSTYLE, *(dp+1)); 511 width = strlen(visbuf); 512 visbuf[4] = '\0'; 513 if (col + width + 2 >= screenwidth) 514 break; 515 col += width; 516 strncpy(bp, visbuf, width); 517 bp += width; 518 if (col + 2 >= screenwidth) 519 break; 520 } 521 strcpy(bp, "\"\n"); 522 *lenp = col + 2; 523 } 524 525 void 526 ktrpsig(psig) 527 struct ktr_psig *psig; 528 { 529 (void)printf("SIG%s ", sys_signame[psig->signo]); 530 if (psig->action == SIG_DFL) 531 (void)printf("SIG_DFL\n"); 532 else { 533 (void)printf("caught handler=0x%lx mask=0x%lx code=0x%x\n", 534 (u_long)psig->action, (unsigned long)psig->mask.__bits[0], 535 psig->code); 536 } 537 } 538 539 void 540 ktrcsw(cs) 541 struct ktr_csw *cs; 542 { 543 (void)printf("%s %s\n", cs->out ? "stop" : "resume", 544 cs->user ? "user" : "kernel"); 545 } 546