ktrdump.c revision 93617
193504Sjake/*- 293504Sjake * Copyright (c) 2002 Jake Burkholder 393504Sjake * All rights reserved. 493504Sjake * 593504Sjake * Redistribution and use in source and binary forms, with or without 693504Sjake * modification, are permitted provided that the following conditions 793504Sjake * are met: 893504Sjake * 1. Redistributions of source code must retain the above copyright 993504Sjake * notice, this list of conditions and the following disclaimer. 1093504Sjake * 2. Redistributions in binary form must reproduce the above copyright 1193504Sjake * notice, this list of conditions and the following disclaimer in the 1293504Sjake * documentation and/or other materials provided with the distribution. 1393504Sjake * 1493504Sjake * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1593504Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1693504Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1793504Sjake * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1893504Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1993504Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2093504Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2193504Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2293504Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2393504Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2493504Sjake * SUCH DAMAGE. 2593504Sjake */ 2693504Sjake 2793504Sjake#include <sys/cdefs.h> 2893504Sjake__FBSDID("$FreeBSD: head/usr.bin/ktrdump/ktrdump.c 93617 2002-04-02 04:24:59Z jake $"); 2993504Sjake 3093504Sjake#include <sys/types.h> 3193504Sjake#include <sys/ktr.h> 3293504Sjake 3393504Sjake#include <err.h> 3493504Sjake#include <fcntl.h> 3593504Sjake#include <kvm.h> 3693504Sjake#include <limits.h> 3793504Sjake#include <nlist.h> 3893617Sjake#include <stdint.h> 3993504Sjake#include <stdio.h> 4093504Sjake#include <stdlib.h> 4193504Sjake#include <string.h> 4293504Sjake#include <unistd.h> 4393504Sjake 4493504Sjake#define SBUFLEN 128 4593504Sjake#define USAGE \ 4693504Sjake "usage: ktrdump [-c] [-f] [-t] [-e execfile] [-m corefile] [-o outfile]" 4793504Sjake 4893504Sjakeextern char *optarg; 4993504Sjakeextern int optind; 5093504Sjake 5193504Sjakestatic void usage(void); 5293504Sjake 5393504Sjakestatic struct nlist nl[] = { 5493504Sjake { "_ktr_version" }, 5593504Sjake { "_ktr_entries" }, 5693504Sjake { "_ktr_idx" }, 5793504Sjake { "_ktr_buf" }, 5893504Sjake { NULL } 5993504Sjake}; 6093504Sjake 6193504Sjakestatic int cflag; 6293504Sjakestatic int eflag; 6393504Sjakestatic int fflag; 6493504Sjakestatic int mflag; 6593504Sjakestatic int tflag; 6693504Sjake 6793504Sjakestatic char corefile[PATH_MAX]; 6893504Sjakestatic char execfile[PATH_MAX]; 6993504Sjake 7093504Sjakestatic char desc[SBUFLEN]; 7193504Sjakestatic char errbuf[_POSIX2_LINE_MAX]; 7293504Sjakestatic char fbuf[PATH_MAX]; 7393504Sjakestatic char obuf[PATH_MAX]; 7493504Sjakestatic char sbuf[KTR_PARMS][SBUFLEN]; 7593504Sjake 7693504Sjake/* 7793504Sjake * Reads the ktr trace buffer from kernel memory and prints the trace entries. 7893504Sjake */ 7993504Sjakeint 8093504Sjakemain(int ac, char **av) 8193504Sjake{ 8293504Sjake u_long parms[KTR_PARMS]; 8393504Sjake struct ktr_entry *buf; 8493504Sjake kvm_t *kd; 8593504Sjake FILE *out; 8693504Sjake char *p; 8793504Sjake int version; 8893504Sjake int entries; 8993504Sjake int index; 9093504Sjake int parm; 9193504Sjake int c; 9293504Sjake int i; 9393504Sjake int n; 9493504Sjake 9593504Sjake /* 9693504Sjake * Parse commandline arguments. 9793504Sjake */ 9893504Sjake out = stdout; 9993504Sjake while ((c = getopt(ac, av, "cfte:m:o:")) != -1) 10093504Sjake switch (c) { 10193504Sjake case 'c': 10293504Sjake cflag = 1; 10393504Sjake break; 10493504Sjake case 'e': 10593617Sjake strcpy(execfile, optarg); 10693504Sjake eflag = 1; 10793504Sjake break; 10893504Sjake case 'f': 10993504Sjake fflag = 1; 11093504Sjake break; 11193504Sjake case 'm': 11293617Sjake strcpy(corefile, optarg); 11393504Sjake mflag = 1; 11493504Sjake break; 11593504Sjake case 'o': 11693504Sjake if ((out = fopen(optarg, "w")) == NULL) 11793504Sjake err(1, "%s", optarg); 11893504Sjake break; 11993504Sjake case 't': 12093504Sjake tflag = 1; 12193504Sjake break; 12293504Sjake case '?': 12393504Sjake default: 12493504Sjake usage(); 12593504Sjake } 12693504Sjake ac -= optind; 12793504Sjake av += optind; 12893504Sjake if (ac != 0) 12993504Sjake usage(); 13093504Sjake 13193504Sjake /* 13293504Sjake * Open our execfile and corefile, resolve needed symbols and read in 13393504Sjake * the trace buffer. 13493504Sjake */ 13593504Sjake if ((kd = kvm_openfiles(eflag ? execfile : NULL, 13693504Sjake mflag ? corefile : NULL, NULL, O_RDONLY, errbuf)) == NULL) 13793504Sjake errx(1, "%s", errbuf); 13893504Sjake if (kvm_nlist(kd, nl) != 0 || 13993504Sjake kvm_read(kd, nl[0].n_value, &version, sizeof(version)) == -1) 14093504Sjake errx(1, "%s", kvm_geterr(kd)); 14193504Sjake if (version != KTR_VERSION) 14293504Sjake errx(1, "ktr version mismatch"); 14393504Sjake if (kvm_read(kd, nl[1].n_value, &entries, sizeof(entries)) == -1) 14493504Sjake errx(1, "%s", kvm_geterr(kd)); 14593504Sjake if ((buf = malloc(sizeof(*buf) * entries)) == NULL) 14693504Sjake err(1, NULL); 14793504Sjake if (kvm_read(kd, nl[2].n_value, &index, sizeof(index)) == -1 || 14893504Sjake kvm_read(kd, nl[3].n_value, buf, sizeof(*buf) * entries) == -1) 14993504Sjake errx(1, "%s", kvm_geterr(kd)); 15093504Sjake 15193504Sjake /* 15293504Sjake * Print a nice header. 15393504Sjake */ 15493504Sjake fprintf(out, "%-6s ", "index"); 15593504Sjake if (cflag) 15693504Sjake fprintf(out, "%-3s ", "cpu"); 15793504Sjake if (tflag) 15893504Sjake fprintf(out, "%-16s ", "timestamp"); 15993504Sjake if (fflag) 16093504Sjake fprintf(out, "%-32s ", "file and line"); 16193504Sjake fprintf(out, "%s", "trace"); 16293504Sjake fprintf(out, "\n"); 16393504Sjake 16493504Sjake fprintf(out, "------ "); 16593504Sjake if (cflag) 16693504Sjake fprintf(out, "--- "); 16793504Sjake if (tflag) 16893504Sjake fprintf(out, "---------------- "); 16993504Sjake if (fflag) 17093504Sjake fprintf(out, "---------------------------------------- "); 17193504Sjake fprintf(out, "----- "); 17293504Sjake fprintf(out, "\n"); 17393504Sjake 17493504Sjake /* 17593504Sjake * Now tear through the trace buffer. 17693504Sjake */ 17793504Sjake i = (index - 1) & (entries - 1); 17893504Sjake for (;;) { 17993504Sjake if (buf[i].ktr_desc == NULL) 18093504Sjake break; 18193504Sjake if (kvm_read(kd, (u_long)buf[i].ktr_desc, desc, 18293504Sjake sizeof(desc)) == -1) 18393504Sjake errx(1, "%s", kvm_geterr(kd)); 18493504Sjake desc[sizeof(desc) - 1] = '\0'; 18593504Sjake parm = 0; 18693504Sjake for (p = desc; (c = *p++) != '\0';) { 18793504Sjake if (c != '%') 18893504Sjake continue; 18993504Sjake if ((c = *p++) == '\0') 19093504Sjake break; 19193504Sjake if (parm == KTR_PARMS) 19293504Sjake errx(1, "too many parameters"); 19393504Sjake switch (c) { 19493504Sjake case 's': 19593504Sjake if (kvm_read(kd, (u_long)buf[i].ktr_parms[parm], 19693504Sjake sbuf[parm], sizeof(sbuf[parm])) == -1) 19793504Sjake strcpy(sbuf[parm], "(null)"); 19893504Sjake sbuf[parm][sizeof(sbuf[0]) - 1] = '\0'; 19993504Sjake parms[parm] = (u_long)sbuf[parm]; 20093504Sjake parm++; 20193504Sjake break; 20293504Sjake default: 20393504Sjake parms[parm] = buf[i].ktr_parms[parm]; 20493504Sjake parm++; 20593504Sjake break; 20693504Sjake } 20793504Sjake } 20893504Sjake fprintf(out, "%6d ", i); 20993504Sjake if (cflag) 21093504Sjake fprintf(out, "%3d ", buf[i].ktr_cpu); 21193504Sjake if (tflag) 21293504Sjake fprintf(out, "%16ju ", 21393504Sjake (uintmax_t)buf[i].ktr_timestamp); 21493504Sjake if (fflag) { 21593504Sjake if (kvm_read(kd, (u_long)buf[i].ktr_file, fbuf, 21693504Sjake sizeof(fbuf)) == -1) 21793504Sjake strcpy(fbuf, "(null)"); 21893504Sjake snprintf(obuf, sizeof(obuf), "%s:%d", fbuf, 21993504Sjake buf[i].ktr_line); 22093504Sjake fprintf(out, "%-40s ", obuf); 22193504Sjake } 22293504Sjake fprintf(out, desc, parms[0], parms[1], parms[2], parms[3], 22393504Sjake parms[4], parms[5]); 22493504Sjake fprintf(out, "\n"); 22593504Sjake if (i == index) 22693504Sjake break; 22793504Sjake i = (i - 1) & (entries - 1); 22893504Sjake } 22993504Sjake 23093504Sjake return (0); 23193504Sjake} 23293504Sjake 23393504Sjakestatic void 23493504Sjakeusage(void) 23593504Sjake{ 23693504Sjake errx(1, USAGE); 23793504Sjake} 238