subr_stack.c revision 212994
1148666Sjeff/*- 2148666Sjeff * Copyright (c) 2005 Antoine Brodin 3148666Sjeff * All rights reserved. 4148666Sjeff * 5148666Sjeff * Redistribution and use in source and binary forms, with or without 6148666Sjeff * modification, are permitted provided that the following conditions 7148666Sjeff * are met: 8148666Sjeff * 1. Redistributions of source code must retain the above copyright 9148666Sjeff * notice, this list of conditions and the following disclaimer. 10148666Sjeff * 2. Redistributions in binary form must reproduce the above copyright 11148666Sjeff * notice, this list of conditions and the following disclaimer in the 12148666Sjeff * documentation and/or other materials provided with the distribution. 13148666Sjeff * 14148666Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15148666Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16148666Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17148666Sjeff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18148666Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19148666Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20148666Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21148666Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22148666Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23148666Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24148666Sjeff * SUCH DAMAGE. 25148666Sjeff */ 26148666Sjeff 27174137Srwatson#include "opt_ddb.h" 28174137Srwatson 29148666Sjeff#include <sys/cdefs.h> 30148666Sjeff__FBSDID("$FreeBSD: head/sys/kern/subr_stack.c 212994 2010-09-22 06:45:07Z avg $"); 31148666Sjeff 32148666Sjeff#include <sys/param.h> 33148666Sjeff#include <sys/kernel.h> 34148666Sjeff#ifdef KTR 35148666Sjeff#include <sys/ktr.h> 36148666Sjeff#endif 37148666Sjeff#include <sys/linker.h> 38148666Sjeff#include <sys/malloc.h> 39148666Sjeff#include <sys/sbuf.h> 40148666Sjeff#include <sys/stack.h> 41148666Sjeff#include <sys/systm.h> 42148666Sjeff 43180495Santoinestatic MALLOC_DEFINE(M_STACK, "stack", "Stack Traces"); 44148666Sjeff 45194828Srwatsonstatic int stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, 46174137Srwatson long *offset); 47194828Srwatsonstatic int stack_symbol_ddb(vm_offset_t pc, const char **name, long *offset); 48148666Sjeff 49148666Sjeffstruct stack * 50148666Sjeffstack_create(void) 51148666Sjeff{ 52148666Sjeff struct stack *st; 53148666Sjeff 54148666Sjeff st = malloc(sizeof *st, M_STACK, M_WAITOK | M_ZERO); 55148666Sjeff return (st); 56148666Sjeff} 57148666Sjeff 58148666Sjeffvoid 59148666Sjeffstack_destroy(struct stack *st) 60148666Sjeff{ 61148666Sjeff 62148666Sjeff free(st, M_STACK); 63148666Sjeff} 64148666Sjeff 65148666Sjeffint 66148666Sjeffstack_put(struct stack *st, vm_offset_t pc) 67148666Sjeff{ 68148666Sjeff 69148666Sjeff if (st->depth < STACK_MAX) { 70148666Sjeff st->pcs[st->depth++] = pc; 71148666Sjeff return (0); 72148666Sjeff } else 73148666Sjeff return (-1); 74148666Sjeff} 75148666Sjeff 76148666Sjeffvoid 77148666Sjeffstack_copy(struct stack *src, struct stack *dst) 78148666Sjeff{ 79148666Sjeff 80148666Sjeff *dst = *src; 81148666Sjeff} 82148666Sjeff 83148666Sjeffvoid 84148666Sjeffstack_zero(struct stack *st) 85148666Sjeff{ 86148666Sjeff 87148666Sjeff bzero(st, sizeof *st); 88148666Sjeff} 89148666Sjeff 90148666Sjeffvoid 91148666Sjeffstack_print(struct stack *st) 92148666Sjeff{ 93174137Srwatson char namebuf[64]; 94148666Sjeff long offset; 95148666Sjeff int i; 96148666Sjeff 97159022Skris KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 98148666Sjeff for (i = 0; i < st->depth; i++) { 99194828Srwatson (void)stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), 100194828Srwatson &offset); 101148666Sjeff printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 102174137Srwatson namebuf, offset); 103148666Sjeff } 104148666Sjeff} 105148666Sjeff 106194828Srwatsonvoid 107194828Srwatsonstack_print_short(struct stack *st) 108194828Srwatson{ 109194828Srwatson char namebuf[64]; 110194828Srwatson long offset; 111194828Srwatson int i; 112194828Srwatson 113194828Srwatson KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 114194828Srwatson for (i = 0; i < st->depth; i++) { 115194828Srwatson if (i > 0) 116194828Srwatson printf(" "); 117194828Srwatson if (stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), 118194828Srwatson &offset) == 0) 119194828Srwatson printf("%s+%#lx", namebuf, offset); 120194828Srwatson else 121194828Srwatson printf("%p", (void *)st->pcs[i]); 122194828Srwatson } 123194828Srwatson printf("\n"); 124194828Srwatson} 125194828Srwatson 126148666Sjeffvoid 127174137Srwatsonstack_print_ddb(struct stack *st) 128174137Srwatson{ 129184060Skib const char *name; 130174137Srwatson long offset; 131174137Srwatson int i; 132174137Srwatson 133174137Srwatson KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 134174137Srwatson for (i = 0; i < st->depth; i++) { 135184060Skib stack_symbol_ddb(st->pcs[i], &name, &offset); 136174137Srwatson printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 137184060Skib name, offset); 138174137Srwatson } 139174137Srwatson} 140194828Srwatson 141212994Savg#ifdef DDB 142194828Srwatsonvoid 143194828Srwatsonstack_print_short_ddb(struct stack *st) 144194828Srwatson{ 145194828Srwatson const char *name; 146194828Srwatson long offset; 147194828Srwatson int i; 148194828Srwatson 149194828Srwatson KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 150194828Srwatson for (i = 0; i < st->depth; i++) { 151194828Srwatson if (i > 0) 152194828Srwatson printf(" "); 153194828Srwatson if (stack_symbol_ddb(st->pcs[i], &name, &offset) == 0) 154194828Srwatson printf("%s+%#lx", name, offset); 155194828Srwatson else 156194828Srwatson printf("%p", (void *)st->pcs[i]); 157194828Srwatson } 158194828Srwatson printf("\n"); 159194828Srwatson} 160174195Srwatson#endif 161174137Srwatson 162174137Srwatson/* 163174137Srwatson * Two print routines -- one for use from DDB and DDB-like contexts, the 164174137Srwatson * other for use in the live kernel. 165174137Srwatson */ 166174137Srwatsonvoid 167148666Sjeffstack_sbuf_print(struct sbuf *sb, struct stack *st) 168148666Sjeff{ 169174137Srwatson char namebuf[64]; 170148666Sjeff long offset; 171148666Sjeff int i; 172148666Sjeff 173159022Skris KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 174148666Sjeff for (i = 0; i < st->depth; i++) { 175194828Srwatson (void)stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), 176194828Srwatson &offset); 177148666Sjeff sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 178174137Srwatson namebuf, offset); 179148666Sjeff } 180148666Sjeff} 181148666Sjeff 182174137Srwatson#ifdef DDB 183174137Srwatsonvoid 184174137Srwatsonstack_sbuf_print_ddb(struct sbuf *sb, struct stack *st) 185174137Srwatson{ 186184060Skib const char *name; 187174137Srwatson long offset; 188174137Srwatson int i; 189174137Srwatson 190174137Srwatson KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 191174137Srwatson for (i = 0; i < st->depth; i++) { 192194828Srwatson (void)stack_symbol_ddb(st->pcs[i], &name, &offset); 193174137Srwatson sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 194184060Skib name, offset); 195174137Srwatson } 196174137Srwatson} 197184487Ssobomax#endif 198174137Srwatson 199148666Sjeff#ifdef KTR 200148666Sjeffvoid 201149574Spjdstack_ktr(u_int mask, const char *file, int line, struct stack *st, u_int depth, 202149574Spjd int cheap) 203148666Sjeff{ 204184487Ssobomax#ifdef DDB 205184060Skib const char *name; 206148666Sjeff long offset; 207148666Sjeff int i; 208184487Ssobomax#endif 209148666Sjeff 210159022Skris KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 211148666Sjeff if (cheap) { 212148666Sjeff ktr_tracepoint(mask, file, line, "#0 %p %p %p %p %p %p", 213148666Sjeff st->pcs[0], st->pcs[1], st->pcs[2], st->pcs[3], 214148666Sjeff st->pcs[4], st->pcs[5]); 215148666Sjeff if (st->depth <= 6) 216148666Sjeff return; 217148666Sjeff ktr_tracepoint(mask, file, line, "#1 %p %p %p %p %p %p", 218148666Sjeff st->pcs[6], st->pcs[7], st->pcs[8], st->pcs[9], 219148666Sjeff st->pcs[10], st->pcs[11]); 220148666Sjeff if (st->depth <= 12) 221148666Sjeff return; 222148666Sjeff ktr_tracepoint(mask, file, line, "#2 %p %p %p %p %p %p", 223148666Sjeff st->pcs[12], st->pcs[13], st->pcs[14], st->pcs[15], 224148666Sjeff st->pcs[16], st->pcs[17]); 225184487Ssobomax#ifdef DDB 226149574Spjd } else { 227149574Spjd if (depth == 0 || st->depth < depth) 228149574Spjd depth = st->depth; 229149574Spjd for (i = 0; i < depth; i++) { 230194828Srwatson (void)stack_symbol_ddb(st->pcs[i], &name, &offset); 231148666Sjeff ktr_tracepoint(mask, file, line, "#%d %p at %s+%#lx", 232184060Skib i, st->pcs[i], (u_long)name, offset, 0, 0); 233148666Sjeff } 234184487Ssobomax#endif 235149574Spjd } 236148666Sjeff} 237148666Sjeff#endif 238148666Sjeff 239174137Srwatson/* 240174137Srwatson * Two variants of stack symbol lookup -- one that uses the DDB interfaces 241174137Srwatson * and bypasses linker locking, and the other that doesn't. 242174137Srwatson */ 243194828Srwatsonstatic int 244174137Srwatsonstack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, long *offset) 245148666Sjeff{ 246148666Sjeff 247174137Srwatson if (linker_search_symbol_name((caddr_t)pc, namebuf, buflen, 248174137Srwatson offset) != 0) { 249174137Srwatson *offset = 0; 250174222Srwatson strlcpy(namebuf, "??", buflen); 251194828Srwatson return (ENOENT); 252194828Srwatson } else 253194828Srwatson return (0); 254148666Sjeff} 255174137Srwatson 256194828Srwatsonstatic int 257184060Skibstack_symbol_ddb(vm_offset_t pc, const char **name, long *offset) 258174137Srwatson{ 259184060Skib linker_symval_t symval; 260184060Skib c_linker_sym_t sym; 261174137Srwatson 262184060Skib if (linker_ddb_search_symbol((caddr_t)pc, &sym, offset) != 0) 263184060Skib goto out; 264184060Skib if (linker_ddb_symbol_values(sym, &symval) != 0) 265184060Skib goto out; 266184060Skib if (symval.name != NULL) { 267184060Skib *name = symval.name; 268194828Srwatson return (0); 269184060Skib } 270184060Skib out: 271184060Skib *offset = 0; 272184060Skib *name = "??"; 273194828Srwatson return (ENOENT); 274174137Srwatson} 275