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$"); 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> 42219028Snetchild#include <sys/sysctl.h> 43148666Sjeff 44219028SnetchildFEATURE(stack, "Support for capturing kernel stack"); 45219028Snetchild 46180495Santoinestatic MALLOC_DEFINE(M_STACK, "stack", "Stack Traces"); 47148666Sjeff 48194828Srwatsonstatic int stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, 49174137Srwatson long *offset); 50194828Srwatsonstatic int stack_symbol_ddb(vm_offset_t pc, const char **name, long *offset); 51148666Sjeff 52148666Sjeffstruct stack * 53148666Sjeffstack_create(void) 54148666Sjeff{ 55148666Sjeff struct stack *st; 56148666Sjeff 57148666Sjeff st = malloc(sizeof *st, M_STACK, M_WAITOK | M_ZERO); 58148666Sjeff return (st); 59148666Sjeff} 60148666Sjeff 61148666Sjeffvoid 62148666Sjeffstack_destroy(struct stack *st) 63148666Sjeff{ 64148666Sjeff 65148666Sjeff free(st, M_STACK); 66148666Sjeff} 67148666Sjeff 68148666Sjeffint 69148666Sjeffstack_put(struct stack *st, vm_offset_t pc) 70148666Sjeff{ 71148666Sjeff 72148666Sjeff if (st->depth < STACK_MAX) { 73148666Sjeff st->pcs[st->depth++] = pc; 74148666Sjeff return (0); 75148666Sjeff } else 76148666Sjeff return (-1); 77148666Sjeff} 78148666Sjeff 79148666Sjeffvoid 80227581Spjdstack_copy(const struct stack *src, struct stack *dst) 81148666Sjeff{ 82148666Sjeff 83148666Sjeff *dst = *src; 84148666Sjeff} 85148666Sjeff 86148666Sjeffvoid 87148666Sjeffstack_zero(struct stack *st) 88148666Sjeff{ 89148666Sjeff 90148666Sjeff bzero(st, sizeof *st); 91148666Sjeff} 92148666Sjeff 93148666Sjeffvoid 94227581Spjdstack_print(const struct stack *st) 95148666Sjeff{ 96174137Srwatson char namebuf[64]; 97148666Sjeff long offset; 98148666Sjeff int i; 99148666Sjeff 100159022Skris KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 101148666Sjeff for (i = 0; i < st->depth; i++) { 102194828Srwatson (void)stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), 103194828Srwatson &offset); 104148666Sjeff printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 105174137Srwatson namebuf, offset); 106148666Sjeff } 107148666Sjeff} 108148666Sjeff 109194828Srwatsonvoid 110227581Spjdstack_print_short(const struct stack *st) 111194828Srwatson{ 112194828Srwatson char namebuf[64]; 113194828Srwatson long offset; 114194828Srwatson int i; 115194828Srwatson 116194828Srwatson KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 117194828Srwatson for (i = 0; i < st->depth; i++) { 118194828Srwatson if (i > 0) 119194828Srwatson printf(" "); 120194828Srwatson if (stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), 121194828Srwatson &offset) == 0) 122194828Srwatson printf("%s+%#lx", namebuf, offset); 123194828Srwatson else 124194828Srwatson printf("%p", (void *)st->pcs[i]); 125194828Srwatson } 126194828Srwatson printf("\n"); 127194828Srwatson} 128194828Srwatson 129148666Sjeffvoid 130227581Spjdstack_print_ddb(const struct stack *st) 131174137Srwatson{ 132184060Skib const char *name; 133174137Srwatson long offset; 134174137Srwatson int i; 135174137Srwatson 136174137Srwatson KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 137174137Srwatson for (i = 0; i < st->depth; i++) { 138184060Skib stack_symbol_ddb(st->pcs[i], &name, &offset); 139174137Srwatson printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 140184060Skib name, offset); 141174137Srwatson } 142174137Srwatson} 143194828Srwatson 144212994Savg#ifdef DDB 145194828Srwatsonvoid 146227581Spjdstack_print_short_ddb(const struct stack *st) 147194828Srwatson{ 148194828Srwatson const char *name; 149194828Srwatson long offset; 150194828Srwatson int i; 151194828Srwatson 152194828Srwatson KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 153194828Srwatson for (i = 0; i < st->depth; i++) { 154194828Srwatson if (i > 0) 155194828Srwatson printf(" "); 156194828Srwatson if (stack_symbol_ddb(st->pcs[i], &name, &offset) == 0) 157194828Srwatson printf("%s+%#lx", name, offset); 158194828Srwatson else 159194828Srwatson printf("%p", (void *)st->pcs[i]); 160194828Srwatson } 161194828Srwatson printf("\n"); 162194828Srwatson} 163174195Srwatson#endif 164174137Srwatson 165174137Srwatson/* 166174137Srwatson * Two print routines -- one for use from DDB and DDB-like contexts, the 167174137Srwatson * other for use in the live kernel. 168174137Srwatson */ 169174137Srwatsonvoid 170227581Spjdstack_sbuf_print(struct sbuf *sb, const struct stack *st) 171148666Sjeff{ 172174137Srwatson char namebuf[64]; 173148666Sjeff long offset; 174148666Sjeff int i; 175148666Sjeff 176159022Skris KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 177148666Sjeff for (i = 0; i < st->depth; i++) { 178194828Srwatson (void)stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), 179194828Srwatson &offset); 180148666Sjeff sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 181174137Srwatson namebuf, offset); 182148666Sjeff } 183148666Sjeff} 184148666Sjeff 185174137Srwatson#ifdef DDB 186174137Srwatsonvoid 187227581Spjdstack_sbuf_print_ddb(struct sbuf *sb, const struct stack *st) 188174137Srwatson{ 189184060Skib const char *name; 190174137Srwatson long offset; 191174137Srwatson int i; 192174137Srwatson 193174137Srwatson KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 194174137Srwatson for (i = 0; i < st->depth; i++) { 195194828Srwatson (void)stack_symbol_ddb(st->pcs[i], &name, &offset); 196174137Srwatson sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], 197184060Skib name, offset); 198174137Srwatson } 199174137Srwatson} 200184487Ssobomax#endif 201174137Srwatson 202148666Sjeff#ifdef KTR 203148666Sjeffvoid 204227581Spjdstack_ktr(u_int mask, const char *file, int line, const struct stack *st, 205227581Spjd u_int depth, int cheap) 206148666Sjeff{ 207184487Ssobomax#ifdef DDB 208184060Skib const char *name; 209148666Sjeff long offset; 210148666Sjeff int i; 211184487Ssobomax#endif 212148666Sjeff 213159022Skris KASSERT(st->depth <= STACK_MAX, ("bogus stack")); 214148666Sjeff if (cheap) { 215148666Sjeff ktr_tracepoint(mask, file, line, "#0 %p %p %p %p %p %p", 216148666Sjeff st->pcs[0], st->pcs[1], st->pcs[2], st->pcs[3], 217148666Sjeff st->pcs[4], st->pcs[5]); 218148666Sjeff if (st->depth <= 6) 219148666Sjeff return; 220148666Sjeff ktr_tracepoint(mask, file, line, "#1 %p %p %p %p %p %p", 221148666Sjeff st->pcs[6], st->pcs[7], st->pcs[8], st->pcs[9], 222148666Sjeff st->pcs[10], st->pcs[11]); 223148666Sjeff if (st->depth <= 12) 224148666Sjeff return; 225148666Sjeff ktr_tracepoint(mask, file, line, "#2 %p %p %p %p %p %p", 226148666Sjeff st->pcs[12], st->pcs[13], st->pcs[14], st->pcs[15], 227148666Sjeff st->pcs[16], st->pcs[17]); 228184487Ssobomax#ifdef DDB 229149574Spjd } else { 230149574Spjd if (depth == 0 || st->depth < depth) 231149574Spjd depth = st->depth; 232149574Spjd for (i = 0; i < depth; i++) { 233194828Srwatson (void)stack_symbol_ddb(st->pcs[i], &name, &offset); 234148666Sjeff ktr_tracepoint(mask, file, line, "#%d %p at %s+%#lx", 235184060Skib i, st->pcs[i], (u_long)name, offset, 0, 0); 236148666Sjeff } 237184487Ssobomax#endif 238149574Spjd } 239148666Sjeff} 240148666Sjeff#endif 241148666Sjeff 242174137Srwatson/* 243174137Srwatson * Two variants of stack symbol lookup -- one that uses the DDB interfaces 244174137Srwatson * and bypasses linker locking, and the other that doesn't. 245174137Srwatson */ 246194828Srwatsonstatic int 247174137Srwatsonstack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, long *offset) 248148666Sjeff{ 249148666Sjeff 250174137Srwatson if (linker_search_symbol_name((caddr_t)pc, namebuf, buflen, 251174137Srwatson offset) != 0) { 252174137Srwatson *offset = 0; 253174222Srwatson strlcpy(namebuf, "??", buflen); 254194828Srwatson return (ENOENT); 255194828Srwatson } else 256194828Srwatson return (0); 257148666Sjeff} 258174137Srwatson 259194828Srwatsonstatic int 260184060Skibstack_symbol_ddb(vm_offset_t pc, const char **name, long *offset) 261174137Srwatson{ 262184060Skib linker_symval_t symval; 263184060Skib c_linker_sym_t sym; 264174137Srwatson 265184060Skib if (linker_ddb_search_symbol((caddr_t)pc, &sym, offset) != 0) 266184060Skib goto out; 267184060Skib if (linker_ddb_symbol_values(sym, &symval) != 0) 268184060Skib goto out; 269184060Skib if (symval.name != NULL) { 270184060Skib *name = symval.name; 271194828Srwatson return (0); 272184060Skib } 273184060Skib out: 274184060Skib *offset = 0; 275184060Skib *name = "??"; 276194828Srwatson return (ENOENT); 277174137Srwatson} 278