From 090235e567d2103bb33c8098bde951eb3c184d05 Mon Sep 17 00:00:00 2001 From: rwatson Date: Sat, 1 Dec 2007 22:04:16 +0000 Subject: [PATCH] Modify stack(9) stack_print() and stack_sbuf_print() routines to use new linker interfaces for looking up function names and offsets from instruction pointers. Create two variants of each call: one that is "DDB-safe" and avoids locking in the linker, and one that is safe for use in live kernels, by virtue of observing locking, and in particular safe when kernel modules are being loaded and unloaded simultaneous to their use. This will allow them to be used outside of debugging contexts. Modify two of three current stack(9) consumers to use the DDB-safe interfaces, as they run in low-level debugging contexts, such as inside lockmgr(9) and the kernel memory allocator. Update man page. --- share/man/man9/Makefile | 1 + share/man/man9/stack.9 | 17 ++++++- sys/kern/kern_lock.c | 2 +- sys/kern/subr_stack.c | 103 ++++++++++++++++++++++++++++++---------- sys/sys/stack.h | 2 + sys/vm/redzone.c | 8 ++-- 6 files changed, 102 insertions(+), 31 deletions(-) diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile index f3257bf3dc85..53ae350283b6 100644 --- a/share/man/man9/Makefile +++ b/share/man/man9/Makefile @@ -1074,6 +1074,7 @@ MLINKS+=stack.9 stack_copy.9 \ stack.9 stack_put.9 \ stack.9 stack_save.9 \ stack.9 stack_sbuf_print.9 \ + stack.9 stack_sbuf_print_ddb.9 \ stack.9 stack_zero.9 MLINKS+=store.9 subyte.9 \ store.9 suswintr.9 \ diff --git a/share/man/man9/stack.9 b/share/man/man9/stack.9 index dabef1aa321b..17cf50946d79 100644 --- a/share/man/man9/stack.9 +++ b/share/man/man9/stack.9 @@ -54,6 +54,8 @@ In kernel configuration files: .Ft void .Fn stack_sbuf_print "struct sbuf sb*" "struct stack *st" .Ft void +.Fn stack_sbuf_print_ddb "struct sbuf sb*" "struct stack *st" +.Ft void .Fn stack_save "struct stack *st" .Sh DESCRIPTION The @@ -96,7 +98,17 @@ as described in .Xr sbuf 9 . This function may sleep if an auto-extending .Dv struct sbuf -is used. +is used, and because the kernel linker (used to look up symbol names) uses +.Xr sx 9 +locks. +.Pp +In locking-sensitive environments, such as +.Xr DDB 4 , +the unsynchronized +.Fn stack_sbuf_print_ddb +variant may be invoked; this makes use of kernel linker data structures to +look up symbol names without following locking protocols, so is appropriate +for use in the debugger but not while the system is live. .Pp The utility functions .Nm stack_zero , @@ -107,7 +119,8 @@ may be used to manipulate stack data structures directly. .Sh SEE ALSO .Xr DDB 4 , .Xr printf 9 , -.Xr sbuf 9 +.Xr sbuf 9 , +.Xr sx 9 .Sh AUTHORS .An -nosplit The diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index b06e17ea5610..3e1d78fe4887 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -625,7 +625,7 @@ lockmgr_printinfo(lkp) if (lkp->lk_waitcount > 0) printf(" with %d pending", lkp->lk_waitcount); #ifdef DEBUG_LOCKS - stack_print(&lkp->lk_stack); + stack_print_ddb(&lkp->lk_stack); #endif } diff --git a/sys/kern/subr_stack.c b/sys/kern/subr_stack.c index 705c21baefdf..e3cf1568c90e 100644 --- a/sys/kern/subr_stack.c +++ b/sys/kern/subr_stack.c @@ -24,6 +24,8 @@ * SUCH DAMAGE. */ +#include "opt_ddb.h" + #include __FBSDID("$FreeBSD$"); @@ -40,7 +42,12 @@ __FBSDID("$FreeBSD$"); MALLOC_DEFINE(M_STACK, "stack", "Stack Traces"); -static void stack_symbol(vm_offset_t pc, const char **name, long *offset); +static void stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, + long *offset); +#ifdef DDB +static void stack_symbol_ddb(vm_offset_t pc, char *namebuf, u_int buflen, + long *offset); +#endif struct stack * stack_create(void) @@ -86,30 +93,67 @@ stack_zero(struct stack *st) void stack_print(struct stack *st) { - const char *name; + char namebuf[64]; long offset; int i; KASSERT(st->depth <= STACK_MAX, ("bogus stack")); for (i = 0; i < st->depth; i++) { - stack_symbol(st->pcs[i], &name, &offset); + stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), &offset); printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], - name, offset); + namebuf, offset); } } void -stack_sbuf_print(struct sbuf *sb, struct stack *st) +stack_print_ddb(struct stack *st) { - const char *name; + char namebuf[64]; long offset; int i; KASSERT(st->depth <= STACK_MAX, ("bogus stack")); for (i = 0; i < st->depth; i++) { - stack_symbol(st->pcs[i], &name, &offset); + stack_symbol_ddb(st->pcs[i], namebuf, sizeof(namebuf), + &offset); + printf("#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], + namebuf, offset); + } +} + +/* + * Two print routines -- one for use from DDB and DDB-like contexts, the + * other for use in the live kernel. + */ +void +stack_sbuf_print(struct sbuf *sb, struct stack *st) +{ + char namebuf[64]; + long offset; + int i; + + KASSERT(st->depth <= STACK_MAX, ("bogus stack")); + for (i = 0; i < st->depth; i++) { + stack_symbol(st->pcs[i], namebuf, sizeof(namebuf), &offset); sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], - name, offset); + namebuf, offset); + } +} + +#ifdef DDB +void +stack_sbuf_print_ddb(struct sbuf *sb, struct stack *st) +{ + char namebuf[64]; + long offset; + int i; + + KASSERT(st->depth <= STACK_MAX, ("bogus stack")); + for (i = 0; i < st->depth; i++) { + stack_symbol_ddb(st->pcs[i], namebuf, sizeof(namebuf), + &offset); + sbuf_printf(sb, "#%d %p at %s+%#lx\n", i, (void *)st->pcs[i], + namebuf, offset); } } @@ -118,7 +162,7 @@ void stack_ktr(u_int mask, const char *file, int line, struct stack *st, u_int depth, int cheap) { - const char *name; + char namebuf[64]; long offset; int i; @@ -141,29 +185,40 @@ stack_ktr(u_int mask, const char *file, int line, struct stack *st, u_int depth, if (depth == 0 || st->depth < depth) depth = st->depth; for (i = 0; i < depth; i++) { - stack_symbol(st->pcs[i], &name, &offset); + stack_symbol_ddb(st->pcs[i], namebuf, + sizeof(namebuf), &offset); ktr_tracepoint(mask, file, line, "#%d %p at %s+%#lx", - i, st->pcs[i], (u_long)name, offset, 0, 0); + i, st->pcs[i], (u_long)namebuf, offset, 0, 0); } } } #endif +#endif +/* + * Two variants of stack symbol lookup -- one that uses the DDB interfaces + * and bypasses linker locking, and the other that doesn't. + */ static void -stack_symbol(vm_offset_t pc, const char **name, long *offset) +stack_symbol(vm_offset_t pc, char *namebuf, u_int buflen, long *offset) { - linker_symval_t symval; - c_linker_sym_t sym; - if (linker_ddb_search_symbol((caddr_t)pc, &sym, offset) != 0) - goto out; - if (linker_ddb_symbol_values(sym, &symval) != 0) - goto out; - if (symval.name != NULL) { - *name = symval.name; - return; + if (linker_search_symbol_name((caddr_t)pc, namebuf, buflen, + offset) != 0) { + *offset = 0; + strlcpy(namebuf, "Unknown func", buflen); } -out: - *offset = 0; - *name = "Unknown func"; } + +#ifdef DDB +static void +stack_symbol_ddb(vm_offset_t pc, char *namebuf, u_int buflen, long *offset) +{ + + if (linker_ddb_search_symbol_name((caddr_t)pc, namebuf, buflen, + offset) != 0) { + *offset = 0; + strlcpy(namebuf, "Unknown func", buflen); + }; +} +#endif diff --git a/sys/sys/stack.h b/sys/sys/stack.h index a7ac114537be..ca834724b518 100644 --- a/sys/sys/stack.h +++ b/sys/sys/stack.h @@ -45,7 +45,9 @@ int stack_put(struct stack *, vm_offset_t); void stack_copy(struct stack *, struct stack *); void stack_zero(struct stack *); void stack_print(struct stack *); +void stack_print_ddb(struct stack *); void stack_sbuf_print(struct sbuf *, struct stack *); +void stack_sbuf_print_ddb(struct sbuf *, struct stack *); #ifdef KTR void stack_ktr(u_int, const char *, int, struct stack *, u_int, int); #define CTRSTACK(m, st, depth, cheap) do { \ diff --git a/sys/vm/redzone.c b/sys/vm/redzone.c index 5598b5defb6f..b3e5c88ef73b 100644 --- a/sys/vm/redzone.c +++ b/sys/vm/redzone.c @@ -152,10 +152,10 @@ redzone_check(caddr_t naddr) "corrupted before %p (%lu bytes allocated).\n", ncorruptions, ncorruptions == 1 ? "" : "s", naddr, nsize); printf("Allocation backtrace:\n"); - stack_print(&ast); + stack_print_ddb(&ast); printf("Free backtrace:\n"); stack_save(&fst); - stack_print(&fst); + stack_print_ddb(&fst); if (redzone_panic) panic("Stopping here."); } @@ -171,10 +171,10 @@ redzone_check(caddr_t naddr) "after %p (%lu bytes allocated).\n", ncorruptions, ncorruptions == 1 ? "" : "s", naddr + nsize, nsize); printf("Allocation backtrace:\n"); - stack_print(&ast); + stack_print_ddb(&ast); printf("Free backtrace:\n"); stack_save(&fst); - stack_print(&fst); + stack_print_ddb(&fst); if (redzone_panic) panic("Stopping here."); }