summaryrefslogtreecommitdiffstats
path: root/runtime/transport/symbols.c
diff options
context:
space:
mode:
authorhunt <hunt>2008-02-27 19:45:45 +0000
committerhunt <hunt>2008-02-27 19:45:45 +0000
commit9a5de18784b77de82e5121861fac892c2d4d2630 (patch)
tree54d0a3fb138a31627788606953bb1cb37897caf8 /runtime/transport/symbols.c
parenta2dc47ddef0dbed1b0dc912c876f5f57f97c1ede (diff)
downloadsystemtap-steved-9a5de18784b77de82e5121861fac892c2d4d2630.tar.gz
systemtap-steved-9a5de18784b77de82e5121861fac892c2d4d2630.tar.xz
systemtap-steved-9a5de18784b77de82e5121861fac892c2d4d2630.zip
2008-02-27 Martin Hunt <hunt@redhat.com>
* sym.h (_stp_module): Add text_size, lock, and unwind data pointer. * sym.c (_stp_find_module_by_addr): New function. (_stp_kallsyms_lookup): Call _stp_find_module_by_addr(). (_stp_get_unwind_info): New. * runtime.h: Move debug macros to debug.h. Include it. * debug.h: New file. * map.c: Update debug calls. * map-gen.c: Update debug calls. * pmap-gen.c: Update debug calls. * mempool.c: New file. * symbols.c: Use rwlocks. Use new dbug macros. Handle unwind info if present. * transport.c: Include mempool.c. Update dbug and kbug calls to new macros. * transport_msgs.h (_stp_command_name): Add struct containing message names for debugging. * control.c, procfs.c: Use new dbug macros. Use new mempool functions.
Diffstat (limited to 'runtime/transport/symbols.c')
-rw-r--r--runtime/transport/symbols.c185
1 files changed, 117 insertions, 68 deletions
diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c
index e740dde8..8c453a55 100644
--- a/runtime/transport/symbols.c
+++ b/runtime/transport/symbols.c
@@ -16,16 +16,6 @@
#define _SYMBOLS_C_
#include "../sym.h"
-DEFINE_SPINLOCK(_stp_module_lock);
-#define STP_TRYLOCK_MODULES ({ \
- int numtrylock = 0; \
- while (!spin_trylock_irqsave (&_stp_module_lock, flags) && (++numtrylock < MAXTRYLOCK)) \
- ndelay (TRYLOCKDELAY); \
- (numtrylock >= MAXTRYLOCK); \
- })
-#define STP_LOCK_MODULES spin_lock_irqsave(&_stp_module_lock, flags)
-#define STP_UNLOCK_MODULES spin_unlock_irqrestore(&_stp_module_lock, flags)
-
static char *_stp_symbol_data = NULL;
static int _stp_symbol_state = 0;
static char *_stp_module_data = NULL;
@@ -63,7 +53,7 @@ static unsigned _stp_get_sym_sizes(struct module *m, unsigned *dsize)
}
/* allocate space for a module and symbols */
-static struct _stp_module * _stp_alloc_module(unsigned num, unsigned datasize)
+static struct _stp_module * _stp_alloc_module(unsigned num, unsigned datasize, unsigned unwindsize)
{
struct _stp_module *mod = (struct _stp_module *)_stp_kzalloc(sizeof(struct _stp_module));
if (mod == NULL)
@@ -85,6 +75,14 @@ static struct _stp_module * _stp_alloc_module(unsigned num, unsigned datasize)
mod->allocated |= 2;
}
+ mod->unwind_data = _stp_kmalloc(unwindsize);
+ if (mod->unwind_data == NULL) {
+ mod->unwind_data = _stp_vmalloc(unwindsize);
+ if (mod->unwind_data == NULL)
+ goto bad;
+ mod->allocated |= 4;
+ }
+
mod->num_symbols = num;
return mod;
@@ -97,19 +95,40 @@ bad:
_stp_kfree(mod->symbols);
mod->symbols = NULL;
}
+ if (mod->symbol_data) {
+ if (mod->allocated & 2)
+ _stp_vfree(mod->symbol_data);
+ else
+ _stp_kfree(mod->symbol_data);
+ mod->symbol_data = NULL;
+ }
+ _stp_kfree(mod);
+ if (mod->symbols) {
+ if (mod->allocated & 1)
+ _stp_vfree(mod->symbols);
+ else
+ _stp_kfree(mod->symbols);
+ mod->symbols = NULL;
+ }
_stp_kfree(mod);
}
return NULL;
}
-static struct _stp_module * _stp_alloc_module_from_module (struct module *m)
+static struct _stp_module * _stp_alloc_module_from_module (struct module *m, uint32_t unwind_len)
{
unsigned datasize, num = _stp_get_sym_sizes(m, &datasize);
- return _stp_alloc_module(num, datasize);
+ return _stp_alloc_module(num, datasize, unwind_len);
}
static void _stp_free_module(struct _stp_module *mod)
{
+ /* The module write lock is held. Any prior readers of this */
+ /* module's data will have read locks and need to finish before */
+ /* the memory is freed. */
+ write_lock(&mod->lock);
+ write_unlock(&mod->lock); /* there will be no more readers */
+
/* free symbol memory */
if (mod->symbols) {
if (mod->allocated & 1)
@@ -126,21 +145,30 @@ static void _stp_free_module(struct _stp_module *mod)
mod->symbol_data = NULL;
}
+ if (mod->unwind_data) {
+ if (mod->allocated & 4)
+ _stp_vfree(mod->unwind_data);
+ else
+ _stp_kfree(mod->unwind_data);
+ mod->unwind_data = NULL;
+
+ }
if (mod->sections) {
_stp_kfree(mod->sections);
mod->sections = NULL;
}
+
/* free module memory */
_stp_kfree(mod);
}
/* Delete a module and free its memory. */
-/* The lock should already be held before calling this. */
+/* The module lock should already be held before calling this. */
static void _stp_del_module(struct _stp_module *mod)
{
int i, num;
- // kbug("deleting %s\n", mod->name);
+ // kbug(DEBUG_SYMBOLS, "deleting %s\n", mod->name);
/* signal relocation code to clear its cache */
_stp_module_relocate((char *)-1, NULL, 0);
@@ -185,7 +213,7 @@ static unsigned long _stp_kallsyms_lookup_name(const char *name);
static int _stp_do_symbols(const char __user *buf, int count)
{
struct _stp_symbol *s;
- unsigned datasize, num;
+ unsigned datasize, num, unwindsize;
int i;
switch (_stp_symbol_state) {
@@ -198,23 +226,26 @@ static int _stp_do_symbols(const char __user *buf, int count)
return -EFAULT;
if (get_user(datasize, (unsigned __user *)(buf+4)))
return -EFAULT;
- //kbug("num=%d datasize=%d\n", num, datasize);
+ if (get_user(unwindsize, (unsigned __user *)(buf+8)))
+ return -EFAULT;
+ dbug(DEBUG_UNWIND, "num=%d datasize=%d unwindsize=%d\n", num, datasize, unwindsize);
- _stp_modules[0] = _stp_alloc_module(num, datasize);
+ _stp_modules[0] = _stp_alloc_module(num, datasize, unwindsize);
if (_stp_modules[0] == NULL) {
errk("cannot allocate memory\n");
return -EFAULT;
}
+ rwlock_init(&_stp_modules[0]->lock);
_stp_symbol_state = 1;
break;
case 1:
- //kbug("got stap_symbols, count=%d\n", count);
+ dbug(DEBUG_SYMBOLS, "got stap_symbols, count=%d\n", count);
if (copy_from_user ((char *)_stp_modules[0]->symbols, buf, count))
return -EFAULT;
_stp_symbol_state = 2;
break;
case 2:
- //kbug("got symbol data, count=%d buf=%p\n", count, buf);
+ dbug(DEBUG_SYMBOLS, "got symbol data, count=%d buf=%p\n", count, buf);
if (copy_from_user (_stp_modules[0]->symbol_data, buf, count))
return -EFAULT;
_stp_num_modules = 1;
@@ -227,8 +258,19 @@ static int _stp_do_symbols(const char __user *buf, int count)
/* NB: this mapping is used by kernel/_stext pseudo-relocations. */
_stp_modules[0]->text = _stp_kallsyms_lookup_name("_stext");
_stp_modules[0]->data = _stp_kallsyms_lookup_name("_etext");
+ _stp_modules[0]->text_size = _stp_modules[0]->data - _stp_modules[0]->text;
_stp_modules_by_addr[0] = _stp_modules[0];
- //kbug("done with symbol data\n");
+ dbug(DEBUG_SYMBOLS, "Got kernel symbols. text=%p len=%u\n",
+ (int64_t)_stp_modules[0]->text, _stp_modules[0]->text_size);
+ break;
+ case 3:
+ dbug(DEBUG_UNWIND, "got unwind data, count=%d\n", count);
+ _stp_symbol_state = 4;
+ if (copy_from_user (_stp_modules[0]->unwind_data, buf, count)) {
+ _dbug("cfu failed\n");
+ return -EFAULT;
+ }
+ _stp_modules[0]->unwind_data_len = count;
break;
default:
errk("unexpected symbol data of size %d.\n", count);
@@ -266,10 +308,8 @@ static void u32_swap(void *a, void *b, int size)
static void generic_swap(void *a, void *b, int size)
{
- char t;
-
do {
- t = *(char *)a;
+ char t = *(char *)a;
*(char *)a++ = *(char *)b;
*(char *)b++ = t;
} while (--size > 0);
@@ -328,7 +368,7 @@ void _stp_sort(void *base, size_t num, size_t size,
}
/* Create a new _stp_module and load the symbols */
-static struct _stp_module *_stp_load_module_symbols (struct _stp_module *imod)
+static struct _stp_module *_stp_load_module_symbols (struct _stp_module *imod, uint32_t unwind_len)
{
unsigned i, num=0;
struct module *m = (struct module *)imod->module;
@@ -336,12 +376,12 @@ static struct _stp_module *_stp_load_module_symbols (struct _stp_module *imod)
char *dataptr;
if (m == NULL) {
- kbug("imod->module is NULL\n");
+ kbug(DEBUG_SYMBOLS, "imod->module is NULL\n");
return NULL;
}
if (try_module_get(m)) {
- mod = _stp_alloc_module_from_module(m);
+ mod = _stp_alloc_module_from_module(m, unwind_len);
if (mod == NULL) {
module_put(m);
errk("failed to allocate memory for module.\n");
@@ -354,6 +394,8 @@ static struct _stp_module *_stp_load_module_symbols (struct _stp_module *imod)
mod->data = imod->data;
mod->num_sections = imod->num_sections;
mod->sections = imod->sections;
+ mod->text_size = m->core_text_size;
+ rwlock_init(&mod->lock);
/* now copy all the symbols we are interested in */
dataptr = mod->symbol_data;
@@ -375,24 +417,32 @@ static struct _stp_module *_stp_load_module_symbols (struct _stp_module *imod)
return mod;
}
-/* Do we already have this module? */
-static int _stp_module_exists(struct _stp_module *mod)
+/* Remove any old module info from our database */
+static void _stp_module_exists_delete (struct _stp_module *mod)
{
- int i, res;
- unsigned long flags;
- // kbug("exists? %s\n", mod->name);
- STP_LOCK_MODULES;
- for (i = 1; i < _stp_num_modules; i++) {
- res = strcmp(_stp_modules[i]->name, mod->name);
- if (res > 0)
+ int i, num;
+
+ /* remove any old modules with the same name */
+ for (num = 1; num < _stp_num_modules; num++) {
+ if (strcmp(_stp_modules[num]->name, mod->name) == 0) {
+ dbug(DEBUG_SYMBOLS, "found existing module with name %s. Deleting.\n", mod->name);
+ _stp_del_module(_stp_modules[num]);
break;
- if (res == 0 && _stp_modules[i]->module == mod->module) {
- STP_UNLOCK_MODULES;
- return 1;
}
}
- STP_UNLOCK_MODULES;
- return 0;
+
+ /* remove modules with overlapping addresses */
+ for (num = 1; num < _stp_num_modules; num++) {
+ if (mod->text + mod->text_size < _stp_modules_by_addr[num]->text)
+ continue;
+ if (mod->text < _stp_modules_by_addr[num]->text
+ + _stp_modules_by_addr[num]->text_size) {
+ dbug(DEBUG_SYMBOLS, "New module %s overlaps with old module %s. Deleting old.\n",
+ mod->name, _stp_modules_by_addr[num]->name);
+ _stp_del_module(_stp_modules_by_addr[num]);
+ }
+ }
+
}
static int _stp_ins_module(struct _stp_module *mod)
@@ -400,9 +450,11 @@ static int _stp_ins_module(struct _stp_module *mod)
int i, num, res, ret = 0;
unsigned long flags;
- // kbug("insert %s\n", mod->name);
+ // kbug(DEBUG_SYMBOLS, "insert %s\n", mod->name);
- STP_LOCK_MODULES;
+ STP_WLOCK_MODULES;
+
+ _stp_module_exists_delete(mod);
/* check for overflow */
if (_stp_num_modules == STP_MAX_MODULES) {
@@ -412,32 +464,25 @@ static int _stp_ins_module(struct _stp_module *mod)
}
/* insert alphabetically in _stp_modules[] */
- for (num = 1; num < _stp_num_modules; num++) {
- res = strcmp(_stp_modules[num]->name, mod->name);
- if (res < 0)
- continue;
- if (res > 0)
+ for (num = 1; num < _stp_num_modules; num++)
+ if (strcmp(_stp_modules[num]->name, mod->name) > 0)
break;
- _stp_del_module(_stp_modules[num]);
- break;
- }
for (i = _stp_num_modules; i > num; i--)
_stp_modules[i] = _stp_modules[i-1];
_stp_modules[num] = mod;
/* insert by text address in _stp_modules_by_addr[] */
- for (num = 1; num < _stp_num_modules; num++) {
- if (_stp_modules_by_addr[num]->text > mod->text)
+ for (num = 1; num < _stp_num_modules; num++)
+ if (mod->text < _stp_modules_by_addr[num]->text)
break;
- }
for (i = _stp_num_modules; i > num; i--)
_stp_modules_by_addr[i] = _stp_modules_by_addr[i-1];
_stp_modules_by_addr[num] = mod;
-
+
_stp_num_modules++;
done:
- STP_UNLOCK_MODULES;
+ STP_WUNLOCK_MODULES;
return ret;
}
@@ -456,13 +501,13 @@ static int _stp_do_module(const char __user *buf, int count)
if (copy_from_user ((char *)&tmpmod, buf, sizeof(tmpmod)))
return -EFAULT;
- section_len = count - sizeof(tmpmod);
+ section_len = count - sizeof(tmpmod) - tmpmod.unwind_len;
if (section_len <= 0) {
errk("section_len = %d\n", section_len);
return -EFAULT;
}
- kbug("Got module %s, count=%d section_len=%d\n",
- tmpmod.name, count, section_len);
+ dbug(DEBUG_SYMBOLS, "Got module %s, count=%d section_len=%d unwind_len=%d\n",
+ tmpmod.name, count, section_len, tmpmod.unwind_len);
strcpy(mod.name, tmpmod.name);
mod.module = tmpmod.module;
@@ -470,9 +515,6 @@ static int _stp_do_module(const char __user *buf, int count)
mod.data = tmpmod.data;
mod.num_sections = tmpmod.num_sections;
- if (_stp_module_exists(&mod))
- return count;
-
/* copy in section data */
mod.sections = _stp_kmalloc(section_len);
if (mod.sections == NULL) {
@@ -489,18 +531,27 @@ static int _stp_do_module(const char __user *buf, int count)
+ (long)((long)mod.sections + mod.num_sections * sizeof(struct _stp_symbol)));
}
- #ifdef DEBUG_SYMBOLS
+ #if 0
for (i = 0; i < mod.num_sections; i++)
- printk("section %d (stored at %p): %s %lx\n", i, &mod.sections[i], mod.sections[i].symbol, mod.sections[i].addr);
+ _dbug("section %d (stored at %p): %s %lx\n", i, &mod.sections[i], mod.sections[i].symbol, mod.sections[i].addr);
#endif
/* load symbols from tmpmod.module to mod */
- m = _stp_load_module_symbols(&mod);
+ m = _stp_load_module_symbols(&mod, tmpmod.unwind_len);
if (m == NULL) {
_stp_kfree(mod.sections);
return 0;
}
+ dbug(DEBUG_SYMBOLS, "module %s loaded. Text=%p text_size=%u\n", m->name, (int64_t)m->text, m->text_size);
+ /* finally copy unwind info */
+ if (copy_from_user (m->unwind_data, buf+sizeof(tmpmod)+section_len, tmpmod.unwind_len)) {
+ _stp_free_module(m);
+ _stp_kfree(mod.sections);
+ return -EFAULT;
+ }
+ m->unwind_data_len = tmpmod.unwind_len;
+
if (_stp_ins_module(m) < 0) {
_stp_free_module(m);
return -ENOMEM;
@@ -513,20 +564,18 @@ static int _stp_ctl_send (int type, void *data, int len);
static int _stp_module_load_notify(struct notifier_block * self, unsigned long val, void * data)
{
-#ifdef CONFIG_MODULES
struct module *mod = (struct module *)data;
struct _stp_module rmod;
switch (val) {
case MODULE_STATE_COMING:
- dbug("module %s loaded\n", mod->name);
+ dbug(DEBUG_SYMBOLS, "module %s load notify\n", mod->name);
strlcpy(rmod.name, mod->name, STP_MODULE_NAME_LEN);
_stp_ctl_send(STP_MODULE, &rmod, sizeof(struct _stp_module));
break;
default:
errk("module loaded? val=%ld\n", val);
}
-#endif
return 0;
}