diff options
Diffstat (limited to 'runtime/sym.c')
-rw-r--r-- | runtime/sym.c | 203 |
1 files changed, 112 insertions, 91 deletions
diff --git a/runtime/sym.c b/runtime/sym.c index 56c93064..3c2f859a 100644 --- a/runtime/sym.c +++ b/runtime/sym.c @@ -1,6 +1,6 @@ /* -*- linux-c -*- * Symbolic Lookup Functions - * Copyright (C) 2005, 2006, 2007 Red Hat Inc. + * Copyright (C) 2005-2008 Red Hat Inc. * Copyright (C) 2006 Intel Corporation. * * This file is part of systemtap, and is free software. You can @@ -9,8 +9,8 @@ * later version. */ -#ifndef _SYM_C_ -#define _SYM_C_ +#ifndef _STP_SYM_C_ +#define _STP_SYM_C_ #include "string.c" @@ -20,11 +20,12 @@ * @{ */ -unsigned long _stp_module_relocate (const char *module, const char *section, unsigned long offset) { +unsigned long _stp_module_relocate(const char *module, const char *section, unsigned long offset) +{ static struct _stp_module *last = NULL; static struct _stp_symbol *last_sec; unsigned long flags; - int i,j; + int i, j; /* if module is -1, we invalidate last. _stp_del_module calls this when modules are deleted. */ if ((long)module == -1) { @@ -32,53 +33,52 @@ unsigned long _stp_module_relocate (const char *module, const char *section, uns return 0; } - dbug("%s, %s, %lx\n", module, section, offset); + dbug(DEBUG_SYMBOLS, "%s, %s, %lx\n", module, section, offset); - STP_LOCK_MODULES; - if (! module - || !strcmp (section, "") /* absolute, unrelocated address */ - || _stp_num_modules == 0) { - STP_UNLOCK_MODULES; - return offset; + STP_RLOCK_MODULES; + if (!module || !strcmp(section, "") /* absolute, unrelocated address */ + ||_stp_num_modules == 0) { + STP_RUNLOCK_MODULES; + return offset; } /* Most likely our relocation is in the same section of the same module as the last. */ if (last) { - if (!strcmp (module, last->name) && !strcmp (section, last_sec->symbol)) { + if (!strcmp(module, last->name) && !strcmp(section, last_sec->symbol)) { offset += last_sec->addr; - STP_UNLOCK_MODULES; - dbug("offset = %lx\n", offset); + STP_RUNLOCK_MODULES; + dbug(DEBUG_SYMBOLS, "offset = %lx\n", offset); return offset; } } /* not cached. need to scan all modules */ - if (! strcmp (module, "kernel")) { - STP_UNLOCK_MODULES; + if (!strcmp(module, "kernel")) { + STP_RUNLOCK_MODULES; /* See also transport/symbols.c (_stp_do_symbols). */ - if (strcmp (section, "_stext")) + if (strcmp(section, "_stext")) return 0; else return offset + _stp_modules[0]->text; } else { /* relocatable module */ - for (i = 1; i < _stp_num_modules; i++) { /* skip over [0]=kernel */ + for (i = 1; i < _stp_num_modules; i++) { /* skip over [0]=kernel */ last = _stp_modules[i]; if (strcmp(module, last->name)) continue; for (j = 0; j < (int)last->num_sections; j++) { last_sec = &last->sections[j]; - if (!strcmp (section, last_sec->symbol)) { + if (!strcmp(section, last_sec->symbol)) { offset += last_sec->addr; - STP_UNLOCK_MODULES; - dbug("offset = %lx\n", offset); + STP_RUNLOCK_MODULES; + dbug(DEBUG_SYMBOLS, "offset = %lx\n", offset); return offset; } } } } - STP_UNLOCK_MODULES; + STP_RUNLOCK_MODULES; last = NULL; return 0; } @@ -97,24 +97,15 @@ static unsigned long _stp_kallsyms_lookup_name(const char *name) return 0; } -static const char * _stp_kallsyms_lookup ( - unsigned long addr, - unsigned long *symbolsize, - unsigned long *offset, - char **modname, - char *namebuf) +static struct _stp_module *_stp_find_module_by_addr(unsigned long addr) { - struct _stp_module *m; - struct _stp_symbol *s; - unsigned long flags; - unsigned end, begin = 0; + unsigned begin = 0; + unsigned end = _stp_num_modules; - if (STP_TRYLOCK_MODULES) + if (unlikely(addr < _stp_modules_by_addr[0]->text)) return NULL; - end = _stp_num_modules; - - if (_stp_num_modules >= 2 && addr > _stp_modules_by_addr[1]->text) { + if (_stp_num_modules > 1 && addr > _stp_modules_by_addr[0]->data) { /* binary search on index [begin,end) */ do { unsigned mid = (begin + end) / 2; @@ -125,18 +116,51 @@ static const char * _stp_kallsyms_lookup ( } while (begin + 1 < end); /* result index in $begin, guaranteed between [0,_stp_num_modules) */ } - m = _stp_modules_by_addr[begin]; - begin = 0; - end = m->num_symbols; + /* check if addr is past the last module */ + if (unlikely(begin == _stp_num_modules - 1 + && (addr > _stp_modules_by_addr[begin]->text + _stp_modules_by_addr[begin]->text_size))) + return NULL; + + return _stp_modules_by_addr[begin]; +} - /* m->data is the lowest address of a data section. It should be */ - /* after the text section. */ - /* If our address is in the data section, then return now. */ - if (m->data > m->text && addr >= m->data) { - STP_UNLOCK_MODULES; +static struct _stp_module *_stp_get_unwind_info(unsigned long addr) +{ + struct _stp_module *m; + struct _stp_symbol *s; + unsigned long flags; + + STP_RLOCK_MODULES; + m = _stp_find_module_by_addr(addr); + if (unlikely(m == NULL)) { + STP_RUNLOCK_MODULES; return NULL; } - + /* Lock the module struct so it doesn't go away while being used. */ + /* Probably could never happen, but lock it to be sure for now. */ + read_lock(&m->lock); + + STP_RUNLOCK_MODULES; + return m; +} + +static const char *_stp_kallsyms_lookup(unsigned long addr, + unsigned long *symbolsize, unsigned long *offset, char **modname, char *namebuf) +{ + struct _stp_module *m; + struct _stp_symbol *s; + unsigned long flags; + unsigned end, begin = 0; + + STP_RLOCK_MODULES; + m = _stp_find_module_by_addr(addr); + if (unlikely(m == NULL)) { + STP_RUNLOCK_MODULES; + return NULL; + } + + end = m->num_symbols; + /* binary search for symbols within the module */ do { unsigned mid = (begin + end) / 2; @@ -148,31 +172,29 @@ static const char * _stp_kallsyms_lookup ( /* result index in $begin */ s = &m->symbols[begin]; - if (addr < s->addr) { - STP_UNLOCK_MODULES; - return NULL; - } else { - if (offset) *offset = addr - s->addr; - if (modname) *modname = m->name; + if (likely(addr >= s->addr)) { + if (offset) + *offset = addr - s->addr; + if (modname) + *modname = m->name; if (symbolsize) { if ((begin + 1) < m->num_symbols) - *symbolsize = m->symbols[begin+1].addr - s->addr; + *symbolsize = m->symbols[begin + 1].addr - s->addr; else *symbolsize = 0; // NB: This is only a heuristic. Sometimes there are large // gaps between text areas of modules. } if (namebuf) { - strlcpy (namebuf, s->symbol, KSYM_NAME_LEN+1); - STP_UNLOCK_MODULES; + strlcpy(namebuf, s->symbol, KSYM_NAME_LEN + 1); + STP_RUNLOCK_MODULES; return namebuf; - } - else { - STP_UNLOCK_MODULES; + } else { + STP_RUNLOCK_MODULES; return s->symbol; } } - STP_UNLOCK_MODULES; + STP_RUNLOCK_MODULES; return NULL; } @@ -182,31 +204,31 @@ static const char * _stp_kallsyms_lookup ( * a probe because it is too time-consuming. Use at module exit time. */ -void _stp_symbol_print (unsigned long address) -{ +void _stp_symbol_print(unsigned long address) +{ char *modname; - const char *name; - unsigned long offset, size; + const char *name; + unsigned long offset, size; - name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL); + name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL); - _stp_printf ("%p", (int64_t)address); + _stp_printf("%p", (int64_t) address); - if (name) { + if (name) { if (modname && *modname) - _stp_printf (" : %s+%#lx/%#lx [%s]", name, offset, size, modname); + _stp_printf(" : %s+%#lx/%#lx [%s]", name, offset, size, modname); else - _stp_printf (" : %s+%#lx/%#lx", name, offset, size); + _stp_printf(" : %s+%#lx/%#lx", name, offset, size); } } /* Like _stp_symbol_print, except only print if the address is a valid function address */ -void _stp_func_print (unsigned long address, int verbose, int exact) -{ +void _stp_func_print(unsigned long address, int verbose, int exact) +{ char *modname; - const char *name; - unsigned long offset, size; + const char *name; + unsigned long offset, size; char *exstr; if (exact) @@ -214,33 +236,32 @@ void _stp_func_print (unsigned long address, int verbose, int exact) else exstr = " (inexact)"; - name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL); + name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL); if (name) { if (verbose) { if (modname && *modname) - _stp_printf (" %p : %s+%#lx/%#lx [%s]%s\n", - (int64_t)address, name, offset, size, modname, exstr); + _stp_printf(" %p : %s+%#lx/%#lx [%s]%s\n", + (int64_t) address, name, offset, size, modname, exstr); else - _stp_printf (" %p : %s+%#lx/%#lx%s\n", - (int64_t)address, name, offset, size, exstr); - } else - _stp_printf ("%p ", (int64_t)address); + _stp_printf(" %p : %s+%#lx/%#lx%s\n", (int64_t) address, name, offset, size, exstr); + } else + _stp_printf("%p ", (int64_t) address); } } -void _stp_symbol_snprint (char *str, size_t len, unsigned long address) -{ - char *modname; - const char *name; - unsigned long offset, size; - - name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL); - if (name) - strlcpy(str, name, len); - else - _stp_snprintf(str, len, "%p", (int64_t)address); +void _stp_symbol_snprint(char *str, size_t len, unsigned long address) +{ + char *modname; + const char *name; + unsigned long offset, size; + + name = _stp_kallsyms_lookup(address, &size, &offset, &modname, NULL); + if (name) + strlcpy(str, name, len); + else + _stp_snprintf(str, len, "%p", (int64_t) address); } /** @} */ -#endif /* _SYM_C_ */ +#endif /* _STP_SYM_C_ */ |