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, int flags); 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, M_WAITOK); 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, M_WAITOK) == 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 * Format stack into sbuf from live kernel. 169 * 170 * flags - M_WAITOK or M_NOWAIT (EWOULDBLOCK). 171 */ 172 int 173 stack_sbuf_print_flags(struct sbuf *sb, const struct stack *st, int flags) 174 { 175 char namebuf[64]; 176 long offset; 177 int i, error; 178 179 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 180 for (i = 0; i < st->depth; i++) { 181 error = stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), 182 &offset, flags); 183 if (error == EWOULDBLOCK) 184 return (error); 185 sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 186 namebuf, offset); 187 } 188 return (0); 189 } 190 191 void 192 stack_sbuf_print(struct sbuf *sb, const struct stack *st) 193 { 194 195 (void)stack_sbuf_print_flags(sb, st, M_WAITOK); 196 } 197 198 #if defined(DDB) || defined(WITNESS) 199 void 200 stack_sbuf_print_ddb(struct sbuf *sb, const struct stack *st) 201 { 202 const char *name; 203 long offset; 204 int i; 205 206 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 207 for (i = 0; i < st->depth; i++) { 208 (void)stack_symbol_ddb(st->pcs[i], &name, &offset); 209 sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 210 name, offset); 211 } 212 } 213 #endif 214 215 #ifdef KTR 216 void 217 stack_ktr(u_int mask, const char *file, int line, const struct stack *st, 218 u_int depth, int cheap) 219 { 220 #ifdef DDB 221 const char *name; 222 long offset; 223 int i; 224 #endif 225 226 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 227 if (cheap) { 228 ktr_tracepoint(mask, file, line, "#0 %p %p %p %p %p %p", 229 st->pcs[0], st->pcs[1], st->pcs[2], st->pcs[3], 230 st->pcs[4], st->pcs[5]); 231 if (st->depth <= 6) 232 return; 233 ktr_tracepoint(mask, file, line, "#1 %p %p %p %p %p %p", 234 st->pcs[6], st->pcs[7], st->pcs[8], st->pcs[9], 235 st->pcs[10], st->pcs[11]); 236 if (st->depth <= 12) 237 return; 238 ktr_tracepoint(mask, file, line, "#2 %p %p %p %p %p %p", 239 st->pcs[12], st->pcs[13], st->pcs[14], st->pcs[15], 240 st->pcs[16], st->pcs[17]); 241 #ifdef DDB 242 } else { 243 if (depth == 0 || st->depth < depth) 244 depth = st->depth; 245 for (i = 0; i < depth; i++) { 246 (void)stack_symbol_ddb(st->pcs[i], &name, &offset); 247 ktr_tracepoint(mask, file, line, "#%d %p at %s+%#lx", 248 i, st->pcs[i], (u_long)name, offset, 0, 0); 249 } 250 #endif 251 } 252 } 253 #endif 254 255 /* 256 * Two variants of stack symbol lookup -- one that uses the DDB interfaces 257 * and bypasses linker locking, and the other that doesn't. 258 */ 259 static int 260 stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, long *offset, 261 int flags) 262 { 263 int error; 264 265 error = linker_search_symbol_name_flags((caddr_t)pc, namebuf, buflen, 266 offset, flags); 267 if (error == 0 || error == EWOULDBLOCK) 268 return (error); 269 270 *offset = 0; 271 strlcpy(namebuf, "??", buflen); 272 return (ENOENT); 273 } 274 275 static int 276 stack_symbol_ddb(vm_offset_t pc, const char **name, long *offset) 277 { 278 linker_symval_t symval; 279 c_linker_sym_t sym; 280 281 if (linker_ddb_search_symbol((caddr_t)pc, &sym, offset) != 0) 282 goto out; 283 if (linker_ddb_symbol_values(sym, &symval) != 0) 284 goto out; 285 if (symval.name != NULL) { 286 *name = symval.name; 287 return (0); 288 } 289 out: 290 *offset = 0; 291 *name = "??"; 292 return (ENOENT); 293 } 294