1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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/param.h> 32 #include <sys/kernel.h> 33 #ifdef KTR 34 #include <sys/ktr.h> 35 #endif 36 #include <sys/linker.h> 37 #include <sys/malloc.h> 38 #include <sys/sbuf.h> 39 #include <sys/stack.h> 40 #include <sys/systm.h> 41 #include <sys/sysctl.h> 42 43 FEATURE(stack, "Support for capturing kernel stack"); 44 45 MALLOC_DEFINE(M_STACK, "stack", "Stack Traces"); 46 47 static int stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, 48 long *offset, int flags); 49 static int stack_symbol_ddb(vm_offset_t pc, const char **name, long *offset); 50 51 struct stack * 52 stack_create(int flags) 53 { 54 struct stack *st; 55 56 st = malloc(sizeof(*st), M_STACK, flags | M_ZERO); 57 return (st); 58 } 59 60 void 61 stack_destroy(struct stack *st) 62 { 63 64 free(st, M_STACK); 65 } 66 67 int 68 stack_put(struct stack *st, vm_offset_t pc) 69 { 70 71 if (st->depth < STACK_MAX) { 72 st->pcs[st->depth++] = pc; 73 return (0); 74 } else 75 return (-1); 76 } 77 78 void 79 stack_copy(const struct stack *src, struct stack *dst) 80 { 81 82 *dst = *src; 83 } 84 85 void 86 stack_zero(struct stack *st) 87 { 88 89 bzero(st, sizeof *st); 90 } 91 92 void 93 stack_print(const struct stack *st) 94 { 95 char namebuf[64]; 96 long offset; 97 int i; 98 99 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 100 for (i = 0; i < st->depth; i++) { 101 (void)stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), 102 &offset, M_WAITOK); 103 printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 104 namebuf, offset); 105 } 106 } 107 108 void 109 stack_print_short(const struct stack *st) 110 { 111 char namebuf[64]; 112 long offset; 113 int i; 114 115 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 116 for (i = 0; i < st->depth; i++) { 117 if (i > 0) 118 printf(" "); 119 if (stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), 120 &offset, M_WAITOK) == 0) 121 printf("%s+%#lx", namebuf, offset); 122 else 123 printf("%p", (void *)st->pcs[i]); 124 } 125 printf("\n"); 126 } 127 128 void 129 stack_print_ddb(const struct stack *st) 130 { 131 const char *name; 132 long offset; 133 int i; 134 135 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 136 for (i = 0; i < st->depth; i++) { 137 stack_symbol_ddb(st->pcs[i], &name, &offset); 138 printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 139 name, offset); 140 } 141 } 142 143 #if defined(DDB) || defined(WITNESS) 144 void 145 stack_print_short_ddb(const struct stack *st) 146 { 147 const char *name; 148 long offset; 149 int i; 150 151 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 152 for (i = 0; i < st->depth; i++) { 153 if (i > 0) 154 printf(" "); 155 if (stack_symbol_ddb(st->pcs[i], &name, &offset) == 0) 156 printf("%s+%#lx", name, offset); 157 else 158 printf("%p", (void *)st->pcs[i]); 159 } 160 printf("\n"); 161 } 162 #endif 163 164 /* 165 * Format stack into sbuf from live kernel. 166 * 167 * flags - M_WAITOK or M_NOWAIT (EWOULDBLOCK). 168 */ 169 int 170 stack_sbuf_print_flags(struct sbuf *sb, const struct stack *st, int flags, 171 enum stack_sbuf_fmt format) 172 { 173 char namebuf[64]; 174 long offset; 175 int i, error; 176 177 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 178 for (i = 0; i < st->depth; i++) { 179 error = stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), 180 &offset, flags); 181 if (error == EWOULDBLOCK) 182 return (error); 183 switch (format) { 184 case STACK_SBUF_FMT_LONG: 185 sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, 186 (void *)st->pcs[i], namebuf, offset); 187 break; 188 case STACK_SBUF_FMT_COMPACT: 189 sbuf_printf(sb, "%s+%#lx ", namebuf, offset); 190 break; 191 default: 192 __assert_unreachable(); 193 } 194 } 195 sbuf_nl_terminate(sb); 196 return (0); 197 } 198 199 void 200 stack_sbuf_print(struct sbuf *sb, const struct stack *st) 201 { 202 203 (void)stack_sbuf_print_flags(sb, st, M_WAITOK, STACK_SBUF_FMT_LONG); 204 } 205 206 #if defined(DDB) || defined(WITNESS) 207 void 208 stack_sbuf_print_ddb(struct sbuf *sb, const struct stack *st) 209 { 210 const char *name; 211 long offset; 212 int i; 213 214 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 215 for (i = 0; i < st->depth; i++) { 216 (void)stack_symbol_ddb(st->pcs[i], &name, &offset); 217 sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 218 name, offset); 219 } 220 } 221 #endif 222 223 #ifdef KTR 224 void 225 stack_ktr(u_int mask, const char *file, int line, const struct stack *st, 226 u_int depth) 227 { 228 #ifdef DDB 229 const char *name; 230 long offset; 231 int i; 232 #endif 233 234 KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 235 #ifdef DDB 236 if (depth == 0 || st->depth < depth) 237 depth = st->depth; 238 for (i = 0; i < depth; i++) { 239 (void)stack_symbol_ddb(st->pcs[i], &name, &offset); 240 ktr_tracepoint(mask, file, line, "#%d %p at %s+%#lx", 241 i, st->pcs[i], (u_long)name, offset, 0, 0); 242 } 243 #endif 244 } 245 #endif 246 247 /* 248 * Two variants of stack symbol lookup -- one that uses the DDB interfaces 249 * and bypasses linker locking, and the other that doesn't. 250 */ 251 static int 252 stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, long *offset, 253 int flags) 254 { 255 int error; 256 257 error = linker_search_symbol_name_flags((caddr_t)pc, namebuf, buflen, 258 offset, flags); 259 if (error == 0 || error == EWOULDBLOCK) 260 return (error); 261 262 *offset = 0; 263 strlcpy(namebuf, "??", buflen); 264 return (ENOENT); 265 } 266 267 static int 268 stack_symbol_ddb(vm_offset_t pc, const char **name, long *offset) 269 { 270 linker_symval_t symval; 271 c_linker_sym_t sym; 272 273 if (linker_ddb_search_symbol((caddr_t)pc, &sym, offset) != 0) 274 goto out; 275 if (linker_ddb_symbol_values(sym, &symval) != 0) 276 goto out; 277 if (symval.name != NULL) { 278 *name = symval.name; 279 return (0); 280 } 281 out: 282 *offset = 0; 283 *name = "??"; 284 return (ENOENT); 285 } 286