Add a caller backtrace feature (enabled by default), which records part of
[dragonfly.git] / sys / kern / kern_ktr.c
1 /*
2  * Copyright (c) 2005 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 /*
35  * The following copyright applies to the DDB command code:
36  *
37  * Copyright (c) 2000 John Baldwin <jhb@FreeBSD.org>
38  * All rights reserved.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  *    notice, this list of conditions and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  *    notice, this list of conditions and the following disclaimer in the
47  *    documentation and/or other materials provided with the distribution.
48  * 3. Neither the name of the author nor the names of any co-contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  */
64 /*
65  * $DragonFly: src/sys/kern/kern_ktr.c,v 1.6 2005/06/20 20:37:24 dillon Exp $
66  */
67 /*
68  * Kernel tracepoint facility.
69  */
70
71 #include "opt_ddb.h"
72 #include "opt_ktr.h"
73
74 #include <sys/param.h>
75 #include <sys/cons.h>
76 #include <sys/kernel.h>
77 #include <sys/libkern.h>
78 #include <sys/proc.h>
79 #include <sys/sysctl.h>
80 #include <sys/ktr.h>
81 #include <sys/systm.h>
82 #include <sys/time.h>
83 #include <sys/malloc.h>
84 #include <sys/thread2.h>
85 #include <sys/ctype.h>
86
87 #include <machine/cpu.h>
88 #include <machine/cpufunc.h>
89 #include <machine/specialreg.h>
90 #include <machine/md_var.h>
91
92 #include <ddb/ddb.h>
93
94 #ifndef KTR_ENTRIES
95 #define KTR_ENTRIES             2048
96 #endif
97 #define KTR_ENTRIES_MASK        (KTR_ENTRIES - 1)
98
99 MALLOC_DEFINE(M_KTR, "ktr", "ktr buffers");
100
101 SYSCTL_NODE(_debug, OID_AUTO, ktr, CTLFLAG_RW, 0, "ktr");
102
103 static int32_t  ktr_cpumask = -1;
104 TUNABLE_INT("debug.ktr.cpumask", &ktr_cpumask);
105 SYSCTL_INT(_debug_ktr, OID_AUTO, cpumask, CTLFLAG_RW, &ktr_cpumask, 0, "");
106
107 static int      ktr_entries = KTR_ENTRIES;
108 SYSCTL_INT(_debug_ktr, OID_AUTO, entries, CTLFLAG_RD, &ktr_entries, 0, "");
109
110 static int      ktr_version = KTR_VERSION;
111 SYSCTL_INT(_debug_ktr, OID_AUTO, version, CTLFLAG_RD, &ktr_version, 0, "");
112
113 static int      ktr_stacktrace = 1;
114 SYSCTL_INT(_debug_ktr, OID_AUTO, stacktrace, CTLFLAG_RD, &ktr_stacktrace, 0, "");
115
116 /*
117  * Give cpu0 a static buffer so the tracepoint facility can be used during
118  * early boot (note however that we still use a critical section, XXX).
119  */
120 static struct   ktr_entry ktr_buf0[KTR_ENTRIES];
121 static struct   ktr_entry *ktr_buf[MAXCPU] = { &ktr_buf0[0] };
122 static int      ktr_idx[MAXCPU];
123
124 #ifdef KTR_VERBOSE
125 int     ktr_verbose = KTR_VERBOSE;
126 TUNABLE_INT("debug.ktr.verbose", &ktr_verbose);
127 SYSCTL_INT(_debug_ktr, OID_AUTO, verbose, CTLFLAG_RW, &ktr_verbose, 0, "");
128 #endif
129
130 static void
131 ktr_sysinit(void *dummy)
132 {
133         int i;
134
135         for(i = 1; i < ncpus; ++i) {
136                 ktr_buf[i] = malloc(KTR_ENTRIES * sizeof(struct ktr_entry),
137                                     M_KTR, M_WAITOK | M_ZERO);
138         }
139 }
140
141 SYSINIT(announce, SI_SUB_INTRINSIC, SI_ORDER_FIRST, ktr_sysinit, NULL);
142
143 static __inline
144 void
145 ktr_write_entry(struct ktr_info *info, const char *file, int line,
146                 const void *ptr)
147 {
148         struct ktr_entry *entry;
149         int cpu;
150
151         cpu = mycpu->gd_cpuid;
152         if (ktr_buf[cpu]) {
153                 crit_enter();
154                 entry = ktr_buf[cpu] + (ktr_idx[cpu] & KTR_ENTRIES_MASK);
155                 ++ktr_idx[cpu];
156                 crit_exit();
157                 if (cpu_feature & CPUID_TSC)
158                         entry->ktr_timestamp = rdtsc();
159                 else
160                         entry->ktr_timestamp = get_approximate_time_t();
161                 entry->ktr_info = info;
162                 entry->ktr_file = file;
163                 entry->ktr_line = line;
164                 if (info->kf_data_size > KTR_BUFSIZE)
165                         bcopyi(ptr, entry->ktr_data, KTR_BUFSIZE);
166                 else
167                         bcopyi(ptr, entry->ktr_data, info->kf_data_size);
168                 if (ktr_stacktrace)
169                         cpu_ktr_caller(entry);
170         }
171 #ifdef KTR_VERBOSE
172         if (ktr_verbose && info->kf_format) {
173 #ifdef SMP
174                 printf("cpu%d ", cpu);
175 #endif
176                 if (ktr_verbose > 1) {
177                         printf("%s.%d\t", entry->ktr_file, entry->ktr_line);
178                 }
179                 vprintf(info->kf_format, ptr);
180                 printf("\n");
181         }
182 #endif
183 }
184
185 void
186 ktr_log(struct ktr_info *info, const char *file, int line, ...)
187 {
188         __va_list va;
189
190         if (panicstr == NULL) {
191                 __va_start(va, line);
192                 ktr_write_entry(info, file, line, va);
193                 __va_end(va);
194         }
195 }
196
197 void
198 ktr_log_ptr(struct ktr_info *info, const char *file, int line, const void *ptr)
199 {
200         if (panicstr == NULL) {
201                 ktr_write_entry(info, file, line, ptr);
202         }
203 }
204
205 #ifdef DDB
206
207 #define NUM_LINES_PER_PAGE      19
208
209 struct tstate {
210         int     cur;
211         int     first;
212 };
213
214 static  int db_ktr_verbose;
215 static  int db_mach_vtrace(int cpu, struct ktr_entry *kp, int idx);
216
217 DB_SHOW_COMMAND(ktr, db_ktr_all)
218 {
219         int a_flag = 0;
220         int c;
221         int nl = 0;
222         int i;
223         struct tstate tstate[MAXCPU];
224         int printcpu = -1;
225
226         for(i = 0; i < ncpus; i++) {
227                 tstate[i].first = -1;
228                 tstate[i].cur = ktr_idx[i] & KTR_ENTRIES_MASK;
229         }
230         db_ktr_verbose = 0;
231         while ((c = *(modif++)) != '\0') {
232                 if (c == 'v') {
233                         db_ktr_verbose = 1;
234                 }
235                 else if (c == 'a') {
236                         a_flag = 1;
237                 }
238                 else if (c == 'c') {
239                         printcpu = 0;
240                         while ((c = *(modif++)) != '\0') {
241                                 if (isdigit(c)) {
242                                         printcpu *= 10;
243                                         printcpu += c - '0';
244                                 }
245                                 else {
246                                         modif++;
247                                         break;
248                                 }
249                         }
250                         modif--;
251                 }
252         }
253         if (printcpu > ncpus - 1) {
254                 db_printf("Invalid cpu number\n");
255                 return;
256         }
257         /*
258          * Lopp throug all the buffers and print the content of them, sorted
259          * by the timestamp.
260          */
261         while (1) {
262                 int counter;
263                 u_int64_t highest_ts;
264                 int highest_cpu;
265                 struct ktr_entry *kp;
266
267                 if (a_flag == 1 && cncheckc() != -1)
268                         return;
269                 highest_ts = 0;
270                 highest_cpu = -1;
271                 /*
272                  * Find the lowest timestamp
273                  */
274                 for (i = 0, counter = 0; i < ncpus; i++) {
275                         if (ktr_buf[i] == NULL)
276                                 continue;
277                         if (printcpu != -1 && printcpu != i)
278                                 continue;
279                         if (tstate[i].cur == -1) {
280                                 counter++;
281                                 if (counter == ncpus) {
282                                         db_printf("--- End of trace buffer ---\n");
283                                         return;
284                                 }
285                                 continue;
286                         }
287                         if (ktr_buf[i][tstate[i].cur].ktr_timestamp > highest_ts) {
288                                 highest_ts = ktr_buf[i][tstate[i].cur].ktr_timestamp;
289                                 highest_cpu = i;
290                         }
291                 }
292                 i = highest_cpu;
293                 KKASSERT(i != -1);
294                 kp = &ktr_buf[i][tstate[i].cur];
295                 if (tstate[i].first == -1)
296                         tstate[i].first = tstate[i].cur;
297                 if (--tstate[i].cur < 0)
298                         tstate[i].cur = KTR_ENTRIES - 1;
299                 if (tstate[i].first == tstate[i].cur) {
300                         db_mach_vtrace(i, kp, tstate[i].cur + 1);
301                         tstate[i].cur = -1;
302                         continue;
303                 }
304                 if (ktr_buf[i][tstate[i].cur].ktr_info == NULL)
305                         tstate[i].cur = -1;
306                 if (db_more(&nl) == -1)
307                         break;
308                 if (db_mach_vtrace(i, kp, tstate[i].cur + 1) == 0)
309                         tstate[i].cur = -1;
310         }
311 }
312
313 static int
314 db_mach_vtrace(int cpu, struct ktr_entry *kp, int idx)
315 {
316         if (kp->ktr_info == NULL)
317                 return(0);
318 #ifdef SMP
319         db_printf("cpu%d ", cpu);
320 #endif
321         db_printf("%d: ", idx);
322         if (db_ktr_verbose) {
323                 db_printf("%10.10lld %s.%d\t", (long long)kp->ktr_timestamp,
324                     kp->ktr_file, kp->ktr_line);
325         }
326         db_printf("%s\t", kp->ktr_info->kf_name);
327         db_printf("from(%p,%p) ", kp->ktr_caller1, kp->ktr_caller2);
328         if (kp->ktr_info->kf_format) {
329                 int32_t *args = kp->ktr_data;
330                 db_printf(kp->ktr_info->kf_format,
331                           args[0], args[1], args[2], args[3],
332                           args[4], args[5], args[6], args[7],
333                           args[8], args[9], args[10], args[11]);
334             
335         }
336         db_printf("\n");
337
338         return(1);
339 }
340
341 #endif  /* DDB */