1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2005 Antoine Brodin 5 * All rights reserved. 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 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include "opt_ddb.h" 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <sys/kernel.h> 36 #ifdef KTR 37 #include <sys/ktr.h> 38 #endif 39 #include <sys/linker.h> 40 #include <sys/malloc.h> 41 #include <sys/sbuf.h> 42 #include <sys/stack.h> 43 #include <sys/systm.h> 44 #include <sys/sysctl.h> 45 46 FEATURE(stack, "Support for capturing kernel stack"); 47 48 static MALLOC_DEFINE(M_STACK, "stack", "Stack Traces"); 49 50 static int stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, 51 long *offset); 52 static int stack_symbol_ddb(vm_offset_t pc, const char **name, long *offset); 53 54 struct stack * 55 stack_create(int flags) 56 { 57 struct stack *st; 58 59 st = malloc(sizeof(*st), M_STACK, flags | M_ZERO); 60 return (st); 61 } 62 63 void 64 stack_destroy(struct stack *st) 65 { 66 67 free(st, M_STACK); 68 } 69 70 int 71 stack_put(struct stack *st, vm_offset_t pc) 72 { 73 74 if (st->depth < STACK_MAX) { 75 st->pcs[st->depth++] = pc; 76 return (0); 77 } else 78 return (-1); 79 } 80 81 void 82 stack_copy(const struct stack *src, struct stack *dst) 83 { 84 85 *dst = *src; 86 } 87 88 void 89 stack_zero(struct stack *st) 90 { 91 92 bzero(st, sizeof *st); 93 } 94 95 void 96 stack_print(const struct stack *st) 97 { 98 char namebuf[64]; 99 long offset; 100 int i; 101 102 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 103 for (i = 0; i < st->depth; i++) { 104 (void)stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), 105 &offset); 106 printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 107 namebuf, offset); 108 } 109 } 110 111 void 112 stack_print_short(const struct stack *st) 113 { 114 char namebuf[64]; 115 long offset; 116 int i; 117 118 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 119 for (i = 0; i < st->depth; i++) { 120 if (i > 0) 121 printf(" "); 122 if (stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), 123 &offset) == 0) 124 printf("%s+%#lx", namebuf, offset); 125 else 126 printf("%p", (void *)st->pcs[i]); 127 } 128 printf("\n"); 129 } 130 131 void 132 stack_print_ddb(const struct stack *st) 133 { 134 const char *name; 135 long offset; 136 int i; 137 138 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 139 for (i = 0; i < st->depth; i++) { 140 stack_symbol_ddb(st->pcs[i], &name, &offset); 141 printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 142 name, offset); 143 } 144 } 145 146 #if defined(DDB) || defined(WITNESS) 147 void 148 stack_print_short_ddb(const struct stack *st) 149 { 150 const char *name; 151 long offset; 152 int i; 153 154 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 155 for (i = 0; i < st->depth; i++) { 156 if (i > 0) 157 printf(" "); 158 if (stack_symbol_ddb(st->pcs[i], &name, &offset) == 0) 159 printf("%s+%#lx", name, offset); 160 else 161 printf("%p", (void *)st->pcs[i]); 162 } 163 printf("\n"); 164 } 165 #endif 166 167 /* 168 * Two print routines -- one for use from DDB and DDB-like contexts, the 169 * other for use in the live kernel. 170 */ 171 void 172 stack_sbuf_print(struct sbuf *sb, const struct stack *st) 173 { 174 char namebuf[64]; 175 long offset; 176 int i; 177 178 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 179 for (i = 0; i < st->depth; i++) { 180 (void)stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), 181 &offset); 182 sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 183 namebuf, offset); 184 } 185 } 186 187 #if defined(DDB) || defined(WITNESS) 188 void 189 stack_sbuf_print_ddb(struct sbuf *sb, const struct stack *st) 190 { 191 const char *name; 192 long offset; 193 int i; 194 195 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 196 for (i = 0; i < st->depth; i++) { 197 (void)stack_symbol_ddb(st->pcs[i], &name, &offset); 198 sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 199 name, offset); 200 } 201 } 202 #endif 203 204 #ifdef KTR 205 void 206 stack_ktr(u_int mask, const char *file, int line, const struct stack *st, 207 u_int depth, int cheap) 208 { 209 #ifdef DDB 210 const char *name; 211 long offset; 212 int i; 213 #endif 214 215 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 216 if (cheap) { 217 ktr_tracepoint(mask, file, line, "#0 %p %p %p %p %p %p", 218 st->pcs[0], st->pcs[1], st->pcs[2], st->pcs[3], 219 st->pcs[4], st->pcs[5]); 220 if (st->depth <= 6) 221 return; 222 ktr_tracepoint(mask, file, line, "#1 %p %p %p %p %p %p", 223 st->pcs[6], st->pcs[7], st->pcs[8], st->pcs[9], 224 st->pcs[10], st->pcs[11]); 225 if (st->depth <= 12) 226 return; 227 ktr_tracepoint(mask, file, line, "#2 %p %p %p %p %p %p", 228 st->pcs[12], st->pcs[13], st->pcs[14], st->pcs[15], 229 st->pcs[16], st->pcs[17]); 230 #ifdef DDB 231 } else { 232 if (depth == 0 || st->depth < depth) 233 depth = st->depth; 234 for (i = 0; i < depth; i++) { 235 (void)stack_symbol_ddb(st->pcs[i], &name, &offset); 236 ktr_tracepoint(mask, file, line, "#%d %p at %s+%#lx", 237 i, st->pcs[i], (u_long)name, offset, 0, 0); 238 } 239 #endif 240 } 241 } 242 #endif 243 244 /* 245 * Two variants of stack symbol lookup -- one that uses the DDB interfaces 246 * and bypasses linker locking, and the other that doesn't. 247 */ 248 static int 249 stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, long *offset) 250 { 251 252 if (linker_search_symbol_name((caddr_t)pc, namebuf, buflen, 253 offset) != 0) { 254 *offset = 0; 255 strlcpy(namebuf, "??", buflen); 256 return (ENOENT); 257 } else 258 return (0); 259 } 260 261 static int 262 stack_symbol_ddb(vm_offset_t pc, const char **name, long *offset) 263 { 264 linker_symval_t symval; 265 c_linker_sym_t sym; 266 267 if (linker_ddb_search_symbol((caddr_t)pc, &sym, offset) != 0) 268 goto out; 269 if (linker_ddb_symbol_values(sym, &symval) != 0) 270 goto out; 271 if (symval.name != NULL) { 272 *name = symval.name; 273 return (0); 274 } 275 out: 276 *offset = 0; 277 *name = "??"; 278 return (ENOENT); 279 } 280