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