kdump.c revision 11823
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 351590Srgrimesstatic 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 411590Srgrimesstatic char sccsid[] = "@(#)kdump.c 8.1 (Berkeley) 6/6/93"; 421590Srgrimes#endif /* not lint */ 431590Srgrimes 442215Scsgr#define KERNEL 452215Scsgrextern int errno; 462215Scsgr#include <sys/errno.h> 472215Scsgr#undef KERNEL 481590Srgrimes#include <sys/param.h> 491590Srgrimes#include <sys/errno.h> 501590Srgrimes#include <sys/time.h> 511590Srgrimes#include <sys/uio.h> 521590Srgrimes#include <sys/ktrace.h> 531590Srgrimes#include <sys/ioctl.h> 541590Srgrimes#include <sys/ptrace.h> 551590Srgrimes#include <vis.h> 561590Srgrimes#include <stdio.h> 571590Srgrimes#include <stdlib.h> 581590Srgrimes#include <string.h> 5911823Sache#include <locale.h> 601590Srgrimes#include "ktrace.h" 611590Srgrimes 621590Srgrimesint timestamp, decimal, fancy = 1, tail, maxdata; 631590Srgrimeschar *tracefile = DEF_TRACEFILE; 641590Srgrimesstruct ktr_header ktr_header; 651590Srgrimes 661590Srgrimes#define eqs(s1, s2) (strcmp((s1), (s2)) == 0) 671590Srgrimes 681590Srgrimesmain(argc, argv) 691590Srgrimes int argc; 701590Srgrimes char *argv[]; 711590Srgrimes{ 721590Srgrimes extern int optind; 731590Srgrimes extern char *optarg; 741590Srgrimes int ch, ktrlen, size; 751590Srgrimes register void *m; 761590Srgrimes int trpoints = ALL_POINTS; 771590Srgrimes 7811823Sache (void) setlocale(LC_CTYPE, ""); 7911823Sache 801590Srgrimes while ((ch = getopt(argc,argv,"f:dlm:nRTt:")) != EOF) 811590Srgrimes switch((char)ch) { 821590Srgrimes case 'f': 831590Srgrimes tracefile = optarg; 841590Srgrimes break; 851590Srgrimes case 'd': 861590Srgrimes decimal = 1; 871590Srgrimes break; 881590Srgrimes case 'l': 891590Srgrimes tail = 1; 901590Srgrimes break; 911590Srgrimes case 'm': 921590Srgrimes maxdata = atoi(optarg); 931590Srgrimes break; 941590Srgrimes case 'n': 951590Srgrimes fancy = 0; 961590Srgrimes break; 971590Srgrimes case 'R': 981590Srgrimes timestamp = 2; /* relative timestamp */ 991590Srgrimes break; 1001590Srgrimes case 'T': 1011590Srgrimes timestamp = 1; 1021590Srgrimes break; 1031590Srgrimes case 't': 1041590Srgrimes trpoints = getpoints(optarg); 1051590Srgrimes if (trpoints < 0) { 1061590Srgrimes (void)fprintf(stderr, 1071590Srgrimes "kdump: unknown trace point in %s\n", 1081590Srgrimes optarg); 1091590Srgrimes exit(1); 1101590Srgrimes } 1111590Srgrimes break; 1121590Srgrimes default: 1131590Srgrimes usage(); 1141590Srgrimes } 1151590Srgrimes argv += optind; 1161590Srgrimes argc -= optind; 1171590Srgrimes 1181590Srgrimes if (argc > 1) 1191590Srgrimes usage(); 1201590Srgrimes 1211590Srgrimes m = (void *)malloc(size = 1025); 1221590Srgrimes if (m == NULL) { 1231590Srgrimes (void)fprintf(stderr, "kdump: %s.\n", strerror(ENOMEM)); 1241590Srgrimes exit(1); 1251590Srgrimes } 1261590Srgrimes if (!freopen(tracefile, "r", stdin)) { 1271590Srgrimes (void)fprintf(stderr, 1281590Srgrimes "kdump: %s: %s.\n", tracefile, strerror(errno)); 1291590Srgrimes exit(1); 1301590Srgrimes } 1311590Srgrimes while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) { 1321590Srgrimes if (trpoints & (1<<ktr_header.ktr_type)) 1331590Srgrimes dumpheader(&ktr_header); 1341590Srgrimes if ((ktrlen = ktr_header.ktr_len) < 0) { 1351590Srgrimes (void)fprintf(stderr, 1361590Srgrimes "kdump: bogus length 0x%x\n", ktrlen); 1371590Srgrimes exit(1); 1381590Srgrimes } 1391590Srgrimes if (ktrlen > size) { 1401590Srgrimes m = (void *)realloc(m, ktrlen+1); 1411590Srgrimes if (m == NULL) { 1421590Srgrimes (void)fprintf(stderr, 1431590Srgrimes "kdump: %s.\n", strerror(ENOMEM)); 1441590Srgrimes exit(1); 1451590Srgrimes } 1461590Srgrimes size = ktrlen; 1471590Srgrimes } 1481590Srgrimes if (ktrlen && fread_tail(m, ktrlen, 1) == 0) { 1491590Srgrimes (void)fprintf(stderr, "kdump: data too short.\n"); 1501590Srgrimes exit(1); 1511590Srgrimes } 1521590Srgrimes if ((trpoints & (1<<ktr_header.ktr_type)) == 0) 1531590Srgrimes continue; 1541590Srgrimes switch (ktr_header.ktr_type) { 1551590Srgrimes case KTR_SYSCALL: 1561590Srgrimes ktrsyscall((struct ktr_syscall *)m); 1571590Srgrimes break; 1581590Srgrimes case KTR_SYSRET: 1591590Srgrimes ktrsysret((struct ktr_sysret *)m); 1601590Srgrimes break; 1611590Srgrimes case KTR_NAMEI: 1621590Srgrimes ktrnamei(m, ktrlen); 1631590Srgrimes break; 1641590Srgrimes case KTR_GENIO: 1651590Srgrimes ktrgenio((struct ktr_genio *)m, ktrlen); 1661590Srgrimes break; 1671590Srgrimes case KTR_PSIG: 1681590Srgrimes ktrpsig((struct ktr_psig *)m); 1691590Srgrimes break; 1701590Srgrimes case KTR_CSW: 1711590Srgrimes ktrcsw((struct ktr_csw *)m); 1721590Srgrimes break; 1731590Srgrimes } 1741590Srgrimes if (tail) 1751590Srgrimes (void)fflush(stdout); 1761590Srgrimes } 1771590Srgrimes} 1781590Srgrimes 1791590Srgrimesfread_tail(buf, size, num) 1801590Srgrimes char *buf; 1811590Srgrimes int num, size; 1821590Srgrimes{ 1831590Srgrimes int i; 1841590Srgrimes 1851590Srgrimes while ((i = fread(buf, size, num, stdin)) == 0 && tail) { 1861590Srgrimes (void)sleep(1); 1871590Srgrimes clearerr(stdin); 1881590Srgrimes } 1891590Srgrimes return (i); 1901590Srgrimes} 1911590Srgrimes 1921590Srgrimesdumpheader(kth) 1931590Srgrimes struct ktr_header *kth; 1941590Srgrimes{ 1951590Srgrimes static char unknown[64]; 1961590Srgrimes static struct timeval prevtime, temp; 1971590Srgrimes char *type; 1981590Srgrimes 1991590Srgrimes switch (kth->ktr_type) { 2001590Srgrimes case KTR_SYSCALL: 2011590Srgrimes type = "CALL"; 2021590Srgrimes break; 2031590Srgrimes case KTR_SYSRET: 2041590Srgrimes type = "RET "; 2051590Srgrimes break; 2061590Srgrimes case KTR_NAMEI: 2071590Srgrimes type = "NAMI"; 2081590Srgrimes break; 2091590Srgrimes case KTR_GENIO: 2101590Srgrimes type = "GIO "; 2111590Srgrimes break; 2121590Srgrimes case KTR_PSIG: 2131590Srgrimes type = "PSIG"; 2141590Srgrimes break; 2151590Srgrimes case KTR_CSW: 2161590Srgrimes type = "CSW"; 2171590Srgrimes break; 2181590Srgrimes default: 2191590Srgrimes (void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type); 2201590Srgrimes type = unknown; 2211590Srgrimes } 2221590Srgrimes 2231590Srgrimes (void)printf("%6d %-8s ", kth->ktr_pid, kth->ktr_comm); 2241590Srgrimes if (timestamp) { 2251590Srgrimes if (timestamp == 2) { 2261590Srgrimes temp = kth->ktr_time; 2271590Srgrimes timevalsub(&kth->ktr_time, &prevtime); 2281590Srgrimes prevtime = temp; 2291590Srgrimes } 2301590Srgrimes (void)printf("%ld.%06ld ", 2311590Srgrimes kth->ktr_time.tv_sec, kth->ktr_time.tv_usec); 2321590Srgrimes } 2331590Srgrimes (void)printf("%s ", type); 2341590Srgrimes} 2351590Srgrimes 2361590Srgrimes#include <sys/syscall.h> 2371590Srgrimes#define KTRACE 2384721Sphk#include <sys/kern/syscalls.c> 2391590Srgrimes#undef KTRACE 2401590Srgrimesint nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]); 2411590Srgrimes 2421590Srgrimesstatic char *ptrace_ops[] = { 2431590Srgrimes "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U", 2441590Srgrimes "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE", 2451590Srgrimes "PT_KILL", "PT_STEP", 2461590Srgrimes}; 2471590Srgrimes 2481590Srgrimesktrsyscall(ktr) 2491590Srgrimes register struct ktr_syscall *ktr; 2501590Srgrimes{ 2511590Srgrimes register narg = ktr->ktr_narg; 2521590Srgrimes register int *ip; 2531590Srgrimes char *ioctlname(); 2541590Srgrimes 2551590Srgrimes if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0) 2561590Srgrimes (void)printf("[%d]", ktr->ktr_code); 2571590Srgrimes else 2581590Srgrimes (void)printf("%s", syscallnames[ktr->ktr_code]); 2591590Srgrimes ip = (int *)((char *)ktr + sizeof(struct ktr_syscall)); 2601590Srgrimes if (narg) { 2611590Srgrimes char c = '('; 2621590Srgrimes if (fancy) { 2631590Srgrimes if (ktr->ktr_code == SYS_ioctl) { 2641590Srgrimes char *cp; 2651590Srgrimes if (decimal) 2661590Srgrimes (void)printf("(%d", *ip); 2671590Srgrimes else 2681590Srgrimes (void)printf("(%#x", *ip); 2691590Srgrimes ip++; 2701590Srgrimes narg--; 2711590Srgrimes if ((cp = ioctlname(*ip)) != NULL) 2721590Srgrimes (void)printf(",%s", cp); 2731590Srgrimes else { 2741590Srgrimes if (decimal) 2751590Srgrimes (void)printf(",%d", *ip); 2761590Srgrimes else 2771590Srgrimes (void)printf(",%#x ", *ip); 2781590Srgrimes } 2791590Srgrimes c = ','; 2801590Srgrimes ip++; 2811590Srgrimes narg--; 2821590Srgrimes } else if (ktr->ktr_code == SYS_ptrace) { 2831590Srgrimes if (*ip <= PT_STEP && *ip >= 0) 2841590Srgrimes (void)printf("(%s", ptrace_ops[*ip]); 2851590Srgrimes else 2861590Srgrimes (void)printf("(%d", *ip); 2871590Srgrimes c = ','; 2881590Srgrimes ip++; 2891590Srgrimes narg--; 2901590Srgrimes } 2911590Srgrimes } 2921590Srgrimes while (narg) { 2931590Srgrimes if (decimal) 2941590Srgrimes (void)printf("%c%d", c, *ip); 2951590Srgrimes else 2961590Srgrimes (void)printf("%c%#x", c, *ip); 2971590Srgrimes c = ','; 2981590Srgrimes ip++; 2991590Srgrimes narg--; 3001590Srgrimes } 3011590Srgrimes (void)putchar(')'); 3021590Srgrimes } 3031590Srgrimes (void)putchar('\n'); 3041590Srgrimes} 3051590Srgrimes 3061590Srgrimesktrsysret(ktr) 3071590Srgrimes struct ktr_sysret *ktr; 3081590Srgrimes{ 3091590Srgrimes register int ret = ktr->ktr_retval; 3101590Srgrimes register int error = ktr->ktr_error; 3111590Srgrimes register int code = ktr->ktr_code; 3121590Srgrimes 3131590Srgrimes if (code >= nsyscalls || code < 0) 3141590Srgrimes (void)printf("[%d] ", code); 3151590Srgrimes else 3161590Srgrimes (void)printf("%s ", syscallnames[code]); 3171590Srgrimes 3181590Srgrimes if (error == 0) { 3191590Srgrimes if (fancy) { 3201590Srgrimes (void)printf("%d", ret); 3211590Srgrimes if (ret < 0 || ret > 9) 3221590Srgrimes (void)printf("/%#x", ret); 3231590Srgrimes } else { 3241590Srgrimes if (decimal) 3251590Srgrimes (void)printf("%d", ret); 3261590Srgrimes else 3271590Srgrimes (void)printf("%#x", ret); 3281590Srgrimes } 3291590Srgrimes } else if (error == ERESTART) 3301590Srgrimes (void)printf("RESTART"); 3311590Srgrimes else if (error == EJUSTRETURN) 3321590Srgrimes (void)printf("JUSTRETURN"); 3331590Srgrimes else { 3341590Srgrimes (void)printf("-1 errno %d", ktr->ktr_error); 3351590Srgrimes if (fancy) 3361590Srgrimes (void)printf(" %s", strerror(ktr->ktr_error)); 3371590Srgrimes } 3381590Srgrimes (void)putchar('\n'); 3391590Srgrimes} 3401590Srgrimes 3418874Srgrimesktrnamei(cp, len) 3421590Srgrimes char *cp; 3431590Srgrimes{ 3441590Srgrimes (void)printf("\"%.*s\"\n", len, cp); 3451590Srgrimes} 3461590Srgrimes 3471590Srgrimesktrgenio(ktr, len) 3481590Srgrimes struct ktr_genio *ktr; 3491590Srgrimes{ 3501590Srgrimes register int datalen = len - sizeof (struct ktr_genio); 3511590Srgrimes register char *dp = (char *)ktr + sizeof (struct ktr_genio); 3521590Srgrimes register char *cp; 3531590Srgrimes register int col = 0; 3541590Srgrimes register width; 3551590Srgrimes char visbuf[5]; 3561590Srgrimes static screenwidth = 0; 3571590Srgrimes 3581590Srgrimes if (screenwidth == 0) { 3591590Srgrimes struct winsize ws; 3601590Srgrimes 3611590Srgrimes if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 && 3621590Srgrimes ws.ws_col > 8) 3631590Srgrimes screenwidth = ws.ws_col; 3641590Srgrimes else 3651590Srgrimes screenwidth = 80; 3661590Srgrimes } 3671590Srgrimes printf("fd %d %s %d bytes\n", ktr->ktr_fd, 3681590Srgrimes ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen); 3691590Srgrimes if (maxdata && datalen > maxdata) 3701590Srgrimes datalen = maxdata; 3711590Srgrimes (void)printf(" \""); 3721590Srgrimes col = 8; 3731590Srgrimes for (;datalen > 0; datalen--, dp++) { 3741590Srgrimes (void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1)); 3751590Srgrimes cp = visbuf; 3761590Srgrimes /* 3771590Srgrimes * Keep track of printables and 3781590Srgrimes * space chars (like fold(1)). 3791590Srgrimes */ 3801590Srgrimes if (col == 0) { 3811590Srgrimes (void)putchar('\t'); 3821590Srgrimes col = 8; 3831590Srgrimes } 3841590Srgrimes switch(*cp) { 3851590Srgrimes case '\n': 3861590Srgrimes col = 0; 3871590Srgrimes (void)putchar('\n'); 3881590Srgrimes continue; 3891590Srgrimes case '\t': 3901590Srgrimes width = 8 - (col&07); 3911590Srgrimes break; 3921590Srgrimes default: 3931590Srgrimes width = strlen(cp); 3941590Srgrimes } 3951590Srgrimes if (col + width > (screenwidth-2)) { 3961590Srgrimes (void)printf("\\\n\t"); 3971590Srgrimes col = 8; 3981590Srgrimes } 3991590Srgrimes col += width; 4001590Srgrimes do { 4011590Srgrimes (void)putchar(*cp++); 4021590Srgrimes } while (*cp); 4031590Srgrimes } 4041590Srgrimes if (col == 0) 4051590Srgrimes (void)printf(" "); 4061590Srgrimes (void)printf("\"\n"); 4071590Srgrimes} 4081590Srgrimes 4091590Srgrimeschar *signames[] = { 4101590Srgrimes "NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", /* 1 - 6 */ 4111590Srgrimes "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", /* 7 - 12 */ 4121590Srgrimes "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", /* 13 - 18 */ 4131590Srgrimes "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", /* 19 - 24 */ 4141590Srgrimes "XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1", /* 25 - 30 */ 4151590Srgrimes "USR2", NULL, /* 31 - 32 */ 4161590Srgrimes}; 4171590Srgrimes 4181590Srgrimesktrpsig(psig) 4191590Srgrimes struct ktr_psig *psig; 4201590Srgrimes{ 4211590Srgrimes (void)printf("SIG%s ", signames[psig->signo]); 4221590Srgrimes if (psig->action == SIG_DFL) 4231590Srgrimes (void)printf("SIG_DFL\n"); 4241590Srgrimes else 4251590Srgrimes (void)printf("caught handler=0x%x mask=0x%x code=0x%x\n", 4261590Srgrimes (u_int)psig->action, psig->mask, psig->code); 4271590Srgrimes} 4281590Srgrimes 4291590Srgrimesktrcsw(cs) 4301590Srgrimes struct ktr_csw *cs; 4311590Srgrimes{ 4321590Srgrimes (void)printf("%s %s\n", cs->out ? "stop" : "resume", 4331590Srgrimes cs->user ? "user" : "kernel"); 4341590Srgrimes} 4351590Srgrimes 4361590Srgrimesusage() 4371590Srgrimes{ 4381590Srgrimes (void)fprintf(stderr, 4391590Srgrimes "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnis]]\n"); 4401590Srgrimes exit(1); 4411590Srgrimes} 442