Index: head/usr.bin/kdump/kdump.1 =================================================================== --- head/usr.bin/kdump/kdump.1 (revision 123186) +++ head/usr.bin/kdump/kdump.1 (revision 123187) @@ -1,108 +1,110 @@ .\" Copyright (c) 1990, 1993 .\" The Regents of the University of California. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed by the University of .\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)kdump.1 8.1 (Berkeley) 6/6/93 .\" $FreeBSD$ .\" .Dd June 6, 1993 .Dt KDUMP 1 .Os .Sh NAME .Nm kdump .Nd display kernel trace data .Sh SYNOPSIS .Nm -.Op Fl dnlRT +.Op Fl dnlERT .Op Fl f Ar file .Op Fl m Ar maxdata .Op Fl p Ar pid .Op Fl t Op cnisuw .Sh DESCRIPTION The .Nm command displays the kernel trace files produced with .Xr ktrace 1 in human readable format. By default, the file .Pa ktrace.out in the current directory is displayed. .Pp The options are as follows: .Bl -tag -width Fl .It Fl d Display all numbers in decimal. .It Fl f Ar file Display the specified file instead of .Pa ktrace.out . .It Fl l Loop reading the trace file, once the end-of-file is reached, waiting for more data. .It Fl m Ar maxdata Display at most .Ar maxdata bytes when decoding .Tn I/O . .It Fl n Suppress ad hoc translations. Normally .Nm tries to decode many system calls into a more human readable format. For example, .Xr ioctl 2 values are replaced with the macro name and .Va errno values are replaced with the .Xr strerror 3 string. Suppressing this feature yields a more consistent output format and is easily amenable to further processing. .It Fl p Ar pid Display only trace events that correspond to the process .Ar pid . This may be useful when there are multiple processes recorded in the same trace file. +.It Fl E +Display elapsed timestamps (time since beginning of trace). .It Fl R Display relative timestamps (time since previous entry). .It Fl T Display absolute timestamps for each entry (seconds since epoch). .It Fl t Ar cnisuw See the .Fl t option of .Xr ktrace 1 . .El .Sh SEE ALSO .Xr ktrace 1 .Sh HISTORY The .Nm command appeared in .Bx 4.4 . Index: head/usr.bin/kdump/kdump.c =================================================================== --- head/usr.bin/kdump/kdump.c (revision 123186) +++ head/usr.bin/kdump/kdump.c (revision 123187) @@ -1,571 +1,579 @@ /*- * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1988, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)kdump.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #define _KERNEL extern int errno; #include #undef _KERNEL #include #include #define _KERNEL #include #undef _KERNEL #include #include #include #include #include #include #include #include #include #include #include #include "ktrace.h" int fread_tail(void *, int, int); void dumpheader(struct ktr_header *); void ktrsyscall(struct ktr_syscall *); void ktrsysret(struct ktr_sysret *); void ktrnamei(char *, int); void hexdump(char *, int, int); void visdump(char *, int, int); void ktrgenio(struct ktr_genio *, int); void ktrpsig(struct ktr_psig *); void ktrcsw(struct ktr_csw *); void ktruser(int, unsigned char *); void usage(void); int timestamp, decimal, fancy = 1, tail, maxdata; const char *tracefile = DEF_TRACEFILE; struct ktr_header ktr_header; #define eqs(s1, s2) (strcmp((s1), (s2)) == 0) int main(int argc, char *argv[]) { int ch, ktrlen, size; void *m; int trpoints = ALL_POINTS; int drop_logged; pid_t pid = 0; (void) setlocale(LC_CTYPE, ""); - while ((ch = getopt(argc,argv,"f:dlm:np:RTt:")) != -1) + while ((ch = getopt(argc,argv,"f:dlm:np:ERTt:")) != -1) switch((char)ch) { case 'f': tracefile = optarg; break; case 'd': decimal = 1; break; case 'l': tail = 1; break; case 'm': maxdata = atoi(optarg); break; case 'n': fancy = 0; break; case 'p': pid = atoi(optarg); break; + case 'E': + timestamp = 3; /* elapsed timestamp */ + break; case 'R': timestamp = 2; /* relative timestamp */ break; case 'T': timestamp = 1; break; case 't': trpoints = getpoints(optarg); if (trpoints < 0) errx(1, "unknown trace point in %s", optarg); break; default: usage(); } if (argc > optind) usage(); m = (void *)malloc(size = 1025); if (m == NULL) errx(1, "%s", strerror(ENOMEM)); if (!freopen(tracefile, "r", stdin)) err(1, "%s", tracefile); drop_logged = 0; while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) { if (ktr_header.ktr_type & KTR_DROP) { ktr_header.ktr_type &= ~KTR_DROP; if (!drop_logged) { (void)printf("%6d %-8.*s Events dropped.\n", ktr_header.ktr_pid, MAXCOMLEN, ktr_header.ktr_comm); drop_logged = 1; } } if (trpoints & (1< size) { m = (void *)realloc(m, ktrlen+1); if (m == NULL) errx(1, "%s", strerror(ENOMEM)); size = ktrlen; } if (ktrlen && fread_tail(m, ktrlen, 1) == 0) errx(1, "data too short"); if (pid && ktr_header.ktr_pid != pid) continue; if ((trpoints & (1<ktr_type) { case KTR_SYSCALL: type = "CALL"; break; case KTR_SYSRET: type = "RET "; break; case KTR_NAMEI: type = "NAMI"; break; case KTR_GENIO: type = "GIO "; break; case KTR_PSIG: type = "PSIG"; break; case KTR_CSW: type = "CSW"; break; case KTR_USER: type = "USER"; break; default: (void)sprintf(unknown, "UNKNOWN(%d)", kth->ktr_type); type = unknown; } (void)printf("%6d %-8.*s ", kth->ktr_pid, MAXCOMLEN, kth->ktr_comm); if (timestamp) { + if (timestamp == 3) { + if (prevtime.tv_sec == 0) + prevtime = kth->ktr_time; + timevalsub(&kth->ktr_time, &prevtime); + } if (timestamp == 2) { temp = kth->ktr_time; timevalsub(&kth->ktr_time, &prevtime); prevtime = temp; } (void)printf("%ld.%06ld ", kth->ktr_time.tv_sec, kth->ktr_time.tv_usec); } (void)printf("%s ", type); } #include #define KTRACE #include #undef KTRACE int nsyscalls = sizeof (syscallnames) / sizeof (syscallnames[0]); static const char *ptrace_ops[] = { "PT_TRACE_ME", "PT_READ_I", "PT_READ_D", "PT_READ_U", "PT_WRITE_I", "PT_WRITE_D", "PT_WRITE_U", "PT_CONTINUE", "PT_KILL", "PT_STEP", "PT_ATTACH", "PT_DETACH", }; void ktrsyscall(struct ktr_syscall *ktr) { int narg = ktr->ktr_narg; register_t *ip; const char *ioctlname(u_long); if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0) (void)printf("[%d]", ktr->ktr_code); else (void)printf("%s", syscallnames[ktr->ktr_code]); ip = &ktr->ktr_args[0]; if (narg) { char c = '('; if (fancy) { if (ktr->ktr_code == SYS_ioctl) { const char *cp; if (decimal) (void)printf("(%ld", (long)*ip); else (void)printf("(%#lx", (long)*ip); ip++; narg--; if ((cp = ioctlname(*ip)) != NULL) (void)printf(",%s", cp); else { if (decimal) (void)printf(",%ld", (long)*ip); else (void)printf(",%#lx ", (long)*ip); } c = ','; ip++; narg--; } else if (ktr->ktr_code == SYS_ptrace) { if ((size_t)*ip < sizeof(ptrace_ops) / sizeof(ptrace_ops[0]) && *ip >= 0) (void)printf("(%s", ptrace_ops[*ip]); #ifdef PT_GETREGS else if (*ip == PT_GETREGS) (void)printf("(%s", "PT_GETREGS"); #endif #ifdef PT_SETREGS else if (*ip == PT_SETREGS) (void)printf("(%s", "PT_SETREGS"); #endif #ifdef PT_GETFPREGS else if (*ip == PT_GETFPREGS) (void)printf("(%s", "PT_GETFPREGS"); #endif #ifdef PT_SETFPREGS else if (*ip == PT_SETFPREGS) (void)printf("(%s", "PT_SETFPREGS"); #endif #ifdef PT_GETDBREGS else if (*ip == PT_GETDBREGS) (void)printf("(%s", "PT_GETDBREGS"); #endif #ifdef PT_SETDBREGS else if (*ip == PT_SETDBREGS) (void)printf("(%s", "PT_SETDBREGS"); #endif else (void)printf("(%ld", (long)*ip); c = ','; ip++; narg--; } } while (narg) { if (decimal) (void)printf("%c%ld", c, (long)*ip); else (void)printf("%c%#lx", c, (long)*ip); c = ','; ip++; narg--; } (void)putchar(')'); } (void)putchar('\n'); } void ktrsysret(struct ktr_sysret *ktr) { register_t ret = ktr->ktr_retval; int error = ktr->ktr_error; int code = ktr->ktr_code; if (code >= nsyscalls || code < 0) (void)printf("[%d] ", code); else (void)printf("%s ", syscallnames[code]); if (error == 0) { if (fancy) { (void)printf("%d", ret); if (ret < 0 || ret > 9) (void)printf("/%#lx", (long)ret); } else { if (decimal) (void)printf("%ld", (long)ret); else (void)printf("%#lx", (long)ret); } } else if (error == ERESTART) (void)printf("RESTART"); else if (error == EJUSTRETURN) (void)printf("JUSTRETURN"); else { (void)printf("-1 errno %d", ktr->ktr_error); if (fancy) (void)printf(" %s", strerror(ktr->ktr_error)); } (void)putchar('\n'); } void ktrnamei(char *cp, int len) { (void)printf("\"%.*s\"\n", len, cp); } void hexdump(char *p, int len, int screenwidth) { int n, i; int width; width = 0; do { width += 2; i = 13; /* base offset */ i += (width / 2) + 1; /* spaces every second byte */ i += (width * 2); /* width of bytes */ i += 3; /* " |" */ i += width; /* each byte */ i += 1; /* "|" */ } while (i < screenwidth); width -= 2; for (n = 0; n < len; n += width) { for (i = n; i < n + width; i++) { if ((i % width) == 0) { /* beginning of line */ printf(" 0x%04x", i); } if ((i % 2) == 0) { printf(" "); } if (i < len) printf("%02x", p[i] & 0xff); else printf(" "); } printf(" |"); for (i = n; i < n + width; i++) { if (i >= len) break; if (p[i] >= ' ' && p[i] <= '~') printf("%c", p[i]); else printf("."); } printf("|\n"); } if ((i % width) != 0) printf("\n"); } void visdump(char *dp, int datalen, int screenwidth) { int col = 0; char *cp; int width; char visbuf[5]; (void)printf(" \""); col = 8; for (;datalen > 0; datalen--, dp++) { (void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1)); cp = visbuf; /* * Keep track of printables and * space chars (like fold(1)). */ if (col == 0) { (void)putchar('\t'); col = 8; } switch(*cp) { case '\n': col = 0; (void)putchar('\n'); continue; case '\t': width = 8 - (col&07); break; default: width = strlen(cp); } if (col + width > (screenwidth-2)) { (void)printf("\\\n\t"); col = 8; } col += width; do { (void)putchar(*cp++); } while (*cp); } if (col == 0) (void)printf(" "); (void)printf("\"\n"); } void ktrgenio(struct ktr_genio *ktr, int len) { int datalen = len - sizeof (struct ktr_genio); char *dp = (char *)ktr + sizeof (struct ktr_genio); static int screenwidth = 0; int i, binary; if (screenwidth == 0) { struct winsize ws; if (fancy && ioctl(fileno(stderr), TIOCGWINSZ, &ws) != -1 && ws.ws_col > 8) screenwidth = ws.ws_col; else screenwidth = 80; } printf("fd %d %s %d byte%s\n", ktr->ktr_fd, ktr->ktr_rw == UIO_READ ? "read" : "wrote", datalen, datalen == 1 ? "" : "s"); if (maxdata && datalen > maxdata) datalen = maxdata; for (i = 0, binary = 0; i < datalen && binary == 0; i++) { if (dp[i] >= 32 && dp[i] < 127) continue; if (dp[i] == 10 || dp[i] == 13 || dp[i] == 0 || dp[i] == 9) continue; binary = 1; } if (binary) hexdump(dp, datalen, screenwidth); else visdump(dp, datalen, screenwidth); } const char *signames[] = { "NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", /* 1 - 6 */ "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", /* 7 - 12 */ "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", /* 13 - 18 */ "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", /* 19 - 24 */ "XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1", /* 25 - 30 */ "USR2", NULL, /* 31 - 32 */ }; void ktrpsig(struct ktr_psig *psig) { (void)printf("SIG%s ", signames[psig->signo]); if (psig->action == SIG_DFL) (void)printf("SIG_DFL\n"); else { (void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n", (u_long)psig->action, psig->mask.__bits[0], psig->code); } } void ktrcsw(struct ktr_csw *cs) { (void)printf("%s %s\n", cs->out ? "stop" : "resume", cs->user ? "user" : "kernel"); } void ktruser(int len, unsigned char *p) { (void)printf("%d ", len); while (len--) (void)printf(" %02x", *p++); (void)printf("\n"); } void usage(void) { (void)fprintf(stderr, "usage: kdump [-dnlRT] [-f trfile] [-m maxdata] [-t [cnisuw]]\n"); exit(1); }