From 0ab794a171ac6568b244e0f424efa9bcf4eb25a1 Mon Sep 17 00:00:00 2001 From: rwatson Date: Sat, 1 Dec 2007 19:24:28 +0000 Subject: [PATCH] The kernel linker includes a number of utility functions to look up symbol information in support of DDB(4); these functions bypass normal linker locking as they may run in contexts where locking is unsafe (such as the kernel debugger). Add a new interface linker_ddb_search_symbol_name(), which looks up a symbol name and offset given an address, and also linker_search_symbol_name() which does the same but *does* follow the locking conventions of the linker. Unlike existing functions, these functions place the name in a caller-provided buffer, which is stable even after linker locks have been released. These functions will be used in upcoming revisions to stack(9) to support kernel stack trace generation in contexts as part of a live, rather than suspended, kernel. --- sys/kern/kern_linker.c | 100 +++++++++++++++++++++++++++++++++++------ sys/sys/linker.h | 8 ++++ 2 files changed, 95 insertions(+), 13 deletions(-) diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c index 321436d935a8..93166a185afe 100644 --- a/sys/kern/kern_linker.c +++ b/sys/kern/kern_linker.c @@ -791,18 +791,18 @@ linker_file_lookup_symbol_internal(linker_file_t file, const char *name, return (0); } -#ifdef DDB /* - * DDB Helpers. DDB has to look across multiple files with their own symbol - * tables and string tables. + * Both DDB and stack(9) rely on the kernel linker to provide forward and + * backward lookup of symbols. However, DDB and sometimes stack(9) need to + * do this in a lockfree manner. We provide a set of internal helper + * routines to perform these operations without locks, and then wrappers that + * optionally lock. * - * Note that we do not obey list locking protocols here. We really don't need - * DDB to hang because somebody's got the lock held. We'll take the chance - * that the files list is inconsistant instead. + * linker_debug_lookup() is ifdef DDB as currently it's only used by DDB. */ - -int -linker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) +#ifdef DDB +static int +linker_debug_lookup(const char *symstr, c_linker_sym_t *sym) { linker_file_t lf; @@ -812,9 +812,10 @@ linker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) } return (ENOENT); } +#endif -int -linker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) +static int +linker_debug_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) { linker_file_t lf; c_linker_sym_t best, es; @@ -844,8 +845,8 @@ linker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) } } -int -linker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) +static int +linker_debug_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) { linker_file_t lf; @@ -855,8 +856,81 @@ linker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) } return (ENOENT); } + +static int +linker_debug_search_symbol_name(caddr_t value, char *buf, u_int buflen, + long *offset) +{ + linker_symval_t symval; + c_linker_sym_t sym; + int error; + + *offset = 0; + error = linker_debug_search_symbol(value, &sym, offset); + if (error) + return (error); + error = linker_debug_symbol_values(sym, &symval); + if (error) + return (error); + strlcpy(buf, symval.name, buflen); + return (0); +} + +#ifdef DDB +/* + * DDB Helpers. DDB has to look across multiple files with their own symbol + * tables and string tables. + * + * Note that we do not obey list locking protocols here. We really don't need + * DDB to hang because somebody's got the lock held. We'll take the chance + * that the files list is inconsistant instead. + */ +int +linker_ddb_lookup(const char *symstr, c_linker_sym_t *sym) +{ + + return (linker_debug_lookup(symstr, sym)); +} + +int +linker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp) +{ + + return (linker_debug_search_symbol(value, sym, diffp)); +} + +int +linker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval) +{ + + return (linker_debug_symbol_values(sym, symval)); +} + +int +linker_ddb_search_symbol_name(caddr_t value, char *buf, u_int buflen, + long *offset) +{ + + return (linker_debug_search_symbol_name(value, buf, buflen, offset)); +} #endif +/* + * stack(9) helper for non-debugging environemnts. Unlike DDB helpers, we do + * obey locking protocols, and offer a significantly less complex interface. + */ +int +linker_search_symbol_name(caddr_t value, char *buf, u_int buflen, + long *offset) +{ + int error; + + KLD_LOCK(); + error = linker_debug_search_symbol_name(value, buf, buflen, offset); + KLD_UNLOCK(); + return (error); +} + /* * Syscalls. */ diff --git a/sys/sys/linker.h b/sys/sys/linker.h index c5087c88a244..6655d46e4c3f 100644 --- a/sys/sys/linker.h +++ b/sys/sys/linker.h @@ -176,6 +176,14 @@ int linker_ddb_lookup(const char *_symstr, c_linker_sym_t *_sym); int linker_ddb_search_symbol(caddr_t _value, c_linker_sym_t *_sym, long *_diffp); int linker_ddb_symbol_values(c_linker_sym_t _sym, linker_symval_t *_symval); +int linker_ddb_search_symbol_name(caddr_t value, char *buf, u_int buflen, + long *offset); + +/* + * stack(9) helper for situations where kernel locking is required. + */ +int linker_search_symbol_name(caddr_t value, char *buf, u_int buflen, + long *offset); /* HWPMC helper */