1 /* $NetBSD: dump.c,v 1.11 2000/11/13 21:36:22 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.11 2000/11/13 21:36:22 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 char *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) { 118 printf("%s\n", buff); 119 if (*iobuff) 120 printf("%s\n", iobuff); 121 return; 122 } 123 124 if (ktr->ktr_type == KTR_GENIO || ktr->ktr_type == KTR_EMUL) { 125 bp = iobuff; 126 lenp = &iolinelen; 127 } else { 128 bp = buff; 129 lenp = &linelen; 130 } 131 if (!mcopy && (trpoints & (1<<ktr->ktr_type))) 132 dumpheader(ktr, bp, KTR_BUFSZ, lenp); 133 134 if ((ktrlen = ktr->ktr_len) < 0) 135 errx(1, "bogus length 0x%x", ktrlen); 136 m = *mp; 137 if (ktrlen >= *sizep) { 138 while(ktrlen > *sizep) *sizep *= 2; 139 *mp = m = (void *)realloc(m, *sizep); 140 if (m == NULL) 141 errx(1, "realloc: %s", strerror(ENOMEM)); 142 } 143 if (ktrlen && fread_tail(m, ktrlen, 1, fp) == 0) 144 errx(1, "data too short"); 145 if ((trpoints & (1<<ktr->ktr_type)) == 0) 146 return; 147 148 /* update context to match currently processed record */ 149 ectx_sanify(ktr->ktr_pid); 150 151 switch (ktr->ktr_type) 152 { 153 case KTR_SYSCALL: 154 if (ktrsyscall((struct ktr_syscall *)m, 0, bp, KTR_BUFSZ, 155 lenp) == 0) { 156 mcopy = (void *)malloc(ktrlen + 1); 157 bcopy(m, mcopy, ktrlen); 158 return; 159 } 160 break; 161 case KTR_SYSRET: 162 ktrsysret((struct ktr_sysret *)m, bp, KTR_BUFSZ, lenp); 163 if (*iobuff || iolinelen) { 164 fputs(iobuff, stdout); 165 *iobuff = '\0'; 166 iolinelen = 0; 167 } 168 break; 169 case KTR_NAMEI: 170 ktrnamei(m, ktrlen, bp, sizeof(buff), lenp); 171 if (mcopy) { 172 (void) ktrsyscall((struct ktr_syscall *)mcopy, 1, bp, 173 KTR_BUFSZ, lenp); 174 free(mcopy); 175 mcopy = NULL; 176 } 177 break; 178 case KTR_GENIO: 179 ktrgenio((struct ktr_genio *)m, ktrlen, bp, KTR_BUFSZ, lenp); 180 break; 181 case KTR_PSIG: 182 ktrpsig((struct ktr_psig *)m); 183 break; 184 case KTR_CSW: 185 ktrcsw((struct ktr_csw *)m); 186 break; 187 case KTR_EMUL: 188 ktremul(ktr, m, ktrlen, bp, sizeof(buff), lenp); 189 break; 190 } 191 192 if (mcopy) { 193 free(mcopy); 194 mcopy = NULL; 195 } 196 } 197 198 void 199 dumpfile(file, fd, trpoints) 200 const char *file; 201 int fd; 202 int trpoints; 203 { 204 struct ktr_header ktr_header; 205 void *m; 206 FILE *fp; 207 int size; 208 209 m = (void *)malloc(size = 1024); 210 if (m == NULL) 211 errx(1, "malloc: %s", strerror(ENOMEM)); 212 if (!file || !*file) { 213 if (!(fp = fdopen(fd, "r"))) 214 err(1, "fdopen(%d)", fd); 215 } else if (!strcmp(file, "-")) 216 fp = stdin; 217 else if (!(fp = fopen(file, "r"))) 218 err(1, "%s", file); 219 220 while (fread_tail((char *)&ktr_header,sizeof(struct ktr_header),1,fp)) { 221 dumprecord(&ktr_header, trpoints, &size, &m, fp); 222 if (tail) 223 (void)fflush(stdout); 224 } 225 dumprecord(NULL, 0, NULL, NULL, fp); 226 } 227 228 229 int 230 fread_tail(buf, size, num, fp) 231 char *buf; 232 int num, size; 233 FILE *fp; 234 { 235 int i; 236 237 while ((i = fread(buf, size, num, fp)) == 0 && tail) { 238 (void)sleep(1); 239 clearerr(fp); 240 } 241 return (i); 242 } 243 244 void 245 dumpheader(kth, buff, buffsz, lenp) 246 struct ktr_header *kth; 247 char *buff; 248 int buffsz, *lenp; 249 { 250 static struct timeval prevtime; 251 char *bp = buff + *lenp; 252 struct timeval temp; 253 254 if (kth->ktr_type == KTR_SYSRET || kth->ktr_type == KTR_GENIO) 255 return; 256 *lenp = 0; 257 (void)snprintf(bp, buffsz - *lenp, "%6d %-8.*s ", 258 kth->ktr_pid, MAXCOMLEN, kth->ktr_comm); 259 *lenp += strlen(bp); 260 bp = buff + *lenp; 261 262 if (timestamp) { 263 if (timestamp == 2) { 264 timersub(&kth->ktr_time, &prevtime, &temp); 265 prevtime = kth->ktr_time; 266 } else 267 temp = kth->ktr_time; 268 (void)snprintf(bp, buffsz - *lenp, "%ld.%06ld ", 269 (long int)temp.tv_sec, 270 (long int)temp.tv_usec); 271 *lenp += strlen(bp); 272 } 273 } 274 275 void 276 ioctldecode(cmd) 277 u_long cmd; 278 { 279 char dirbuf[4], *dir = dirbuf; 280 281 if (cmd & IOC_OUT) 282 *dir++ = 'W'; 283 if (cmd & IOC_IN) 284 *dir++ = 'R'; 285 *dir = '\0'; 286 287 printf(decimal ? ",_IO%s('%c',%ld" : ",_IO%s('%c',%#lx", 288 dirbuf, (int) ((cmd >> 8) & 0xff), cmd & 0xff); 289 if ((cmd & IOC_VOID) == 0) 290 printf(decimal ? ",%ld)" : ",%#lx)", (cmd >> 16) & 0xff); 291 else 292 printf(")"); 293 } 294 295 int 296 ktrsyscall(ktr, nohdr, buff, bufsz, lenp) 297 register struct ktr_syscall *ktr; 298 int nohdr, bufsz, *lenp; 299 char *buff; 300 { 301 register int argsize = ktr->ktr_argsize; 302 register register_t *ap; 303 char *bp = buff; 304 int eol = 1; 305 306 if (*lenp < bufsz) { 307 bp += *lenp; 308 bzero(bp, BLEFT); 309 } 310 if (!nohdr) { 311 if (ktr->ktr_code >= current->nsysnames || ktr->ktr_code < 0) 312 (void)snprintf(bp, BLEFT, "[%d]", ktr->ktr_code); 313 else 314 (void)snprintf(bp, BLEFT, 315 "%s", current->sysnames[ktr->ktr_code]); 316 bp += strlen(bp); 317 } 318 ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall)); 319 if (argsize) { 320 char *s = "("; 321 if (fancy && !nohdr) { 322 switch (ktr->ktr_code) { 323 /* 324 * All these have a path as the first param. 325 */ 326 case SYS_open : case SYS_chdir : 327 case SYS___stat13 : case SYS_chroot : 328 case SYS_execve : case SYS_pathconf : 329 case SYS_rmdir : case SYS_rename : 330 case SYS_symlink : case SYS_chflags : 331 case SYS_link : case SYS_mkdir : 332 case SYS_mknod : case SYS_mkfifo : 333 if (BLEFT > 1) 334 *bp++ = '('; 335 eol = 0; 336 break; 337 case SYS___sigaction14 : 338 (void)snprintf(bp, BLEFT, "(%s", 339 signals[(int)*ap].name); 340 s = ", "; 341 argsize -= sizeof(register_t); 342 ap++; 343 break; 344 case SYS_ioctl : 345 if (decimal) 346 (void)snprintf(bp, BLEFT, "(%ld", 347 (long)*ap); 348 else 349 (void)snprintf(bp, BLEFT, "(%#lx", 350 (long)*ap); 351 bp += strlen(bp); 352 ap++; 353 argsize -= sizeof(register_t); 354 if ((s = ioctlname(*ap)) != NULL) 355 (void)snprintf(bp, BLEFT, ", %s", s); 356 else 357 ioctldecode(*ap); 358 s = ", "; 359 ap++; 360 argsize -= sizeof(register_t); 361 break; 362 case SYS_ptrace : 363 if (*ap >= 0 && *ap <= 364 sizeof(ptrace_ops) / sizeof(ptrace_ops[0])) 365 (void)snprintf(bp, BLEFT, "(%s", 366 ptrace_ops[*ap]); 367 else 368 (void)snprintf(bp, BLEFT, "(%ld", 369 (long)*ap); 370 s = ", "; 371 ap++; 372 argsize -= sizeof(register_t); 373 break; 374 default : 375 break; 376 } 377 bp += strlen(bp); 378 } 379 if (eol) { 380 while (argsize) { 381 if (!nohdr || strcmp(s, "(")) { 382 if (decimal) 383 (void)snprintf(bp, BLEFT, 384 "%s%ld", s, 385 (long)*ap); 386 else 387 (void)snprintf(bp, BLEFT, 388 "%s%#lx", s, 389 (long)*ap); 390 bp += strlen(bp); 391 } 392 s = ", "; 393 ap++; 394 argsize -= sizeof(register_t); 395 } 396 if (BLEFT > 1) 397 *bp++ = ')'; 398 } 399 } 400 *bp = '\0'; 401 402 *lenp = bp - buff; 403 return eol; 404 } 405 406 void 407 ktrsysret(ktr, buff, buffsz, lenp) 408 struct ktr_sysret *ktr; 409 int buffsz, *lenp; 410 char *buff; 411 { 412 register register_t ret = ktr->ktr_retval; 413 register int error = ktr->ktr_error; 414 415 while (*lenp < 50) 416 buff[(*lenp)++] = ' '; 417 if (error == EJUSTRETURN) 418 strcpy(buff + *lenp, " JUSTRETURN"); 419 else if (error == ERESTART) 420 strcpy(buff + *lenp, " RESTART"); 421 else if (error) { 422 sprintf(buff + *lenp, " Err#%d", error); 423 if (error < MAXERRNOS && error >= -2) 424 sprintf(buff + strlen(buff), " %s",errnos[error].name); 425 } else 426 sprintf(buff + *lenp, " = %ld", (long)ret); 427 strcat(buff + *lenp, "\n"); 428 *lenp = 0; 429 fputs(buff, stdout); 430 *buff = '\0'; 431 } 432 433 void 434 ktrnamei(cp, len, buff, buffsz, lenp) 435 int buffsz, *lenp; 436 char *cp, *buff; 437 { 438 snprintf(buff + *lenp, buffsz - *lenp, "\"%.*s\"", len, cp); 439 *lenp += strlen(buff + *lenp); 440 } 441 442 void 443 ktremul(ktr_header, cp, len, buff, buffsz, lenp) 444 struct ktr_header *ktr_header; 445 int buffsz, *lenp; 446 char *cp, *buff; 447 { 448 bzero(buff + *lenp, buffsz - *lenp); 449 cp[len] = '\0'; 450 snprintf(buff + *lenp, buffsz - *lenp, "emul(%s)\n", cp); 451 *lenp += strlen(buff + *lenp); 452 453 setemul(cp, ktr_header->ktr_pid, 1); 454 } 455 456 void 457 ktrgenio(ktr, len, buff, bufsz, lenp) 458 struct ktr_genio *ktr; 459 int len; 460 char *buff; 461 int bufsz, *lenp; 462 { 463 static int screenwidth = 0; 464 register int datalen = len - sizeof (struct ktr_genio); 465 register char *dp = (char *)ktr + sizeof (struct ktr_genio); 466 register int col = 0; 467 register int width; 468 char visbuf[5], *bp = buff; 469 470 if (*lenp < bufsz) { 471 bp += *lenp; 472 bzero(buff, BLEFT); 473 } else 474 *lenp = 0; 475 if (screenwidth == 0) { 476 struct winsize ws; 477 478 if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 && 479 ws.ws_col > 8) 480 screenwidth = ws.ws_col; 481 else 482 screenwidth = 80; 483 } 484 485 if (maxdata && datalen > maxdata) 486 datalen = maxdata; 487 strcpy(bp, " \""); 488 col = *lenp; 489 col += 8; 490 bp += 8; 491 for (; datalen > 0; datalen--, dp++) { 492 (void) vis(visbuf, *dp, VIS_NL|VIS_TAB|VIS_CSTYLE, *(dp+1)); 493 width = strlen(visbuf); 494 visbuf[4] = '\0'; 495 if (col + width + 2 >= screenwidth) 496 break; 497 col += width; 498 strncpy(bp, visbuf, width); 499 bp += width; 500 if (col + 2 >= screenwidth) 501 break; 502 } 503 strcpy(bp, "\"\n"); 504 *lenp = col + 2; 505 } 506 507 void 508 ktrpsig(psig) 509 struct ktr_psig *psig; 510 { 511 (void)printf("SIG%s ", sys_signame[psig->signo]); 512 if (psig->action == SIG_DFL) 513 (void)printf("SIG_DFL\n"); 514 else { 515 (void)printf("caught handler=0x%lx mask=0x%lx code=0x%x\n", 516 (u_long)psig->action, (unsigned long)psig->mask.__bits[0], 517 psig->code); 518 } 519 } 520 521 void 522 ktrcsw(cs) 523 struct ktr_csw *cs; 524 { 525 (void)printf("%s %s\n", cs->out ? "stop" : "resume", 526 cs->user ? "user" : "kernel"); 527 } 528