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