ktrdump.c revision 129559
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 129559 2004-05-21 21:24:58Z rwatson $"); 2993504Sjake 3093504Sjake#include <sys/types.h> 3193504Sjake#include <sys/ktr.h> 32103791Sjeff#include <sys/mman.h> 33103791Sjeff#include <sys/stat.h> 3493504Sjake 3593504Sjake#include <err.h> 3693504Sjake#include <fcntl.h> 3793504Sjake#include <kvm.h> 3893504Sjake#include <limits.h> 3993504Sjake#include <nlist.h> 4093617Sjake#include <stdint.h> 4193504Sjake#include <stdio.h> 4293504Sjake#include <stdlib.h> 4393504Sjake#include <string.h> 4493504Sjake#include <unistd.h> 4593504Sjake 4693504Sjake#define SBUFLEN 128 4793504Sjake#define USAGE \ 48129559Srwatson "usage: ktrdump [-c] [-f] [-q] [-t] [-e execfile] [-i ktrfile ] [-m corefile] [-o outfile]" 4993504Sjake 5093504Sjakeextern char *optarg; 5193504Sjakeextern int optind; 5293504Sjake 5393504Sjakestatic void usage(void); 5493504Sjake 5593504Sjakestatic struct nlist nl[] = { 5693504Sjake { "_ktr_version" }, 5793504Sjake { "_ktr_entries" }, 5893504Sjake { "_ktr_idx" }, 5993504Sjake { "_ktr_buf" }, 6093504Sjake { NULL } 6193504Sjake}; 6293504Sjake 6393504Sjakestatic int cflag; 6493504Sjakestatic int eflag; 6593504Sjakestatic int fflag; 6693504Sjakestatic int mflag; 67129559Srwatsonstatic int qflag; 6893504Sjakestatic int tflag; 69103791Sjeffstatic int iflag; 7093504Sjake 7193504Sjakestatic char corefile[PATH_MAX]; 7293504Sjakestatic char execfile[PATH_MAX]; 7393504Sjake 7493504Sjakestatic char desc[SBUFLEN]; 7593504Sjakestatic char errbuf[_POSIX2_LINE_MAX]; 7693504Sjakestatic char fbuf[PATH_MAX]; 7793504Sjakestatic char obuf[PATH_MAX]; 7893504Sjakestatic char sbuf[KTR_PARMS][SBUFLEN]; 7993504Sjake 8093504Sjake/* 8193504Sjake * Reads the ktr trace buffer from kernel memory and prints the trace entries. 8293504Sjake */ 8393504Sjakeint 8493504Sjakemain(int ac, char **av) 8593504Sjake{ 8693504Sjake u_long parms[KTR_PARMS]; 8793504Sjake struct ktr_entry *buf; 88103791Sjeff struct stat sb; 8993504Sjake kvm_t *kd; 9093504Sjake FILE *out; 9193504Sjake char *p; 9293504Sjake int version; 9393504Sjake int entries; 9493504Sjake int index; 9593504Sjake int parm; 96103791Sjeff int in; 9793504Sjake int c; 9893504Sjake int i; 9993504Sjake 10093504Sjake /* 10193504Sjake * Parse commandline arguments. 10293504Sjake */ 10393504Sjake out = stdout; 104129559Srwatson while ((c = getopt(ac, av, "cfqte:i:m:o:")) != -1) 10593504Sjake switch (c) { 10693504Sjake case 'c': 10793504Sjake cflag = 1; 10893504Sjake break; 10993504Sjake case 'e': 110104586Skris if (strlcpy(execfile, optarg, sizeof(execfile)) 111104586Skris >= sizeof(execfile)) 112104586Skris errx(1, "%s: File name too long", optarg); 11393504Sjake eflag = 1; 11493504Sjake break; 11593504Sjake case 'f': 11693504Sjake fflag = 1; 11793504Sjake break; 118103791Sjeff case 'i': 119103791Sjeff iflag = 1; 120103791Sjeff if ((in = open(optarg, O_RDONLY)) == -1) 121103791Sjeff err(1, "%s", optarg); 122103791Sjeff break; 12393504Sjake case 'm': 124104586Skris if (strlcpy(corefile, optarg, sizeof(corefile)) 125104586Skris >= sizeof(corefile)) 126104586Skris errx(1, "%s: File name too long", optarg); 12793504Sjake mflag = 1; 12893504Sjake break; 12993504Sjake case 'o': 13093504Sjake if ((out = fopen(optarg, "w")) == NULL) 13193504Sjake err(1, "%s", optarg); 13293504Sjake break; 133129559Srwatson case 'q': 134129559Srwatson qflag++; 135129559Srwatson break; 13693504Sjake case 't': 13793504Sjake tflag = 1; 13893504Sjake break; 13993504Sjake case '?': 14093504Sjake default: 14193504Sjake usage(); 14293504Sjake } 14393504Sjake ac -= optind; 14493504Sjake av += optind; 14593504Sjake if (ac != 0) 14693504Sjake usage(); 14793504Sjake 14893504Sjake /* 14993504Sjake * Open our execfile and corefile, resolve needed symbols and read in 15093504Sjake * the trace buffer. 15193504Sjake */ 15293504Sjake if ((kd = kvm_openfiles(eflag ? execfile : NULL, 15393504Sjake mflag ? corefile : NULL, NULL, O_RDONLY, errbuf)) == NULL) 15493504Sjake errx(1, "%s", errbuf); 15593504Sjake if (kvm_nlist(kd, nl) != 0 || 15693504Sjake kvm_read(kd, nl[0].n_value, &version, sizeof(version)) == -1) 15793504Sjake errx(1, "%s", kvm_geterr(kd)); 15893504Sjake if (version != KTR_VERSION) 15993504Sjake errx(1, "ktr version mismatch"); 160103791Sjeff if (iflag) { 161103791Sjeff if (fstat(in, &sb) == -1) 162103791Sjeff errx(1, "stat"); 163103791Sjeff entries = sb.st_size / sizeof(*buf); 164103791Sjeff index = 0; 165103791Sjeff buf = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, in, 0); 166103791Sjeff if (buf == MAP_FAILED) 167103791Sjeff errx(1, "mmap"); 168103791Sjeff } else { 169103791Sjeff if (kvm_read(kd, nl[1].n_value, &entries, sizeof(entries)) 170103791Sjeff == -1) 171103791Sjeff errx(1, "%s", kvm_geterr(kd)); 172103791Sjeff if ((buf = malloc(sizeof(*buf) * entries)) == NULL) 173103791Sjeff err(1, NULL); 174103791Sjeff if (kvm_read(kd, nl[2].n_value, &index, sizeof(index)) == -1 || 175103791Sjeff kvm_read(kd, nl[3].n_value, buf, sizeof(*buf) * entries) 176103791Sjeff == -1) 177103791Sjeff errx(1, "%s", kvm_geterr(kd)); 178103791Sjeff } 17993504Sjake 18093504Sjake /* 18193504Sjake * Print a nice header. 18293504Sjake */ 183129559Srwatson if (!qflag) { 184129559Srwatson fprintf(out, "%-6s ", "index"); 185129559Srwatson if (cflag) 186129559Srwatson fprintf(out, "%-3s ", "cpu"); 187129559Srwatson if (tflag) 188129559Srwatson fprintf(out, "%-16s ", "timestamp"); 189129559Srwatson if (fflag) 190129559Srwatson fprintf(out, "%-40s ", "file and line"); 191129559Srwatson fprintf(out, "%s", "trace"); 192129559Srwatson fprintf(out, "\n"); 19393504Sjake 194129559Srwatson fprintf(out, "------ "); 195129559Srwatson if (cflag) 196129559Srwatson fprintf(out, "--- "); 197129559Srwatson if (tflag) 198129559Srwatson fprintf(out, "---------------- "); 199129559Srwatson if (fflag) 200129559Srwatson fprintf(out, 201129559Srwatson "---------------------------------------- "); 202129559Srwatson fprintf(out, "----- "); 203129559Srwatson fprintf(out, "\n"); 204129559Srwatson } 20593504Sjake 20693504Sjake /* 20793504Sjake * Now tear through the trace buffer. 20893504Sjake */ 209103791Sjeff if (!iflag) 210103791Sjeff i = (index - 1) & (entries - 1); 21193504Sjake for (;;) { 21293504Sjake if (buf[i].ktr_desc == NULL) 21393504Sjake break; 21493504Sjake if (kvm_read(kd, (u_long)buf[i].ktr_desc, desc, 21593504Sjake sizeof(desc)) == -1) 21693504Sjake errx(1, "%s", kvm_geterr(kd)); 21793504Sjake desc[sizeof(desc) - 1] = '\0'; 21893504Sjake parm = 0; 21993504Sjake for (p = desc; (c = *p++) != '\0';) { 22093504Sjake if (c != '%') 22193504Sjake continue; 22293504Sjake if ((c = *p++) == '\0') 22393504Sjake break; 22493504Sjake if (parm == KTR_PARMS) 22593504Sjake errx(1, "too many parameters"); 22693504Sjake switch (c) { 22793504Sjake case 's': 22893504Sjake if (kvm_read(kd, (u_long)buf[i].ktr_parms[parm], 22993504Sjake sbuf[parm], sizeof(sbuf[parm])) == -1) 23093504Sjake strcpy(sbuf[parm], "(null)"); 23193504Sjake sbuf[parm][sizeof(sbuf[0]) - 1] = '\0'; 23293504Sjake parms[parm] = (u_long)sbuf[parm]; 23393504Sjake parm++; 23493504Sjake break; 23593504Sjake default: 23693504Sjake parms[parm] = buf[i].ktr_parms[parm]; 23793504Sjake parm++; 23893504Sjake break; 23993504Sjake } 24093504Sjake } 24193504Sjake fprintf(out, "%6d ", i); 24293504Sjake if (cflag) 24393504Sjake fprintf(out, "%3d ", buf[i].ktr_cpu); 24493504Sjake if (tflag) 24593504Sjake fprintf(out, "%16ju ", 24693504Sjake (uintmax_t)buf[i].ktr_timestamp); 24793504Sjake if (fflag) { 24893504Sjake if (kvm_read(kd, (u_long)buf[i].ktr_file, fbuf, 24993504Sjake sizeof(fbuf)) == -1) 25093504Sjake strcpy(fbuf, "(null)"); 25193504Sjake snprintf(obuf, sizeof(obuf), "%s:%d", fbuf, 25293504Sjake buf[i].ktr_line); 25393504Sjake fprintf(out, "%-40s ", obuf); 25493504Sjake } 25593504Sjake fprintf(out, desc, parms[0], parms[1], parms[2], parms[3], 25693504Sjake parms[4], parms[5]); 25793504Sjake fprintf(out, "\n"); 258103791Sjeff if (!iflag) { 259103791Sjeff if (i == index) 260103791Sjeff break; 261103791Sjeff i = (i - 1) & (entries - 1); 262103791Sjeff } else { 263103791Sjeff if (++i == entries) 264103791Sjeff break; 265103791Sjeff } 26693504Sjake } 26793504Sjake 26893504Sjake return (0); 26993504Sjake} 27093504Sjake 27193504Sjakestatic void 27293504Sjakeusage(void) 27393504Sjake{ 27493504Sjake errx(1, USAGE); 27593504Sjake} 276