summaryrefslogtreecommitdiffstats
path: root/runtime/sym.c
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/sym.c')
-rw-r--r--runtime/sym.c203
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_ */