2 * Copyright (c) 2002 Jake Burkholder
3 * Copyright (c) 2004 Robert Watson
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * $FreeBSD: src/usr.bin/ktrdump/ktrdump.c,v 1.10 2005/05/21 09:55:06 ru Exp $
28 * $DragonFly: src/usr.bin/ktrdump/ktrdump.c,v 1.3 2005/06/21 06:50:28 dillon Exp $
31 #include <sys/cdefs.h>
33 #include <sys/types.h>
37 #include <sys/queue.h>
55 static void usage(void);
56 static void print_header(FILE *fo, int row);
57 static void print_entry(FILE *fo, kvm_t *kd, int n, int i, struct ktr_entry *entry);
58 static struct ktr_info *kvm_ktrinfo(kvm_t *kd, void *kptr);
59 static const char *kvm_string(kvm_t *kd, const char *kptr);
60 static const char *trunc_path(const char *str, int maxlen);
61 static void read_symbols(const char *execfile);
62 static const char *address_to_symbol(void *kptr);
64 static struct nlist nl[] = {
84 static int64_t last_timestamp;
86 static char corefile[PATH_MAX];
87 static char execfile[PATH_MAX];
89 static char desc[SBUFLEN];
90 static char errbuf[_POSIX2_LINE_MAX];
91 static char fbuf[PATH_MAX];
92 static char obuf[PATH_MAX];
95 * Reads the ktr trace buffer from kernel memory and prints the trace entries.
98 main(int ac, char **av)
100 struct ktr_entry **ktr_buf;
101 uintmax_t tlast, tnow;
110 int did_display_flag = 0;
117 * Parse commandline arguments.
120 while ((c = getopt(ac, av, "acfiqrtxpN:M:o:")) != -1) {
134 if (strlcpy(execfile, optarg, sizeof(execfile))
136 errx(1, "%s: File name too long", optarg);
146 if (strlcpy(corefile, optarg, sizeof(corefile))
148 errx(1, "%s: File name too long", optarg);
155 if ((fo = fopen(optarg, "w")) == NULL)
156 err(1, "%s", optarg);
178 if (cflag + iflag + tflag + xflag + fflag + pflag == 0) {
192 * Open our execfile and corefile, resolve needed symbols and read in
195 if ((kd = kvm_openfiles(Nflag ? execfile : NULL,
196 Mflag ? corefile : NULL, NULL, O_RDONLY, errbuf)) == NULL)
197 errx(1, "%s", errbuf);
198 if (kvm_nlist(kd, nl) != 0)
199 errx(1, "%s", kvm_geterr(kd));
200 if (kvm_read(kd, nl[0].n_value, &version, sizeof(version)) == -1)
201 errx(1, "%s", kvm_geterr(kd));
202 if (kvm_read(kd, nl[4].n_value, &ncpus, sizeof(ncpus)) == -1)
203 errx(1, "%s", kvm_geterr(kd));
205 if (version != KTR_VERSION)
206 errx(1, "ktr version mismatch");
207 if (kvm_read(kd, nl[1].n_value, &entries, sizeof(entries)) == -1)
208 errx(1, "%s", kvm_geterr(kd));
209 ktr_buf = malloc(sizeof(*ktr_buf) * ncpus);
210 ktr_idx = malloc(sizeof(*ktr_idx) * ncpus);
213 read_symbols(Nflag ? execfile : NULL);
215 if (kvm_read(kd, nl[2].n_value, ktr_idx, sizeof(*ktr_idx) * ncpus) == -1)
216 errx(1, "%s", kvm_geterr(kd));
217 if (kvm_read(kd, nl[3].n_value, ktr_buf, sizeof(*ktr_buf) * ncpus) == -1)
218 errx(1, "%s", kvm_geterr(kd));
219 for (n = 0; n < ncpus; ++n) {
220 void *kptr = ktr_buf[n];
221 ktr_buf[n] = malloc(sizeof(**ktr_buf) * entries);
222 if (kvm_read(kd, (uintptr_t)kptr, ktr_buf[n], sizeof(**ktr_buf) * entries) == -1)
223 errx(1, "%s", kvm_geterr(kd));
227 * Now tear through the trace buffer.
229 for (n = 0; n < ncpus; ++n) {
231 for (i = 0; i < entries; ++i) {
233 print_entry(fo, kd, n, i, &ktr_buf[n][i]);
240 print_header(FILE *fo, int row)
242 if (qflag == 0 && row % 20 == 0) {
243 fprintf(fo, "%-6s ", "index");
245 fprintf(fo, "%-3s ", "cpu");
247 fprintf(fo, "%-16s ", "timestamp");
250 fprintf(fo, "%-10s %-10s", "caller2", "caller1");
252 fprintf(fo, "%-20s %-20s", "caller2", "caller1");
255 fprintf(fo, "%-20s ", "ID");
257 fprintf(fo, "%10s%-30s ", "", "file and line");
259 fprintf(fo, "%s", "trace");
265 print_entry(FILE *fo, kvm_t *kd, int n, int i, struct ktr_entry *entry)
267 struct ktr_info *info = NULL;
269 fprintf(fo, " %5d ", i);
271 fprintf(fo, "%-3d ", n);
272 if (tflag || rflag) {
274 fprintf(fo, "%-16lld ", entry->ktr_timestamp -
277 fprintf(fo, "%-16lld ", entry->ktr_timestamp);
281 fprintf(fo, "%p %p ",
282 entry->ktr_caller2, entry->ktr_caller1);
284 fprintf(fo, "%-20s ",
285 address_to_symbol(entry->ktr_caller2));
286 fprintf(fo, "%-20s ",
287 address_to_symbol(entry->ktr_caller1));
291 info = kvm_ktrinfo(kd, entry->ktr_info);
293 fprintf(fo, "%-20s ", kvm_string(kd, info->kf_name));
295 fprintf(fo, "%-20s ", "<empty>");
298 fprintf(fo, "%34s:%-4d ", trunc_path(kvm_string(kd, entry->ktr_file), 34), entry->ktr_line);
301 info = kvm_ktrinfo(kd, entry->ktr_info);
303 fprintf(fo, kvm_string(kd, info->kf_format),
304 entry->ktr_data[0], entry->ktr_data[1],
305 entry->ktr_data[2], entry->ktr_data[3],
306 entry->ktr_data[4], entry->ktr_data[5],
307 entry->ktr_data[6], entry->ktr_data[7],
308 entry->ktr_data[8], entry->ktr_data[9]);
314 last_timestamp = entry->ktr_timestamp;
319 kvm_ktrinfo(kvm_t *kd, void *kptr)
321 static struct ktr_info save_info;
322 static void *save_kptr;
326 if (save_kptr != kptr) {
327 if (kvm_read(kd, (uintptr_t)kptr, &save_info, sizeof(save_info)) == -1) {
328 bzero(&save_info, sizeof(save_info));
338 kvm_string(kvm_t *kd, const char *kptr)
340 static char save_str[128];
341 static const char *save_kptr;
347 if (save_kptr != kptr) {
350 while (l < sizeof(save_str) - 1) {
351 n = 256 - ((intptr_t)(kptr + l) & 255);
352 if (n > sizeof(save_str) - l - 1)
353 n = sizeof(save_str) - l - 1;
354 if (kvm_read(kd, (uintptr_t)(kptr + l), save_str + l, n) < 0)
356 while (l < sizeof(save_str) && n) {
357 if (save_str[l] == 0)
372 trunc_path(const char *str, int maxlen)
374 int len = strlen(str);
377 return(str + len - maxlen);
383 TAILQ_ENTRY(symdata) link;
389 static TAILQ_HEAD(symlist, symdata) symlist;
390 static struct symdata *symcache;
391 static char *symbegin;
396 read_symbols(const char *execfile)
400 int buflen = sizeof(buf);
407 TAILQ_INIT(&symlist);
409 if (execfile == NULL) {
410 if (sysctlbyname("kern.bootfile", buf, &buflen, NULL, 0) < 0)
411 execfile = "/kernel";
415 snprintf(cmd, sizeof(cmd), "nm -n %s", execfile);
416 if ((fp = popen(cmd, "r")) != NULL) {
417 while (fgets(buf, sizeof(buf), fp) != NULL) {
418 s1 = strtok(buf, " \t\n");
419 s2 = strtok(NULL, " \t\n");
420 s3 = strtok(NULL, " \t\n");
421 if (s1 && s2 && s3) {
422 sym = malloc(sizeof(struct symdata));
423 sym->symaddr = (char *)strtoul(s1, NULL, 16);
424 sym->symtype = s2[0];
425 sym->symname = strdup(s3);
426 if (strcmp(s3, "kernbase") == 0)
427 symbegin = sym->symaddr;
428 if (strcmp(s3, "end") == 0)
429 symend = sym->symaddr;
430 TAILQ_INSERT_TAIL(&symlist, sym, link);
435 symcache = TAILQ_FIRST(&symlist);
440 address_to_symbol(void *kptr)
444 if (symcache == NULL ||
445 (char *)kptr < symbegin || (char *)kptr >= symend
447 snprintf(buf, sizeof(buf), "%p", kptr);
450 while ((char *)symcache->symaddr < (char *)kptr) {
451 if (TAILQ_NEXT(symcache, link) == NULL)
453 symcache = TAILQ_NEXT(symcache, link);
455 while ((char *)symcache->symaddr > (char *)kptr) {
456 if (symcache != TAILQ_FIRST(&symlist))
457 symcache = TAILQ_PREV(symcache, symlist, link);
459 snprintf(buf, sizeof(buf), "%s+%d", symcache->symname,
460 (int)((char *)kptr - symcache->symaddr));
467 fprintf(stderr, "usage: ktrdump [-acfinpqrtx] [-N execfile] "
468 "[-M corefile] [-o outfile]\n");