ktrdump.c revision 93504
1/*-
2 * Copyright (c) 2002 Jake Burkholder
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/usr.bin/ktrdump/ktrdump.c 93504 2002-04-01 05:41:13Z jake $");
29
30#include <sys/types.h>
31#include <sys/ktr.h>
32
33#include <err.h>
34#include <fcntl.h>
35#include <kvm.h>
36#include <limits.h>
37#include <nlist.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <unistd.h>
42
43#define	SBUFLEN	128
44#define	USAGE \
45	"usage: ktrdump [-c] [-f] [-t] [-e execfile] [-m corefile] [-o outfile]"
46
47extern char *optarg;
48extern int optind;
49
50static void usage(void);
51
52static struct nlist nl[] = {
53	{ "_ktr_version" },
54	{ "_ktr_entries" },
55	{ "_ktr_idx" },
56	{ "_ktr_buf" },
57	{ NULL }
58};
59
60static int cflag;
61static int eflag;
62static int fflag;
63static int mflag;
64static int tflag;
65
66static char corefile[PATH_MAX];
67static char execfile[PATH_MAX];
68
69static char desc[SBUFLEN];
70static char errbuf[_POSIX2_LINE_MAX];
71static char fbuf[PATH_MAX];
72static char obuf[PATH_MAX];
73static char sbuf[KTR_PARMS][SBUFLEN];
74
75/*
76 * Reads the ktr trace buffer from kernel memory and prints the trace entries.
77 */
78int
79main(int ac, char **av)
80{
81	u_long parms[KTR_PARMS];
82	struct ktr_entry *buf;
83	kvm_t *kd;
84	FILE *out;
85	char *p;
86	int version;
87	int entries;
88	int index;
89	int parm;
90	int c;
91	int i;
92	int n;
93
94	/*
95	 * Parse commandline arguments.
96	 */
97	out = stdout;
98	while ((c = getopt(ac, av, "cfte:m:o:")) != -1)
99		switch (c) {
100		case 'c':
101			cflag = 1;
102			break;
103		case 'e':
104			strcpy(optarg, execfile);
105			eflag = 1;
106			break;
107		case 'f':
108			fflag = 1;
109			break;
110		case 'm':
111			strcpy(optarg, corefile);
112			mflag = 1;
113			break;
114		case 'o':
115			if ((out = fopen(optarg, "w")) == NULL)
116				err(1, "%s", optarg);
117			break;
118		case 't':
119			tflag = 1;
120			break;
121		case '?':
122		default:
123			usage();
124		}
125	ac -= optind;
126	av += optind;
127	if (ac != 0)
128		usage();
129
130	/*
131	 * Open our execfile and corefile, resolve needed symbols and read in
132	 * the trace buffer.
133	 */
134	if ((kd = kvm_openfiles(eflag ? execfile : NULL,
135	    mflag ? corefile : NULL, NULL, O_RDONLY, errbuf)) == NULL)
136		errx(1, "%s", errbuf);
137	if (kvm_nlist(kd, nl) != 0 ||
138	    kvm_read(kd, nl[0].n_value, &version, sizeof(version)) == -1)
139		errx(1, "%s", kvm_geterr(kd));
140	if (version != KTR_VERSION)
141		errx(1, "ktr version mismatch");
142	if (kvm_read(kd, nl[1].n_value, &entries, sizeof(entries)) == -1)
143		errx(1, "%s", kvm_geterr(kd));
144	if ((buf = malloc(sizeof(*buf) * entries)) == NULL)
145		err(1, NULL);
146	if (kvm_read(kd, nl[2].n_value, &index, sizeof(index)) == -1 ||
147	    kvm_read(kd, nl[3].n_value, buf, sizeof(*buf) * entries) == -1)
148		errx(1, "%s", kvm_geterr(kd));
149
150	/*
151	 * Print a nice header.
152	 */
153	fprintf(out, "%-6s ", "index");
154	if (cflag)
155		fprintf(out, "%-3s ", "cpu");
156	if (tflag)
157		fprintf(out, "%-16s ", "timestamp");
158	if (fflag)
159		fprintf(out, "%-32s ", "file and line");
160	fprintf(out, "%s", "trace");
161	fprintf(out, "\n");
162
163	fprintf(out, "------ ");
164	if (cflag)
165		fprintf(out, "--- ");
166	if (tflag)
167		fprintf(out, "---------------- ");
168	if (fflag)
169		fprintf(out, "---------------------------------------- ");
170	fprintf(out, "----- ");
171	fprintf(out, "\n");
172
173	/*
174	 * Now tear through the trace buffer.
175	 */
176	i = (index - 1) & (entries - 1);
177	for (;;) {
178		if (buf[i].ktr_desc == NULL)
179			break;
180		if (kvm_read(kd, (u_long)buf[i].ktr_desc, desc,
181		    sizeof(desc)) == -1)
182			errx(1, "%s", kvm_geterr(kd));
183		desc[sizeof(desc) - 1] = '\0';
184		parm = 0;
185		for (p = desc; (c = *p++) != '\0';) {
186			if (c != '%')
187				continue;
188			if ((c = *p++) == '\0')
189				break;
190			if (parm == KTR_PARMS)
191				errx(1, "too many parameters");
192			switch (c) {
193			case 's':
194				if (kvm_read(kd, (u_long)buf[i].ktr_parms[parm],
195				    sbuf[parm], sizeof(sbuf[parm])) == -1)
196					strcpy(sbuf[parm], "(null)");
197				sbuf[parm][sizeof(sbuf[0]) - 1] = '\0';
198				parms[parm] = (u_long)sbuf[parm];
199				parm++;
200				break;
201			default:
202				parms[parm] = buf[i].ktr_parms[parm];
203				parm++;
204				break;
205			}
206		}
207		fprintf(out, "%6d ", i);
208		if (cflag)
209			fprintf(out, "%3d ", buf[i].ktr_cpu);
210		if (tflag)
211			fprintf(out, "%16ju ",
212			    (uintmax_t)buf[i].ktr_timestamp);
213		if (fflag) {
214			if (kvm_read(kd, (u_long)buf[i].ktr_file, fbuf,
215			    sizeof(fbuf)) == -1)
216				strcpy(fbuf, "(null)");
217			snprintf(obuf, sizeof(obuf), "%s:%d", fbuf,
218			    buf[i].ktr_line);
219			fprintf(out, "%-40s ", obuf);
220		}
221		fprintf(out, desc, parms[0], parms[1], parms[2], parms[3],
222		    parms[4], parms[5]);
223		fprintf(out, "\n");
224		if (i == index)
225			break;
226		i = (i - 1) & (entries - 1);
227	}
228
229	return (0);
230}
231
232static void
233usage(void)
234{
235	errx(1, USAGE);
236}
237