diff options
Diffstat (limited to 'runtime/transport/symbols.c')
-rw-r--r-- | runtime/transport/symbols.c | 185 |
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; } |