xref: /freebsd/sys/kern/kern_ktr.c (revision a3e8fd0b7f663db7eafff527d5c3ca3bcfa8a537)
1 /*
2  * Copyright (c) 2000
3  *	John Baldwin <jhb@FreeBSD.org>.  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  * 4. Neither the name of the author nor the names of any co-contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY JOHN BALDWIN AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL JOHN BALDWIN OR THE VOICES IN HIS HEAD
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 
32 /*
33  * This module holds the global variables used by KTR and the ktr_tracepoint()
34  * function that does the actual tracing.
35  */
36 
37 #include "opt_ddb.h"
38 #include "opt_ktr.h"
39 #include "opt_alq.h"
40 
41 #include <sys/param.h>
42 #include <sys/alq.h>
43 #include <sys/cons.h>
44 #include <sys/kernel.h>
45 #include <sys/ktr.h>
46 #include <sys/libkern.h>
47 #include <sys/proc.h>
48 #include <sys/sysctl.h>
49 #include <sys/systm.h>
50 #include <sys/time.h>
51 
52 #include <machine/cpu.h>
53 #ifdef __sparc64__
54 #include <machine/ktr.h>
55 #endif
56 
57 
58 #include <ddb/ddb.h>
59 
60 #ifndef KTR_ENTRIES
61 #define	KTR_ENTRIES	1024
62 #endif
63 
64 #ifndef KTR_MASK
65 #define	KTR_MASK	(KTR_GEN)
66 #endif
67 
68 #ifndef KTR_CPUMASK
69 #define	KTR_CPUMASK	(~0)
70 #endif
71 
72 #ifndef KTR_TIME
73 #define	KTR_TIME	get_cyclecount()
74 #endif
75 
76 #ifndef KTR_CPU
77 #define	KTR_CPU		PCPU_GET(cpuid)
78 #endif
79 
80 SYSCTL_NODE(_debug, OID_AUTO, ktr, CTLFLAG_RD, 0, "KTR options");
81 
82 int	ktr_cpumask = KTR_CPUMASK;
83 TUNABLE_INT("debug.ktr.cpumask", &ktr_cpumask);
84 SYSCTL_INT(_debug_ktr, OID_AUTO, cpumask, CTLFLAG_RW, &ktr_cpumask, 0, "");
85 
86 int	ktr_mask = KTR_MASK;
87 TUNABLE_INT("debug.ktr.mask", &ktr_mask);
88 SYSCTL_INT(_debug_ktr, OID_AUTO, mask, CTLFLAG_RW, &ktr_mask, 0, "");
89 
90 int	ktr_entries = KTR_ENTRIES;
91 SYSCTL_INT(_debug_ktr, OID_AUTO, entries, CTLFLAG_RD, &ktr_entries, 0, "");
92 
93 int	ktr_version = KTR_VERSION;
94 SYSCTL_INT(_debug_ktr, OID_AUTO, version, CTLFLAG_RD, &ktr_version, 0, "");
95 
96 volatile int	ktr_idx = 0;
97 struct	ktr_entry ktr_buf[KTR_ENTRIES];
98 
99 #ifdef KTR_VERBOSE
100 int	ktr_verbose = KTR_VERBOSE;
101 TUNABLE_INT("debug.ktr.verbose", &ktr_verbose);
102 SYSCTL_INT(_debug_ktr, OID_AUTO, verbose, CTLFLAG_RW, &ktr_verbose, 0, "");
103 #endif
104 
105 #ifdef KTR_ALQ
106 struct alq *ktr_alq;
107 char	ktr_alq_file[MAXPATHLEN] = "/tmp/ktr.out";
108 int	ktr_alq_cnt = 0;
109 int	ktr_alq_depth = KTR_ENTRIES;
110 int	ktr_alq_enabled = 0;
111 int	ktr_alq_failed = 0;
112 int	ktr_alq_max = 0;
113 
114 SYSCTL_INT(_debug_ktr, OID_AUTO, alq_max, CTLFLAG_RW, &ktr_alq_max, 0,
115     "Maximum number of entries to write");
116 SYSCTL_INT(_debug_ktr, OID_AUTO, alq_cnt, CTLFLAG_RD, &ktr_alq_cnt, 0,
117     "Current number of written entries");
118 SYSCTL_INT(_debug_ktr, OID_AUTO, alq_failed, CTLFLAG_RD, &ktr_alq_failed, 0,
119     "Number of times we overran the buffer");
120 SYSCTL_INT(_debug_ktr, OID_AUTO, alq_depth, CTLFLAG_RW, &ktr_alq_depth, 0,
121     "Number of items in the write buffer");
122 SYSCTL_STRING(_debug_ktr, OID_AUTO, alq_file, CTLFLAG_RW, ktr_alq_file,
123     sizeof(ktr_alq_file), "KTR logging file");
124 
125 static int
126 sysctl_debug_ktr_alq_enable(SYSCTL_HANDLER_ARGS)
127 {
128 	int error;
129 	int enable;
130 
131 	enable = ktr_alq_enabled;
132 
133         error = sysctl_handle_int(oidp, &enable, 0, req);
134         if (error || !req->newptr)
135                 return (error);
136 
137 	if (enable) {
138 		if (ktr_alq_enabled)
139 			return (0);
140 		error = suser(curthread);
141 		if (error)
142 			return (error);
143 		error = alq_open(&ktr_alq, (const char *)ktr_alq_file,
144 		    sizeof(struct ktr_entry), ktr_alq_depth);
145 		if (error == 0) {
146 			ktr_mask &= ~KTR_ALQ_MASK;
147 			ktr_alq_cnt = 0;
148 			ktr_alq_failed = 0;
149 			ktr_alq_enabled = 1;
150 		}
151 	} else {
152 		if (ktr_alq_enabled == 0)
153 			return (0);
154 		ktr_alq_enabled = 0;
155 		alq_close(ktr_alq);
156 		ktr_alq = NULL;
157 	}
158 
159 	return (error);
160 }
161 SYSCTL_PROC(_debug_ktr, OID_AUTO, alq_enable,
162     CTLTYPE_INT|CTLFLAG_RW, 0, 0, sysctl_debug_ktr_alq_enable,
163     "I", "Enable KTR logging");
164 #endif
165 
166 void
167 ktr_tracepoint(u_int mask, const char *file, int line, const char *format,
168     u_long arg1, u_long arg2, u_long arg3, u_long arg4, u_long arg5,
169     u_long arg6)
170 {
171 	struct ktr_entry *entry;
172 #ifdef KTR_ALQ
173 	struct ale *ale = NULL;
174 #else
175 	int newindex, saveindex;
176 #endif
177 #if defined(KTR_VERBOSE) || defined(KTR_ALQ)
178 	struct thread *td;
179 #endif
180 	int cpu;
181 
182 	if (panicstr)
183 		return;
184 	if ((ktr_mask & mask) == 0)
185 		return;
186 	cpu = KTR_CPU;
187 	if (((1 << cpu) & ktr_cpumask) == 0)
188 		return;
189 #if defined(KTR_VERBOSE) || defined(KTR_ALQ)
190 	td = curthread;
191 	if (td->td_inktr)
192 		return;
193 	td->td_inktr++;
194 #endif
195 #ifdef KTR_ALQ
196 	if (ktr_alq_enabled &&
197 	    td->td_critnest == 0 &&
198 	    (td->td_kse->ke_flags & KEF_IDLEKSE) == 0 &&
199 	    td != ald_thread) {
200 		if (ktr_alq_max && ktr_alq_cnt > ktr_alq_max)
201 			goto done;
202 		if ((ale = alq_get(ktr_alq, ALQ_NOWAIT)) == NULL) {
203 			ktr_alq_failed++;
204 			goto done;
205 		}
206 		ktr_alq_cnt++;
207 		entry = (struct ktr_entry *)ale->ae_data;
208 	} else
209 		goto done;
210 #else
211 	do {
212 		saveindex = ktr_idx;
213 		newindex = (saveindex + 1) & (KTR_ENTRIES - 1);
214 	} while (atomic_cmpset_rel_int(&ktr_idx, saveindex, newindex) == 0);
215 	entry = &ktr_buf[saveindex];
216 #endif
217 	entry->ktr_timestamp = KTR_TIME;
218 	entry->ktr_cpu = cpu;
219 	entry->ktr_file = file;
220 	entry->ktr_line = line;
221 #ifdef KTR_VERBOSE
222 	if (ktr_verbose) {
223 #ifdef SMP
224 		printf("cpu%d ", cpu);
225 #endif
226 		if (ktr_verbose > 1) {
227 			printf("%s.%d\t", entry->ktr_file,
228 			    entry->ktr_line);
229 		}
230 		printf(format, arg1, arg2, arg3, arg4, arg5, arg6);
231 		printf("\n");
232 	}
233 #endif
234 	entry->ktr_desc = format;
235 	entry->ktr_parms[0] = arg1;
236 	entry->ktr_parms[1] = arg2;
237 	entry->ktr_parms[2] = arg3;
238 	entry->ktr_parms[3] = arg4;
239 	entry->ktr_parms[4] = arg5;
240 	entry->ktr_parms[5] = arg6;
241 #ifdef KTR_ALQ
242 	if (ale)
243 		alq_post(ktr_alq, ale);
244 done:
245 #endif
246 #if defined(KTR_VERBOSE) || defined(KTR_ALQ)
247 	td->td_inktr--;
248 #endif
249 }
250 
251 #ifdef DDB
252 
253 struct tstate {
254 	int	cur;
255 	int	first;
256 };
257 static	struct tstate tstate;
258 static	int db_ktr_verbose;
259 static	int db_mach_vtrace(void);
260 
261 #define	NUM_LINES_PER_PAGE	18
262 
263 DB_SHOW_COMMAND(ktr, db_ktr_all)
264 {
265 	int	c, lines;
266 
267 	lines = NUM_LINES_PER_PAGE;
268 	tstate.cur = (ktr_idx - 1) & (KTR_ENTRIES - 1);
269 	tstate.first = -1;
270 	if (strcmp(modif, "v") == 0)
271 		db_ktr_verbose = 1;
272 	else
273 		db_ktr_verbose = 0;
274 	while (db_mach_vtrace())
275 		if (--lines == 0) {
276 			db_printf("--More--");
277 			c = cngetc();
278 			db_printf("\r");
279 			switch (c) {
280 			case '\n':	/* one more line */
281 				lines = 1;
282 				break;
283 			case ' ':	/* one more page */
284 				lines = NUM_LINES_PER_PAGE;
285 				break;
286 			default:
287 				db_printf("\n");
288 				return;
289 			}
290 		}
291 }
292 
293 static int
294 db_mach_vtrace(void)
295 {
296 	struct ktr_entry	*kp;
297 
298 	if (tstate.cur == tstate.first) {
299 		db_printf("--- End of trace buffer ---\n");
300 		return (0);
301 	}
302 	kp = &ktr_buf[tstate.cur];
303 
304 	/* Skip over unused entries. */
305 	if (kp->ktr_desc == NULL) {
306 		db_printf("--- End of trace buffer ---\n");
307 		return (0);
308 	}
309 	db_printf("%d: ", tstate.cur);
310 #ifdef SMP
311 	db_printf("cpu%d ", kp->ktr_cpu);
312 #endif
313 	if (db_ktr_verbose) {
314 		db_printf("%10.10lld %s.%d\t", (long long)kp->ktr_timestamp,
315 		    kp->ktr_file, kp->ktr_line);
316 	}
317 	db_printf(kp->ktr_desc, kp->ktr_parms[0], kp->ktr_parms[1],
318 	    kp->ktr_parms[2], kp->ktr_parms[3], kp->ktr_parms[4],
319 	    kp->ktr_parms[5]);
320 	db_printf("\n");
321 
322 	if (tstate.first == -1)
323 		tstate.first = tstate.cur;
324 
325 	if (--tstate.cur < 0)
326 		tstate.cur = KTR_ENTRIES - 1;
327 
328 	return (1);
329 }
330 
331 #endif	/* DDB */
332