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