1169689Skan/*- 2169689Skan * Copyright (c) 2002 Jake Burkholder 3169689Skan * Copyright (c) 2004 Robert Watson 4169689Skan * All rights reserved. 5169689Skan * 6169689Skan * Redistribution and use in source and binary forms, with or without 7169689Skan * modification, are permitted provided that the following conditions 8169689Skan * are met: 9169689Skan * 1. Redistributions of source code must retain the above copyright 10169689Skan * notice, this list of conditions and the following disclaimer. 11169689Skan * 2. Redistributions in binary form must reproduce the above copyright 12169689Skan * notice, this list of conditions and the following disclaimer in the 13169689Skan * documentation and/or other materials provided with the distribution. 14169689Skan * 15169689Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18169689Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25169689Skan * SUCH DAMAGE. 26169689Skan */ 27169689Skan 28169689Skan#include <sys/cdefs.h> 29169689Skan__FBSDID("$FreeBSD$"); 30169689Skan 31169689Skan#include <sys/types.h> 32169689Skan#include <sys/ktr.h> 33169689Skan#include <sys/mman.h> 34169689Skan#include <sys/stat.h> 35169689Skan 36169689Skan#include <err.h> 37169689Skan#include <fcntl.h> 38169689Skan#include <kvm.h> 39169689Skan#include <limits.h> 40169689Skan#include <nlist.h> 41169689Skan#include <stdint.h> 42169689Skan#include <stdio.h> 43169689Skan#include <stdlib.h> 44169689Skan#include <string.h> 45169689Skan#include <unistd.h> 46169689Skan 47169689Skan#define SBUFLEN 128 48169689Skan#define USAGE \ 49169689Skan "usage: ktrdump [-cfqrtH] [-i ktrfile] [-M core] [-N system] [-o outfile]\n" 50169689Skan 51169689Skanstatic void usage(void); 52169689Skan 53169689Skanstatic struct nlist nl[] = { 54169689Skan { "_ktr_version" }, 55169689Skan { "_ktr_entries" }, 56169689Skan { "_ktr_idx" }, 57169689Skan { "_ktr_buf" }, 58169689Skan { NULL } 59169689Skan}; 60169689Skan 61169689Skanstatic int cflag; 62169689Skanstatic int fflag; 63169689Skanstatic int Mflag; 64169689Skanstatic int Nflag; 65169689Skanstatic int qflag; 66169689Skanstatic int rflag; 67169689Skanstatic int tflag; 68169689Skanstatic int iflag; 69169689Skanstatic int hflag; 70169689Skan 71169689Skanstatic char corefile[PATH_MAX]; 72169689Skanstatic char execfile[PATH_MAX]; 73169689Skan 74169689Skanstatic char desc[SBUFLEN]; 75169689Skanstatic char errbuf[_POSIX2_LINE_MAX]; 76169689Skanstatic char fbuf[PATH_MAX]; 77169689Skanstatic char obuf[PATH_MAX]; 78169689Skanstatic char sbuf[KTR_PARMS][SBUFLEN]; 79169689Skan 80169689Skan/* 81169689Skan * Reads the ktr trace buffer from kernel memory and prints the trace entries. 82169689Skan */ 83169689Skanint 84169689Skanmain(int ac, char **av) 85169689Skan{ 86169689Skan u_long parms[KTR_PARMS]; 87169689Skan struct ktr_entry *buf; 88169689Skan uintmax_t tlast, tnow; 89169689Skan unsigned long bufptr; 90169689Skan struct stat sb; 91169689Skan kvm_t *kd; 92169689Skan FILE *out; 93169689Skan char *p; 94169689Skan int version; 95169689Skan int entries; 96169689Skan int index; 97169689Skan int parm; 98169689Skan int in; 99169689Skan int c; 100169689Skan int i = 0; 101169689Skan 102169689Skan /* 103169689Skan * Parse commandline arguments. 104169689Skan */ 105169689Skan out = stdout; 106169689Skan while ((c = getopt(ac, av, "cfqrtHe:i:m:M:N:o:")) != -1) 107169689Skan switch (c) { 108169689Skan case 'c': 109169689Skan cflag = 1; 110169689Skan break; 111169689Skan case 'N': 112169689Skan case 'e': 113169689Skan if (strlcpy(execfile, optarg, sizeof(execfile)) 114169689Skan >= sizeof(execfile)) 115169689Skan errx(1, "%s: File name too long", optarg); 116169689Skan Nflag = 1; 117169689Skan break; 118169689Skan case 'f': 119169689Skan fflag = 1; 120169689Skan break; 121169689Skan case 'i': 122169689Skan iflag = 1; 123169689Skan if ((in = open(optarg, O_RDONLY)) == -1) 124169689Skan err(1, "%s", optarg); 125169689Skan break; 126169689Skan case 'M': 127169689Skan case 'm': 128169689Skan if (strlcpy(corefile, optarg, sizeof(corefile)) 129169689Skan >= sizeof(corefile)) 130169689Skan errx(1, "%s: File name too long", optarg); 131169689Skan Mflag = 1; 132169689Skan break; 133169689Skan case 'o': 134169689Skan if ((out = fopen(optarg, "w")) == NULL) 135169689Skan err(1, "%s", optarg); 136169689Skan break; 137169689Skan case 'q': 138169689Skan qflag++; 139169689Skan break; 140169689Skan case 'r': 141169689Skan rflag = 1; 142169689Skan break; 143169689Skan case 't': 144169689Skan tflag = 1; 145169689Skan break; 146169689Skan case 'H': 147169689Skan hflag = 1; 148169689Skan break; 149169689Skan case '?': 150169689Skan default: 151169689Skan usage(); 152169689Skan } 153169689Skan ac -= optind; 154169689Skan av += optind; 155169689Skan if (ac != 0) 156169689Skan usage(); 157169689Skan 158169689Skan /* 159169689Skan * Open our execfile and corefile, resolve needed symbols and read in 160169689Skan * the trace buffer. 161169689Skan */ 162169689Skan if ((kd = kvm_openfiles(Nflag ? execfile : NULL, 163169689Skan Mflag ? corefile : NULL, NULL, O_RDONLY, errbuf)) == NULL) 164169689Skan errx(1, "%s", errbuf); 165169689Skan if (kvm_nlist(kd, nl) != 0 || 166169689Skan kvm_read(kd, nl[0].n_value, &version, sizeof(version)) == -1) 167169689Skan errx(1, "%s", kvm_geterr(kd)); 168169689Skan if (version != KTR_VERSION) 169169689Skan errx(1, "ktr version mismatch"); 170169689Skan if (iflag) { 171169689Skan if (fstat(in, &sb) == -1) 172169689Skan errx(1, "stat"); 173169689Skan entries = sb.st_size / sizeof(*buf); 174169689Skan index = 0; 175169689Skan buf = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, in, 0); 176169689Skan if (buf == MAP_FAILED) 177169689Skan errx(1, "mmap"); 178169689Skan } else { 179169689Skan if (kvm_read(kd, nl[1].n_value, &entries, sizeof(entries)) 180169689Skan == -1) 181169689Skan errx(1, "%s", kvm_geterr(kd)); 182169689Skan if ((buf = malloc(sizeof(*buf) * entries)) == NULL) 183169689Skan err(1, NULL); 184169689Skan if (kvm_read(kd, nl[2].n_value, &index, sizeof(index)) == -1 || 185169689Skan kvm_read(kd, nl[3].n_value, &bufptr, 186169689Skan sizeof(bufptr)) == -1 || 187169689Skan kvm_read(kd, bufptr, buf, sizeof(*buf) * entries) == -1) 188169689Skan errx(1, "%s", kvm_geterr(kd)); 189169689Skan } 190169689Skan 191169689Skan /* 192169689Skan * Print a nice header. 193169689Skan */ 194169689Skan if (!qflag) { 195169689Skan fprintf(out, "%-6s ", "index"); 196169689Skan if (cflag) 197169689Skan fprintf(out, "%-3s ", "cpu"); 198169689Skan if (tflag) 199169689Skan fprintf(out, "%-16s ", "timestamp"); 200169689Skan if (fflag) 201169689Skan fprintf(out, "%-40s ", "file and line"); 202169689Skan if (hflag) 203169689Skan fprintf(out, "%-18s ", "tid"); 204169689Skan fprintf(out, "%s", "trace"); 205169689Skan fprintf(out, "\n"); 206169689Skan 207169689Skan fprintf(out, "------ "); 208169689Skan if (cflag) 209169689Skan fprintf(out, "--- "); 210169689Skan if (tflag) 211169689Skan fprintf(out, "---------------- "); 212169689Skan if (fflag) 213169689Skan fprintf(out, 214169689Skan "---------------------------------------- "); 215169689Skan if (hflag) 216169689Skan fprintf(out, "------------------ "); 217169689Skan fprintf(out, "----- "); 218169689Skan fprintf(out, "\n"); 219169689Skan } 220169689Skan 221169689Skan /* 222169689Skan * Now tear through the trace buffer. 223169689Skan */ 224169689Skan if (!iflag) 225169689Skan i = (index - 1) % entries; 226169689Skan tlast = -1; 227169689Skan for (;;) { 228169689Skan if (buf[i].ktr_desc == NULL) 229169689Skan break; 230169689Skan if (kvm_read(kd, (u_long)buf[i].ktr_desc, desc, 231169689Skan sizeof(desc)) == -1) 232169689Skan errx(1, "%s", kvm_geterr(kd)); 233169689Skan desc[sizeof(desc) - 1] = '\0'; 234169689Skan parm = 0; 235169689Skan for (p = desc; (c = *p++) != '\0';) { 236169689Skan if (c != '%') 237169689Skan continue; 238169689Skannext: if ((c = *p++) == '\0') 239169689Skan break; 240169689Skan if (parm == KTR_PARMS) 241169689Skan errx(1, "too many parameters"); 242169689Skan switch (c) { 243169689Skan case '0': case '1': case '2': case '3': case '4': 244169689Skan case '5': case '6': case '7': case '8': case '9': 245169689Skan case '#': case '-': case ' ': case '+': case '\'': 246169689Skan case 'h': case 'l': case 'j': case 't': case 'z': 247169689Skan case 'q': case 'L': case '.': 248169689Skan goto next; 249169689Skan case 's': 250169689Skan if (kvm_read(kd, (u_long)buf[i].ktr_parms[parm], 251169689Skan sbuf[parm], sizeof(sbuf[parm])) == -1) 252169689Skan strcpy(sbuf[parm], "(null)"); 253169689Skan sbuf[parm][sizeof(sbuf[0]) - 1] = '\0'; 254169689Skan parms[parm] = (u_long)sbuf[parm]; 255169689Skan parm++; 256169689Skan break; 257169689Skan default: 258169689Skan parms[parm] = buf[i].ktr_parms[parm]; 259169689Skan parm++; 260169689Skan break; 261169689Skan } 262169689Skan } 263169689Skan fprintf(out, "%6d ", i); 264169689Skan if (cflag) 265169689Skan fprintf(out, "%3d ", buf[i].ktr_cpu); 266169689Skan if (tflag) { 267169689Skan tnow = (uintmax_t)buf[i].ktr_timestamp; 268169689Skan if (rflag) { 269169689Skan if (tlast == -1) 270169689Skan tlast = tnow; 271169689Skan fprintf(out, "%16ju ", !iflag ? tlast - tnow : 272169689Skan tnow - tlast); 273 tlast = tnow; 274 } else 275 fprintf(out, "%16ju ", tnow); 276 } 277 if (fflag) { 278 if (kvm_read(kd, (u_long)buf[i].ktr_file, fbuf, 279 sizeof(fbuf)) == -1) 280 strcpy(fbuf, "(null)"); 281 snprintf(obuf, sizeof(obuf), "%s:%d", fbuf, 282 buf[i].ktr_line); 283 fprintf(out, "%-40s ", obuf); 284 } 285 if (hflag) 286 fprintf(out, "%p ", buf[i].ktr_thread); 287 fprintf(out, desc, parms[0], parms[1], parms[2], parms[3], 288 parms[4], parms[5]); 289 fprintf(out, "\n"); 290 if (!iflag) { 291 if (i == index) 292 break; 293 i = (i - 1) % entries; 294 } else { 295 if (++i == entries) 296 break; 297 } 298 } 299 300 return (0); 301} 302 303static void 304usage(void) 305{ 306 307 fprintf(stderr, USAGE); 308 exit(1); 309} 310