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 */ 342