diff options
Diffstat (limited to 'runtime/transport/symbols.c')
-rw-r--r-- | runtime/transport/symbols.c | 606 |
1 files changed, 319 insertions, 287 deletions
diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c index 8c453a55..6406d6ad 100644 --- a/runtime/transport/symbols.c +++ b/runtime/transport/symbols.c @@ -12,8 +12,8 @@ * lib/sort.c of kernel 2.6.22-rc5. It was written by Matt Mackall. */ -#ifndef _SYMBOLS_C_ -#define _SYMBOLS_C_ +#ifndef _STP_SYMBOLS_C_ +#define _STP_SYMBOLS_C_ #include "../sym.h" static char *_stp_symbol_data = NULL; @@ -21,17 +21,12 @@ static int _stp_symbol_state = 0; static char *_stp_module_data = NULL; static int _stp_module_state = 0; - /* these are all the symbol types we are interested in */ static int _stp_sym_type_ok(int type) { - switch (type) { - case 'T': - case 't': + /* we only care about function symbols, which are in the text section */ + if (type == 'T' || type == 't') return 1; - default: - return 0; - } return 0; } @@ -41,10 +36,10 @@ static unsigned _stp_get_sym_sizes(struct module *m, unsigned *dsize) { unsigned int i; unsigned num = 0, datasize = 0; - for (i=0; i < m->num_symtab; i++) { + for (i = 0; i < m->num_symtab; i++) { char *str = (char *)(m->strtab + m->symtab[i].st_name); if (*str != '\0' && _stp_sym_type_ok(m->symtab[i].st_info)) { - datasize += strlen(str)+1; + datasize += strlen(str) + 1; num++; } } @@ -52,19 +47,23 @@ static unsigned _stp_get_sym_sizes(struct module *m, unsigned *dsize) return num; } -/* allocate space for a module and symbols */ -static struct _stp_module * _stp_alloc_module(unsigned num, unsigned datasize, unsigned unwindsize) +/* allocate space for a module, sections, and symbols */ +static struct _stp_module *_stp_alloc_module(unsigned sectsize, unsigned num, unsigned datasize) { struct _stp_module *mod = (struct _stp_module *)_stp_kzalloc(sizeof(struct _stp_module)); if (mod == NULL) goto bad; + mod->sections = (struct _stp_symbol *)_stp_kmalloc(sectsize); + if (mod->sections == NULL) + goto bad; + mod->symbols = (struct _stp_symbol *)_stp_kmalloc(num * sizeof(struct _stp_symbol)); if (mod->symbols == NULL) { mod->symbols = (struct _stp_symbol *)_stp_vmalloc(num * sizeof(struct _stp_symbol)); if (mod->symbols == NULL) goto bad; - mod->allocated = 1; + mod->allocated.symbols = 1; } mod->symbol_data = _stp_kmalloc(datasize); @@ -72,91 +71,63 @@ static struct _stp_module * _stp_alloc_module(unsigned num, unsigned datasize, u mod->symbol_data = _stp_vmalloc(datasize); if (mod->symbol_data == NULL) goto bad; - mod->allocated |= 2; + mod->allocated.symbol_data = 1; } - 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; bad: if (mod) { + if (mod->sections) + _stp_kfree(mod->sections); if (mod->symbols) { - if (mod->allocated & 1) + if (mod->allocated.symbols) _stp_vfree(mod->symbols); else _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); + _stp_kfree(mod); } return NULL; } -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, 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 */ + write_unlock(&mod->lock); /* there will be no more readers */ - /* free symbol memory */ - if (mod->symbols) { - if (mod->allocated & 1) - _stp_vfree(mod->symbols); - else - _stp_kfree(mod->symbols); - mod->symbols = NULL; - } + /* Free symbol memory */ + /* If symbol_data wasn't allocated, then symbols weren't either. */ if (mod->symbol_data) { - if (mod->allocated & 2) + if (mod->symbols) { + if (mod->allocated.symbols) + _stp_vfree(mod->symbols); + else + _stp_kfree(mod->symbols); + } + if (mod->allocated.symbol_data) _stp_vfree(mod->symbol_data); else _stp_kfree(mod->symbol_data); - mod->symbol_data = NULL; - } if (mod->unwind_data) { - if (mod->allocated & 4) + if (mod->allocated.unwind_data) _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; + if (mod->unwind_hdr) { + if (mod->allocated.unwind_hdr) + _stp_vfree(mod->unwind_hdr); + else + _stp_kfree(mod->unwind_hdr); } + if (mod->sections) + _stp_kfree(mod->sections); /* free module memory */ _stp_kfree(mod); @@ -168,7 +139,7 @@ static void _stp_del_module(struct _stp_module *mod) { int i, num; - // kbug(DEBUG_SYMBOLS, "deleting %s\n", mod->name); + dbug_sym(1, "deleting module %s\n", mod->name); /* signal relocation code to clear its cache */ _stp_module_relocate((char *)-1, NULL, 0); @@ -181,15 +152,15 @@ static void _stp_del_module(struct _stp_module *mod) if (num >= _stp_num_modules) return; - for (i = num; i < _stp_num_modules-1; i++) - _stp_modules[i] = _stp_modules[i+1]; + for (i = num; i < _stp_num_modules - 1; i++) + _stp_modules[i] = _stp_modules[i + 1]; for (num = 0; num < _stp_num_modules; num++) { if (_stp_modules_by_addr[num] == mod) break; } - for (i = num; i < _stp_num_modules-1; i++) - _stp_modules_by_addr[i] = _stp_modules_by_addr[i+1]; + for (i = num; i < _stp_num_modules - 1; i++) + _stp_modules_by_addr[i] = _stp_modules_by_addr[i + 1]; _stp_num_modules--; @@ -197,10 +168,8 @@ static void _stp_del_module(struct _stp_module *mod) } static void _stp_free_modules(void) -{ +{ int i; - unsigned long flags; - /* This only happens when the systemtap module unloads */ /* so there is no need for locks. */ for (i = _stp_num_modules - 1; i >= 0; i--) @@ -208,82 +177,120 @@ static void _stp_free_modules(void) } static unsigned long _stp_kallsyms_lookup_name(const char *name); +static void _stp_create_unwind_hdr(struct _stp_module *m); + +extern unsigned _stp_num_kernel_symbols; +extern struct _stp_symbol _stp_kernel_symbols[]; -/* process the KERNEL symbols */ -static int _stp_do_symbols(const char __user *buf, int count) +/* initialize the kernel symbols */ +static int _stp_init_kernel_symbols(void) { - struct _stp_symbol *s; - unsigned datasize, num, unwindsize; + _stp_modules[0] = (struct _stp_module *)_stp_kzalloc(sizeof(struct _stp_module)); + if (_stp_modules[0] == NULL) { + errk("cannot allocate memory\n"); + return -EFAULT; + } + _stp_modules[0]->symbols = _stp_kernel_symbols; + _stp_modules[0]->num_symbols = _stp_num_kernel_symbols; + rwlock_init(&_stp_modules[0]->lock); + _stp_num_modules = 1; + + /* Note: 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]; + return 0; +} + +static void _stp_do_unwind_data(const char __user *buf, size_t count) +{ + u64 unwind_len; + unsigned long flags; + char name[STP_MODULE_NAME_LEN]; int i; + struct _stp_module *m; - switch (_stp_symbol_state) { - case 0: - if (count != sizeof(struct _stp_msg_symbol_hdr)) { - errk("count=%d\n", count); - return -EFAULT; - } - if (get_user(num, (unsigned __user *)buf)) - return -EFAULT; - if (get_user(datasize, (unsigned __user *)(buf+4))) - return -EFAULT; - 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, unwindsize); - if (_stp_modules[0] == NULL) { - errk("cannot allocate memory\n"); - return -EFAULT; + dbug_unwind(1, "got unwind data, count=%d\n", count); + + if (count < STP_MODULE_NAME_LEN + sizeof(u64)) { + dbug_unwind(1, "unwind message too short\n"); + return; + } + if (strncpy_from_user(name, buf, STP_MODULE_NAME_LEN) < 0) { + errk("userspace copy failed\n"); + return; + } + dbug_unwind(1, "name=%s\n", name); + if (!strcmp(name,"*")) { + /* OK, all initial unwind data received. Ready to go. */ + _stp_ctl_send(STP_TRANSPORT, NULL, 0); + return; + } + count -= STP_MODULE_NAME_LEN; + buf += STP_MODULE_NAME_LEN; + + if (get_user(unwind_len, (u64 __user *)buf)) { + errk("userspace copy failed\n"); + return; + } + count -= sizeof(u64); + buf += sizeof(u64); + if (count != unwind_len) { + dbug_unwind(1, "count=%d unwind_len=%d\n", (int)count, (int)unwind_len); + return; + } + + STP_RLOCK_MODULES; + for (i = 0; i < _stp_num_modules; i++) { + if (strcmp(name, _stp_modules[i]->name) == 0) + break; + } + if (unlikely(i == _stp_num_modules)) { + dbug_unwind(1, "module %s not found!\n", name); + STP_RUNLOCK_MODULES; + return; + } + m = _stp_modules[i]; + write_lock(&m->lock); + STP_RUNLOCK_MODULES; + + /* allocate space for unwind data */ + m->unwind_data = _stp_kmalloc(count); + if (unlikely(m->unwind_data == NULL)) { + m->unwind_data = _stp_vmalloc(count); + if (m->unwind_data == NULL) { + errk("kmalloc failed\n"); + goto done; } - rwlock_init(&_stp_modules[0]->lock); - _stp_symbol_state = 1; - break; - case 1: - 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: - 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; - - s = _stp_modules[0]->symbols; - for (i = 0; i < _stp_modules[0]->num_symbols; i++) - s[i].symbol += (long)_stp_modules[0]->symbol_data; - - _stp_symbol_state = 3; - /* 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]; - 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; + m->allocated.unwind_data = 1; + } + + if (unlikely(copy_from_user(m->unwind_data, buf, count))) { + errk("userspace copy failed\n"); + if (m->unwind_data) { + if (m->allocated.unwind_data) + _stp_vfree(m->unwind_data); + else + _stp_kfree(m->unwind_data); + m->unwind_data = NULL; } - _stp_modules[0]->unwind_data_len = count; - break; - default: - errk("unexpected symbol data of size %d.\n", count); + goto done; } - return count; + m->unwind_data_len = count; + _stp_create_unwind_hdr(m); +done: + write_unlock(&m->lock); } static int _stp_compare_addr(const void *p1, const void *p2) { struct _stp_symbol *s1 = (struct _stp_symbol *)p1; struct _stp_symbol *s2 = (struct _stp_symbol *)p2; - if (s1->addr == s2->addr) return 0; - if (s1->addr < s2->addr) return -1; + if (s1->addr == s2->addr) + return 0; + if (s1->addr < s2->addr) + return -1; return 1; } @@ -332,18 +339,17 @@ static void generic_swap(void *a, void *b, int size) * it less suitable for kernel use. */ void _stp_sort(void *base, size_t num, size_t size, - int (*cmp)(const void *, const void *), - void (*swap)(void *, void *, int size)) + int (*cmp) (const void *, const void *), void (*swap) (void *, void *, int size)) { /* pre-scale counters for performance */ - int i = (num/2 - 1) * size, n = num * size, c, r; + int i = (num / 2 - 1) * size, n = num * size, c, r; if (!swap) swap = (size == 4 ? u32_swap : generic_swap); /* heapify */ - for ( ; i >= 0; i -= size) { - for (r = i; r * 2 + size < n; r = c) { + for (; i >= 0; i -= size) { + for (r = i; r * 2 + size < n; r = c) { c = r * 2 + size; if (c < n - size && cmp(base + c, base + c + size) < 0) c += size; @@ -367,65 +373,114 @@ void _stp_sort(void *base, size_t num, size_t size, } } +/* filter out section names we don't care about */ +static int _stp_section_is_interesting(const char *name) +{ + int ret = 1; + if (!strncmp("__", name, 2) + || !strncmp(".note", name, 5) + || !strncmp(".gnu", name, 4) + || !strncmp(".mod", name, 4)) + ret = 0; + return ret; +} + /* Create a new _stp_module and load the symbols */ -static struct _stp_module *_stp_load_module_symbols (struct _stp_module *imod, uint32_t unwind_len) +static struct _stp_module *_stp_load_module_symbols(struct module *mod) { - unsigned i, num=0; - struct module *m = (struct module *)imod->module; - struct _stp_module *mod = NULL; - char *dataptr; + int i, num, overflow = 0; + struct module_sect_attrs *sa; + unsigned sect_size = 0, sect_num = 0, sym_size, sym_num; + struct _stp_module *sm; + char *dataptr, *endptr; + + sa = mod->sect_attrs; + /* calculate how much space to allocate for section strings */ + for (i = 0; i < sa->nsections; i++) { + if (_stp_section_is_interesting(sa->attrs[i].name)) { + sect_num++; + sect_size += strlen(sa->attrs[i].name) + 1; + dbug_sym(2, "\t%s\t%lx\n", sa->attrs[i].name, sa->attrs[i].address); + } + } + sect_size += sect_num * sizeof(struct _stp_symbol); + + /* and how much space for symbols */ + sym_num = _stp_get_sym_sizes(mod, &sym_size); - if (m == NULL) { - kbug(DEBUG_SYMBOLS, "imod->module is NULL\n"); + sm = _stp_alloc_module(sect_size, sym_num, sym_size); + if (!sm) { + errk("failed to allocate memory for module.\n"); return NULL; } - if (try_module_get(m)) { - mod = _stp_alloc_module_from_module(m, unwind_len); - if (mod == NULL) { - module_put(m); - errk("failed to allocate memory for module.\n"); - return NULL; - } + strlcpy(sm->name, mod->name, STP_MODULE_NAME_LEN); + sm->module = (unsigned long)mod; + sm->text = (unsigned long)mod->module_core; + sm->text_size = mod->core_text_size; + sm->data = 0; /* fixme */ + sm->num_sections = sect_num; + rwlock_init(&sm->lock); - strlcpy(mod->name, imod->name, STP_MODULE_NAME_LEN); - mod->module = imod->module; - mod->text = imod->text; - 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; - for (i=0; i < m->num_symtab; i++) { - char *str = (char *)(m->strtab + m->symtab[i].st_name); - if (*str != '\0' && _stp_sym_type_ok(m->symtab[i].st_info)) { - mod->symbols[num].symbol = dataptr; - mod->symbols[num].addr = m->symtab[i].st_value; - while (*str) *dataptr++ = *str++; - *dataptr++ = 0; - num++; + /* copy in section data */ + dataptr = (char *)((long)sm->sections + sect_num * sizeof(struct _stp_symbol)); + endptr = (char *)((long)sm->sections + sect_size); + num = 0; + for (i = 0; i < sa->nsections; i++) { + size_t len, maxlen; + if (_stp_section_is_interesting(sa->attrs[i].name)) { + sm->sections[num].addr = sa->attrs[i].address; + sm->sections[num].symbol = dataptr; + maxlen = (size_t) (endptr - dataptr); + len = strlcpy(dataptr, sa->attrs[i].name, maxlen); + if (unlikely(len >= maxlen)) { + _dbug("dataptr=%lx endptr=%lx len=%d maxlen=%d\n", dataptr, endptr, len, maxlen); + overflow = 1; } + dataptr += len + 1; + num++; } - module_put(m); + } + if (unlikely(overflow)) { + errk("Section names truncated!!! Should never happen!!\n"); + *endptr = 0; + overflow = 0; + } - /* sort symbols by address */ - _stp_sort (mod->symbols, num, sizeof(struct _stp_symbol), _stp_compare_addr, _stp_swap_symbol); + /* now copy all the symbols we are interested in */ + dataptr = sm->symbol_data; + endptr = dataptr + sym_size - 1; + num = 0; + for (i = 0; i < mod->num_symtab; i++) { + char *str = (char *)(mod->strtab + mod->symtab[i].st_name); + if (*str != '\0' && _stp_sym_type_ok(mod->symtab[i].st_info)) { + sm->symbols[num].symbol = dataptr; + sm->symbols[num].addr = mod->symtab[i].st_value; + while (*str && (dataptr < endptr)) + *dataptr++ = *str++; + if (unlikely(*str)) + overflow = 1; + *dataptr++ = 0; + num++; + } } - return mod; + if (unlikely(overflow)) + errk("Symbol names truncated!!! Should never happen!!\n"); + + /* sort symbols by address */ + _stp_sort(sm->symbols, num, sizeof(struct _stp_symbol), _stp_compare_addr, _stp_swap_symbol); + + return sm; } -/* Remove any old module info from our database */ -static void _stp_module_exists_delete (struct _stp_module *mod) +/* Remove any old module info from our database. */ +static void _stp_module_exists_delete(struct _stp_module *mod) { 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); + dbug_sym(1, "found existing module with name %s. Deleting.\n", mod->name); _stp_del_module(_stp_modules[num]); break; } @@ -435,143 +490,61 @@ static void _stp_module_exists_delete (struct _stp_module *mod) 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); + if (mod->text < _stp_modules_by_addr[num]->text + _stp_modules_by_addr[num]->text_size) { + dbug_sym(1, "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) +static void _stp_ins_module(struct module *mod) { - int i, num, res, ret = 0; + int i, num, res; unsigned long flags; - - // kbug(DEBUG_SYMBOLS, "insert %s\n", mod->name); + struct _stp_module *m; + dbug_sym(1, "insert %s\n", mod->name); + m = _stp_load_module_symbols(mod); + if (m == NULL) + return; STP_WLOCK_MODULES; - - _stp_module_exists_delete(mod); - + _stp_module_exists_delete(m); /* check for overflow */ if (_stp_num_modules == STP_MAX_MODULES) { errk("Exceeded the limit of %d modules\n", STP_MAX_MODULES); - ret = -ENOMEM; goto done; } - + /* insert alphabetically in _stp_modules[] */ for (num = 1; num < _stp_num_modules; num++) - if (strcmp(_stp_modules[num]->name, mod->name) > 0) + if (strcmp(_stp_modules[num]->name, m->name) > 0) break; for (i = _stp_num_modules; i > num; i--) - _stp_modules[i] = _stp_modules[i-1]; - _stp_modules[num] = mod; - + _stp_modules[i] = _stp_modules[i - 1]; + _stp_modules[num] = m; /* insert by text address in _stp_modules_by_addr[] */ for (num = 1; num < _stp_num_modules; num++) - if (mod->text < _stp_modules_by_addr[num]->text) + if (m->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_modules_by_addr[i] = _stp_modules_by_addr[i - 1]; + _stp_modules_by_addr[num] = m; _stp_num_modules++; - done: STP_WUNLOCK_MODULES; - return ret; + return; } - -/* Called from procfs.c when a STP_MODULE msg is received */ -static int _stp_do_module(const char __user *buf, int count) -{ - struct _stp_msg_module tmpmod; - struct _stp_module mod, *m; - unsigned i, section_len; - - if (count < (int)sizeof(tmpmod)) { - errk("expected %d and got %d\n", (int)sizeof(tmpmod), count); - return -EFAULT; - } - if (copy_from_user ((char *)&tmpmod, buf, sizeof(tmpmod))) - return -EFAULT; - - section_len = count - sizeof(tmpmod) - tmpmod.unwind_len; - if (section_len <= 0) { - errk("section_len = %d\n", section_len); - return -EFAULT; - } - 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; - mod.text = tmpmod.text; - mod.data = tmpmod.data; - mod.num_sections = tmpmod.num_sections; - - /* copy in section data */ - mod.sections = _stp_kmalloc(section_len); - if (mod.sections == NULL) { - errk("unable to allocate memory.\n"); - return -EFAULT; - } - if (copy_from_user ((char *)mod.sections, buf+sizeof(tmpmod), section_len)) { - _stp_kfree(mod.sections); - return -EFAULT; - } - for (i = 0; i < mod.num_sections; i++) { - mod.sections[i].symbol = - (char *)((long)mod.sections[i].symbol - + (long)((long)mod.sections + mod.num_sections * sizeof(struct _stp_symbol))); - } - - #if 0 - for (i = 0; i < mod.num_sections; i++) - _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, 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; - } - - return count; -} - -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) +static int _stp_module_load_notify(struct notifier_block *self, unsigned long val, void *data) { struct module *mod = (struct module *)data; struct _stp_module rmod; - switch (val) { case MODULE_STATE_COMING: - 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)); + dbug_sym(1, "module %s load notify\n", mod->name); + _stp_ins_module(mod); break; default: errk("module loaded? val=%ld\n", val); @@ -583,4 +556,63 @@ static struct notifier_block _stp_module_load_nb = { .notifier_call = _stp_module_load_notify, }; -#endif /* _SYMBOLS_C_ */ +#include <linux/seq_file.h> +extern unsigned long _stp_modules_op; /* from stap */ +static int _stp_init_modules(void) +{ + loff_t pos = 0; + void *res; + struct module *mod; + + const struct seq_operations *modules_op = (const struct seq_operations *)_stp_modules_op; + /* Use the seq_file interface to safely get a list of installed modules */ + res = modules_op->start(NULL, &pos); + while (res) { + mod = list_entry(res, struct module, list); + _stp_ins_module(mod); + res = modules_op->next(NULL, res, &pos); + } + + if (register_module_notifier(&_stp_module_load_nb)) + errk("failed to load module notifier\n"); + + /* unlocks the list */ + modules_op->stop(NULL, NULL); + +#ifndef CONFIG_FRAME_POINTER + /* now that we have all the modules, ask for their unwind info */ + { + unsigned long flags; + int i, left = STP_CTL_BUFFER_SIZE; + char buf[STP_CTL_BUFFER_SIZE]; + char *ptr = buf; + *ptr = 0; + + STP_RLOCK_MODULES; + /* Loop through modules, sending module names packed into */ + /* messages of size STP_CTL_BUFFER. */ + for (i = 0; i < _stp_num_modules; i++) { + char *name = _stp_modules[i]->name; + int len = strlen(name); + if (len >= left) { + _stp_ctl_send(STP_UNWIND, buf, sizeof(buf) - left); + ptr = buf; + left = STP_CTL_BUFFER_SIZE; + } + strlcpy(ptr, name, left); + ptr += len + 1; + left -= len + 1; + } + STP_RUNLOCK_MODULES; + + /* Send terminator. When we get this back from stapio */ + /* that means all the unwind info has been sent. */ + strlcpy(ptr, "*", left); + left -= 2; + _stp_ctl_send(STP_UNWIND, buf, sizeof(buf) - left); + } +#endif + return 0; +} + +#endif /* _STP_SYMBOLS_C_ */ |