5f536af9b619db5416d4f4ccaa862eb25ce6b90f
[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.5 2005/06/20 17:59:32 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 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 int     ktr_entries = KTR_ENTRIES;
108 SYSCTL_INT(_debug_ktr, OID_AUTO, entries, CTLFLAG_RD, &ktr_entries, 0, "");
109
110 int     ktr_version = KTR_VERSION;
111 SYSCTL_INT(_debug_ktr, OID_AUTO, version, CTLFLAG_RD, &ktr_version, 0, "");
112
113 /*
114  * Give cpu0 a static buffer so the tracepoint facility can be used during
115  * early boot (note however that we still use a critical section, XXX).
116  */
117 static struct   ktr_entry ktr_buf0[KTR_ENTRIES];
118 static struct   ktr_entry *ktr_buf[MAXCPU] = { &ktr_buf0[0] };
119 static int      ktr_idx[MAXCPU];
120
121 #ifdef KTR_VERBOSE
122 int     ktr_verbose = KTR_VERBOSE;
123 TUNABLE_INT("debug.ktr.verbose", &ktr_verbose);
124 SYSCTL_INT(_debug_ktr, OID_AUTO, verbose, CTLFLAG_RW, &ktr_verbose, 0, "");
125 #endif
126
127 static void
128 ktr_sysinit(void *dummy)
129 {
130         int i;
131
132         for(i = 1; i < ncpus; ++i) {
133                 ktr_buf[i] = malloc(KTR_ENTRIES * sizeof(struct ktr_entry),
134                                     M_KTR, M_WAITOK | M_ZERO);
135         }
136 }
137
138 SYSINIT(announce, SI_SUB_INTRINSIC, SI_ORDER_FIRST, ktr_sysinit, NULL);
139
140 static __inline
141 void
142 ktr_write_entry(struct ktr_info *info, const char *file, int line,
143                 const void *ptr)
144 {
145         struct ktr_entry *entry;
146         int cpu;
147
148         cpu = mycpu->gd_cpuid;
149         if (ktr_buf[cpu]) {
150                 crit_enter();
151                 entry = ktr_buf[cpu] + (ktr_idx[cpu] & KTR_ENTRIES_MASK);
152                 ++ktr_idx[cpu];
153                 crit_exit();
154                 if (cpu_feature & CPUID_TSC)
155                         entry->ktr_timestamp = rdtsc();
156                 else
157                         entry->ktr_timestamp = get_approximate_time_t();
158                 entry->ktr_info = info;
159                 entry->ktr_file = file;
160                 entry->ktr_line = line;
161                 if (info->kf_data_size > KTR_BUFSIZE)
162                         bcopyi(ptr, entry->ktr_data, KTR_BUFSIZE);
163                 else
164                         bcopyi(ptr, entry->ktr_data, info->kf_data_size);
165         }
166 #ifdef KTR_VERBOSE
167         if (ktr_verbose && info->kf_format) {
168 #ifdef SMP
169                 printf("cpu%d ", cpu);
170 #endif
171                 if (ktr_verbose > 1) {
172                         printf("%s.%d\t", entry->ktr_file, entry->ktr_line);
173                 }
174                 vprintf(info->kf_format, ptr);
175                 printf("\n");
176         }
177 #endif
178 }
179
180 void
181 ktr_log(struct ktr_info *info, const char *file, int line, ...)
182 {
183         __va_list va;
184
185         __va_start(va, line);
186         ktr_write_entry(info, file, line, va);
187         __va_end(va);
188 }
189
190 void
191 ktr_log_ptr(struct ktr_info *info, const char *file, int line, const void *ptr)
192 {
193         ktr_write_entry(info, file, line, ptr);
194 }
195
196 #ifdef DDB
197
198 #define NUM_LINES_PER_PAGE      19
199
200 struct tstate {
201         int     cur;
202         int     first;
203 };
204
205 static  int db_ktr_verbose;
206 static  int db_mach_vtrace(int cpu, struct ktr_entry *kp, int idx);
207
208 DB_SHOW_COMMAND(ktr, db_ktr_all)
209 {
210         int a_flag = 0;
211         int c;
212         int nl = 0;
213         int i;
214         struct tstate tstate[MAXCPU];
215         int printcpu = -1;
216
217         for(i = 0; i < ncpus; i++) {
218                 tstate[i].first = -1;
219                 tstate[i].cur = ktr_idx[i] & KTR_ENTRIES_MASK;
220         }
221         db_ktr_verbose = 0;
222         while ((c = *(modif++)) != '\0') {
223                 if (c == 'v') {
224                         db_ktr_verbose = 1;
225                 }
226                 else if (c == 'a') {
227                         a_flag = 1;
228                 }
229                 else if (c == 'c') {
230                         printcpu = 0;
231                         while ((c = *(modif++)) != '\0') {
232                                 if (isdigit(c)) {
233                                         printcpu *= 10;
234                                         printcpu += c - '0';
235                                 }
236                                 else {
237                                         modif++;
238                                         break;
239                                 }
240                         }
241                         modif--;
242                 }
243         }
244         if (printcpu > ncpus - 1) {
245                 db_printf("Invalid cpu number\n");
246                 return;
247         }
248         /*
249          * Lopp throug all the buffers and print the content of them, sorted
250          * by the timestamp.
251          */
252         while (1) {
253                 int counter;
254                 u_int64_t highest_ts;
255                 int highest_cpu;
256                 struct ktr_entry *kp;
257
258                 if (a_flag == 1 && cncheckc() != -1)
259                         return;
260                 highest_ts = 0;
261                 highest_cpu = -1;
262                 /*
263                  * Find the lowest timestamp
264                  */
265                 for (i = 0, counter = 0; i < ncpus; i++) {
266                         if (ktr_buf[i] == NULL)
267                                 continue;
268                         if (printcpu != -1 && printcpu != i)
269                                 continue;
270                         if (tstate[i].cur == -1) {
271                                 counter++;
272                                 if (counter == ncpus) {
273                                         db_printf("--- End of trace buffer ---\n");
274                                         return;
275                                 }
276                                 continue;
277                         }
278                         if (ktr_buf[i][tstate[i].cur].ktr_timestamp > highest_ts) {
279                                 highest_ts = ktr_buf[i][tstate[i].cur].ktr_timestamp;
280                                 highest_cpu = i;
281                         }
282                 }
283                 i = highest_cpu;
284                 KKASSERT(i != -1);
285                 kp = &ktr_buf[i][tstate[i].cur];
286                 if (tstate[i].first == -1)
287                         tstate[i].first = tstate[i].cur;
288                 if (--tstate[i].cur < 0)
289                         tstate[i].cur = KTR_ENTRIES - 1;
290                 if (tstate[i].first == tstate[i].cur) {
291                         db_mach_vtrace(i, kp, tstate[i].cur + 1);
292                         tstate[i].cur = -1;
293                         continue;
294                 }
295                 if (ktr_buf[i][tstate[i].cur].ktr_info == NULL)
296                         tstate[i].cur = -1;
297                 if (db_more(&nl) == -1)
298                         break;
299                 if (db_mach_vtrace(i, kp, tstate[i].cur + 1) == 0)
300                         tstate[i].cur = -1;
301         }
302 }
303
304 static int
305 db_mach_vtrace(int cpu, struct ktr_entry *kp, int idx)
306 {
307         if (kp->ktr_info == NULL)
308                 return(0);
309 #ifdef SMP
310         db_printf("cpu%d ", cpu);
311 #endif
312         db_printf("%d: ", idx);
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("%s\t", kp->ktr_info->kf_name);
318         if (kp->ktr_info->kf_format) {
319                 int32_t *args = (int32_t *)kp->ktr_data;
320                 db_printf(kp->ktr_info->kf_format,
321                           args[0], args[1], args[2], args[3],
322                           args[4], args[5], args[6], args[7],
323                           args[8], args[9], args[10], args[11]);
324             
325         }
326         db_printf("\n");
327
328         return(1);
329 }
330
331 #endif  /* DDB */