kdump.c revision 99112
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1988, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 3527443Scharnierstatic const char copyright[] = 361590Srgrimes"@(#) Copyright (c) 1988, 1993\n\ 371590Srgrimes The Regents of the University of California. All rights reserved.\n"; 381590Srgrimes#endif /* not lint */ 391590Srgrimes 401590Srgrimes#ifndef lint 4127443Scharnier#if 0 421590Srgrimesstatic char sccsid[] = "@(#)kdump.c 8.1 (Berkeley) 6/6/93"; 4327443Scharnier#endif 441590Srgrimes#endif /* not lint */ 4599112Sobrien#include <sys/cdefs.h> 4699112Sobrien__FBSDID("$FreeBSD: head/usr.bin/kdump/kdump.c 99112 2002-06-30 05:25:07Z obrien $"); 471590Srgrimes 4855206Speter#define _KERNEL 492215Scsgrextern int errno; 502215Scsgr#include <sys/errno.h> 5155206Speter#undef _KERNEL 521590Srgrimes#include <sys/param.h> 531590Srgrimes#include <sys/errno.h> 541590Srgrimes#include <sys/time.h> 551590Srgrimes#include <sys/uio.h> 561590Srgrimes#include <sys/ktrace.h> 571590Srgrimes#include <sys/ioctl.h> 581590Srgrimes#include <sys/ptrace.h> 5927443Scharnier#include <err.h> 6027443Scharnier#include <locale.h> 611590Srgrimes#include <stdio.h> 621590Srgrimes#include <stdlib.h> 631590Srgrimes#include <string.h> 6427443Scharnier#include <unistd.h> 6527443Scharnier#include <vis.h> 661590Srgrimes#include "ktrace.h" 671590Srgrimes 681590Srgrimesint timestamp, decimal, fancy = 1, tail, maxdata; 691590Srgrimeschar *tracefile = DEF_TRACEFILE; 701590Srgrimesstruct ktr_header ktr_header; 711590Srgrimes 721590Srgrimes#define eqs(s1, s2) (strcmp((s1), (s2)) == 0) 731590Srgrimes 741590Srgrimesmain(argc, argv) 751590Srgrimes int argc; 761590Srgrimes char *argv[]; 771590Srgrimes{ 781590Srgrimes int ch, ktrlen, size; 791590Srgrimes register void *m; 801590Srgrimes int trpoints = ALL_POINTS; 811590Srgrimes 8211823Sache (void) setlocale(LC_CTYPE, ""); 8311823Sache 8424360Simp while ((ch = getopt(argc,argv,"f:dlm:nRTt:")) != -1) 851590Srgrimes switch((char)ch) { 861590Srgrimes case 'f': 871590Srgrimes tracefile = optarg; 881590Srgrimes break; 891590Srgrimes case 'd': 901590Srgrimes decimal = 1; 911590Srgrimes break; 921590Srgrimes case 'l': 931590Srgrimes tail = 1; 941590Srgrimes break; 951590Srgrimes case 'm': 961590Srgrimes maxdata = atoi(optarg); 971590Srgrimes break; 981590Srgrimes case 'n': 991590Srgrimes fancy = 0; 1001590Srgrimes break; 1011590Srgrimes case 'R': 1021590Srgrimes timestamp = 2; /* relative timestamp */ 1031590Srgrimes break; 1041590Srgrimes case 'T': 1051590Srgrimes timestamp = 1; 1061590Srgrimes break; 1071590Srgrimes case 't': 1081590Srgrimes trpoints = getpoints(optarg); 10927443Scharnier if (trpoints < 0) 11027443Scharnier errx(1, "unknown trace point in %s", optarg); 1111590Srgrimes break; 1121590Srgrimes default: 1131590Srgrimes usage(); 1141590Srgrimes } 1151590Srgrimes 11619853Sfenner if (argc > optind) 1171590Srgrimes usage(); 1181590Srgrimes 1191590Srgrimes m = (void *)malloc(size = 1025); 12027443Scharnier if (m == NULL) 12127443Scharnier errx(1, "%s", strerror(ENOMEM)); 12227443Scharnier if (!freopen(tracefile, "r", stdin)) 12327443Scharnier err(1, "%s", tracefile); 1241590Srgrimes while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) { 1251590Srgrimes if (trpoints & (1<<ktr_header.ktr_type)) 1261590Srgrimes dumpheader(&ktr_header); 12727443Scharnier if ((ktrlen = ktr_header.ktr_len) < 0) 12827443Scharnier errx(1, "bogus length 0x%x", ktrlen); 1291590Srgrimes if (ktrlen > size) { 1301590Srgrimes m = (void *)realloc(m, ktrlen+1); 13127443Scharnier if (m == NULL) 13227443Scharnier errx(1, "%s", strerror(ENOMEM)); 1331590Srgrimes size = ktrlen; 1341590Srgrimes } 13527443Scharnier if (ktrlen && fread_tail(m, ktrlen, 1) == 0) 13627443Scharnier errx(1, "data too short"); 1371590Srgrimes if ((trpoints & (1<<ktr_header.ktr_type)) == 0) 1381590Srgrimes continue; 1391590Srgrimes switch (ktr_header.ktr_type) { 1401590Srgrimes case KTR_SYSCALL: 1411590Srgrimes ktrsyscall((struct ktr_syscall *)m); 1421590Srgrimes break; 1431590Srgrimes case KTR_SYSRET: 1441590Srgrimes ktrsysret((struct ktr_sysret *)m); 1451590Srgrimes break; 1461590Srgrimes case KTR_NAMEI: 1471590Srgrimes ktrnamei(m, ktrlen); 1481590Srgrimes break; 1491590Srgrimes case KTR_GENIO: 1501590Srgrimes ktrgenio((struct ktr_genio *)m, ktrlen); 1511590Srgrimes break; 1521590Srgrimes case KTR_PSIG: 1531590Srgrimes ktrpsig((struct ktr_psig *)m); 1541590Srgrimes break; 1551590Srgrimes case KTR_CSW: 1561590Srgrimes ktrcsw((struct ktr_csw *)m); 1571590Srgrimes break; 15818400Sphk case KTR_USER: 15918470Sphk ktruser(ktrlen, m); 16018400Sphk break; 1611590Srgrimes } 1621590Srgrimes if (tail) 1631590Srgrimes (void)fflush(stdout); 1641590Srgrimes } 1651590Srgrimes} 1661590Srgrimes 1671590Srgrimesfread_tail(buf, size, num) 1681590Srgrimes char *buf; 1691590Srgrimes int num, size; 1701590Srgrimes{ 1711590Srgrimes int i; 1721590Srgrimes 1731590Srgrimes while ((i = fread(buf, size, num, stdin)) == 0 && tail) { 1741590Srgrimes (void)sleep(1); 1751590Srgrimes clearerr(stdin); 1761590Srgrimes } 1771590Srgrimes return (i); 1781590Srgrimes} 1791590Srgrimes 1801590Srgrimesdumpheader(kth) 1811590Srgrimes struct ktr_header *kth; 1821590Srgrimes{ 1831590Srgrimes static char unknown[64]; 1841590Srgrimes static struct timeval prevtime, temp; 1851590Srgrimes char *type; 1861590Srgrimes 1871590Srgrimes switch (kth->ktr_type) { 1881590Srgrimes case KTR_SYSCALL: 1891590Srgrimes type = "CALL"; 1901590Srgrimes break; 1911590Srgrimes case KTR_SYSRET: 1921590Srgrimes type = "RET "; 1931590Srgrimes break; 1941590Srgrimes case KTR_NAMEI: 1951590Srgrimes type = "NAMI"; 1961590Srgrimes break; 1971590Srgrimes case KTR_GENIO: 1981590Srgrimes type = "GIO "; 1991590Srgrimes break; 2001590Srgrimes case KTR_PSIG: 2011590Srgrimes type = "PSIG"; 2021590Srgrimes break; 2031590Srgrimes case KTR_CSW: 2041590Srgrimes type = "CSW"; 2051590Srgrimes break; 20618400Sphk case KTR_USER: 20718400Sphk type = "USER"; 20818400Sphk break; 2091590Srgrimes default: 2101590Srgrimes (void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type); 2111590Srgrimes type = unknown; 2121590Srgrimes } 2131590Srgrimes 21447349Sjmz (void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm); 2151590Srgrimes if (timestamp) { 2161590Srgrimes if (timestamp == 2) { 2171590Srgrimes temp = kth->ktr_time; 2181590Srgrimes timevalsub(&kth->ktr_time, &prevtime); 2191590Srgrimes prevtime = temp; 2201590Srgrimes } 2211590Srgrimes (void)printf("%ld.%06ld ", 2221590Srgrimes kth->ktr_time.tv_sec, kth->ktr_time.tv_usec); 2231590Srgrimes } 2241590Srgrimes (void)printf("%s ", type); 2251590Srgrimes} 2261590Srgrimes 2271590Srgrimes#include <sys/syscall.h> 2281590Srgrimes#define KTRACE 2294721Sphk#include <sys/kern/syscalls.c> 2301590Srgrimes#undef KTRACE 2311590Srgrimesint nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]); 2321590Srgrimes 2331590Srgrimesstatic char *ptrace_ops[] = { 2341590Srgrimes "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U", 2351590Srgrimes "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE", 23648234Sbde "PT_KILL", "PT_STEP", "PT_ATTACH", "PT_DETACH", 2371590Srgrimes}; 2381590Srgrimes 2391590Srgrimesktrsyscall(ktr) 2401590Srgrimes register struct ktr_syscall *ktr; 2411590Srgrimes{ 2421590Srgrimes register narg = ktr->ktr_narg; 24347957Sdt register register_t *ip; 2441590Srgrimes char *ioctlname(); 2451590Srgrimes 2461590Srgrimes if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0) 2471590Srgrimes (void)printf("[%d]", ktr->ktr_code); 2481590Srgrimes else 2491590Srgrimes (void)printf("%s", syscallnames[ktr->ktr_code]); 25047957Sdt ip = &ktr->ktr_args[0]; 2511590Srgrimes if (narg) { 2521590Srgrimes char c = '('; 2531590Srgrimes if (fancy) { 2541590Srgrimes if (ktr->ktr_code == SYS_ioctl) { 2551590Srgrimes char *cp; 2561590Srgrimes if (decimal) 25747957Sdt (void)printf("(%ld", (long)*ip); 2581590Srgrimes else 25947957Sdt (void)printf("(%#lx", (long)*ip); 2601590Srgrimes ip++; 2611590Srgrimes narg--; 2621590Srgrimes if ((cp = ioctlname(*ip)) != NULL) 2631590Srgrimes (void)printf(",%s", cp); 2641590Srgrimes else { 2651590Srgrimes if (decimal) 26647957Sdt (void)printf(",%ld", (long)*ip); 2671590Srgrimes else 26847957Sdt (void)printf(",%#lx ", (long)*ip); 2691590Srgrimes } 2701590Srgrimes c = ','; 2711590Srgrimes ip++; 2721590Srgrimes narg--; 2731590Srgrimes } else if (ktr->ktr_code == SYS_ptrace) { 27448234Sbde if (*ip < sizeof(ptrace_ops) / 27548234Sbde sizeof(ptrace_ops[0]) && *ip >= 0) 2761590Srgrimes (void)printf("(%s", ptrace_ops[*ip]); 27748234Sbde#ifdef PT_GETREGS 27848234Sbde else if (*ip == PT_GETREGS) 27948234Sbde (void)printf("(%s", "PT_GETREGS"); 28048234Sbde#endif 28148234Sbde#ifdef PT_SETREGS 28248234Sbde else if (*ip == PT_SETREGS) 28348234Sbde (void)printf("(%s", "PT_SETREGS"); 28448234Sbde#endif 28548234Sbde#ifdef PT_GETFPREGS 28648234Sbde else if (*ip == PT_GETFPREGS) 28748234Sbde (void)printf("(%s", "PT_GETFPREGS"); 28848234Sbde#endif 28948234Sbde#ifdef PT_SETFPREGS 29048234Sbde else if (*ip == PT_SETFPREGS) 29148234Sbde (void)printf("(%s", "PT_SETFPREGS"); 29248234Sbde#endif 29348852Sbde#ifdef PT_GETDBREGS 29448852Sbde else if (*ip == PT_GETDBREGS) 29548852Sbde (void)printf("(%s", "PT_GETDBREGS"); 29648852Sbde#endif 29748852Sbde#ifdef PT_SETDBREGS 29848852Sbde else if (*ip == PT_SETDBREGS) 29948852Sbde (void)printf("(%s", "PT_SETDBREGS"); 30048852Sbde#endif 3011590Srgrimes else 30247957Sdt (void)printf("(%ld", (long)*ip); 3031590Srgrimes c = ','; 3041590Srgrimes ip++; 3051590Srgrimes narg--; 3061590Srgrimes } 3071590Srgrimes } 3081590Srgrimes while (narg) { 3091590Srgrimes if (decimal) 31047957Sdt (void)printf("%c%ld", c, (long)*ip); 3111590Srgrimes else 31247957Sdt (void)printf("%c%#lx", c, (long)*ip); 3131590Srgrimes c = ','; 3141590Srgrimes ip++; 3151590Srgrimes narg--; 3161590Srgrimes } 3171590Srgrimes (void)putchar(')'); 3181590Srgrimes } 3191590Srgrimes (void)putchar('\n'); 3201590Srgrimes} 3211590Srgrimes 3221590Srgrimesktrsysret(ktr) 3231590Srgrimes struct ktr_sysret *ktr; 3241590Srgrimes{ 32547957Sdt register register_t ret = ktr->ktr_retval; 3261590Srgrimes register int error = ktr->ktr_error; 3271590Srgrimes register int code = ktr->ktr_code; 3281590Srgrimes 3291590Srgrimes if (code >= nsyscalls || code < 0) 3301590Srgrimes (void)printf("[%d] ", code); 3311590Srgrimes else 3321590Srgrimes (void)printf("%s ", syscallnames[code]); 3331590Srgrimes 3341590Srgrimes if (error == 0) { 3351590Srgrimes if (fancy) { 3361590Srgrimes (void)printf("%d", ret); 3371590Srgrimes if (ret < 0 || ret > 9) 33847957Sdt (void)printf("/%#lx", (long)ret); 3391590Srgrimes } else { 3401590Srgrimes if (decimal) 34147957Sdt (void)printf("%ld", (long)ret); 3421590Srgrimes else 34347957Sdt (void)printf("%#lx", (long)ret); 3441590Srgrimes } 3451590Srgrimes } else if (error == ERESTART) 3461590Srgrimes (void)printf("RESTART"); 3471590Srgrimes else if (error == EJUSTRETURN) 3481590Srgrimes (void)printf("JUSTRETURN"); 3491590Srgrimes else { 3501590Srgrimes (void)printf("-1 errno %d", ktr->ktr_error); 3511590Srgrimes if (fancy) 3521590Srgrimes (void)printf(" %s", strerror(ktr->ktr_error)); 3531590Srgrimes } 3541590Srgrimes (void)putchar('\n'); 3551590Srgrimes} 3561590Srgrimes 3578874Srgrimesktrnamei(cp, len) 3581590Srgrimes char *cp; 3591590Srgrimes{ 3601590Srgrimes (void)printf("\"%.*s\"\n", len, cp); 3611590Srgrimes} 3621590Srgrimes 3631590Srgrimesktrgenio(ktr, len) 3641590Srgrimes struct ktr_genio *ktr; 3651590Srgrimes{ 3661590Srgrimes register int datalen = len - sizeof (struct ktr_genio); 3671590Srgrimes register char *dp = (char *)ktr + sizeof (struct ktr_genio); 3681590Srgrimes register char *cp; 3691590Srgrimes register int col = 0; 3701590Srgrimes register width; 3711590Srgrimes char visbuf[5]; 3721590Srgrimes static screenwidth = 0; 3731590Srgrimes 3741590Srgrimes if (screenwidth == 0) { 3751590Srgrimes struct winsize ws; 3761590Srgrimes 3771590Srgrimes if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 && 3781590Srgrimes ws.ws_col > 8) 3791590Srgrimes screenwidth = ws.ws_col; 3801590Srgrimes else 3811590Srgrimes screenwidth = 80; 3821590Srgrimes } 38325995Scharnier printf("fd %d %s %d byte%s\n", ktr->ktr_fd, 38425995Scharnier ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen, 38525995Scharnier datalen == 1 ? "" : "s"); 3861590Srgrimes if (maxdata && datalen > maxdata) 3871590Srgrimes datalen = maxdata; 3881590Srgrimes (void)printf(" \""); 3891590Srgrimes col = 8; 3901590Srgrimes for (;datalen > 0; datalen--, dp++) { 3911590Srgrimes (void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1)); 3921590Srgrimes cp = visbuf; 3931590Srgrimes /* 3941590Srgrimes * Keep track of printables and 3951590Srgrimes * space chars (like fold(1)). 3961590Srgrimes */ 3971590Srgrimes if (col == 0) { 3981590Srgrimes (void)putchar('\t'); 3991590Srgrimes col = 8; 4001590Srgrimes } 4011590Srgrimes switch(*cp) { 4021590Srgrimes case '\n': 4031590Srgrimes col = 0; 4041590Srgrimes (void)putchar('\n'); 4051590Srgrimes continue; 4061590Srgrimes case '\t': 4071590Srgrimes width = 8 - (col&07); 4081590Srgrimes break; 4091590Srgrimes default: 4101590Srgrimes width = strlen(cp); 4111590Srgrimes } 4121590Srgrimes if (col + width > (screenwidth-2)) { 4131590Srgrimes (void)printf("\\\n\t"); 4141590Srgrimes col = 8; 4151590Srgrimes } 4161590Srgrimes col += width; 4171590Srgrimes do { 4181590Srgrimes (void)putchar(*cp++); 4191590Srgrimes } while (*cp); 4201590Srgrimes } 4211590Srgrimes if (col == 0) 4221590Srgrimes (void)printf(" "); 4231590Srgrimes (void)printf("\"\n"); 4241590Srgrimes} 4251590Srgrimes 4261590Srgrimeschar *signames[] = { 4271590Srgrimes "NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", /* 1 - 6 */ 4281590Srgrimes "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", /* 7 - 12 */ 4291590Srgrimes "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", /* 13 - 18 */ 4301590Srgrimes "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", /* 19 - 24 */ 4311590Srgrimes "XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1", /* 25 - 30 */ 4321590Srgrimes "USR2", NULL, /* 31 - 32 */ 4331590Srgrimes}; 4341590Srgrimes 4351590Srgrimesktrpsig(psig) 4361590Srgrimes struct ktr_psig *psig; 4371590Srgrimes{ 4381590Srgrimes (void)printf("SIG%s ", signames[psig->signo]); 4391590Srgrimes if (psig->action == SIG_DFL) 4401590Srgrimes (void)printf("SIG_DFL\n"); 4411590Srgrimes else 44247957Sdt (void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n", 44347957Sdt (u_long)psig->action, psig->mask, psig->code); 4441590Srgrimes} 4451590Srgrimes 4461590Srgrimesktrcsw(cs) 4471590Srgrimes struct ktr_csw *cs; 4481590Srgrimes{ 4491590Srgrimes (void)printf("%s %s\n", cs->out ? "stop" : "resume", 4501590Srgrimes cs->user ? "user" : "kernel"); 4511590Srgrimes} 4521590Srgrimes 45318470Sphkktruser(len, p) 45418470Sphk int len; 45518470Sphk unsigned char *p; 45618400Sphk{ 45718470Sphk (void)printf("%d ", len); 45818470Sphk while (len--) 45918400Sphk (void)printf(" %02x", *p++); 46018400Sphk (void)printf("\n"); 46118400Sphk 46218400Sphk} 46318400Sphk 4641590Srgrimesusage() 4651590Srgrimes{ 4661590Srgrimes (void)fprintf(stderr, 46718400Sphk "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnisuw]]\n"); 4681590Srgrimes exit(1); 4691590Srgrimes} 470