diff options
author | Frank Ch. Eigler <fche@elastic.org> | 2008-07-17 06:42:45 -0400 |
---|---|---|
committer | Frank Ch. Eigler <fche@elastic.org> | 2008-07-17 06:42:45 -0400 |
commit | 7795c7e74987876f71fe85ab9119b8810e8897f0 (patch) | |
tree | 44761281ec3f8752b3adc055448945ef600e880c | |
parent | 4464a6bb1793076b3fa85a25c5a489cd9ef7d367 (diff) | |
download | systemtap-steved-7795c7e74987876f71fe85ab9119b8810e8897f0.tar.gz systemtap-steved-7795c7e74987876f71fe85ab9119b8810e8897f0.tar.xz systemtap-steved-7795c7e74987876f71fe85ab9119b8810e8897f0.zip |
support multiple-relocatable-section modules such as hypothetical -ffunction-sections .ko's
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | runtime/ChangeLog | 7 | ||||
-rw-r--r-- | runtime/sym.c | 101 | ||||
-rw-r--r-- | runtime/sym.h | 30 | ||||
-rw-r--r-- | runtime/transport/ChangeLog | 4 | ||||
-rw-r--r-- | runtime/transport/symbols.c | 25 | ||||
-rw-r--r-- | translate.cxx | 97 |
7 files changed, 138 insertions, 134 deletions
@@ -1,3 +1,11 @@ +2008-07-17 Frank Ch. Eigler <fche@elastic.org> + + * translate.cxx (dump_unwindsyms): Produce symbol tables and section + lists for all text-like sections, useful for -ffunction-sections type + kernel modules. + (emit_symbol_data): Tolerate missing unwind/symbol data during + elf processing. Subsequently warn about anything missing. + 2008-07-16 Frank Ch. Eigler <fche@elastic.org> * configure.ac: Bumped version to 0.7.1. diff --git a/runtime/ChangeLog b/runtime/ChangeLog index 4fe2d033..025a7b86 100644 --- a/runtime/ChangeLog +++ b/runtime/ChangeLog @@ -1,3 +1,10 @@ +2008-07-17 Frank Ch. Eigler <fche@elastic.org> + + * sym.c (_stp_kallsyms_lookup, _stp_module_relocate): Add + multiple-section-per-module support. + * sym.h (_stp_section): New type for separately relocatable + _stp_module pieces. + 2008-07-12 Frank Ch. Eigler <fche@elastic.org> PR 6738. diff --git a/runtime/sym.c b/runtime/sym.c index 178c6219..dcdbaf69 100644 --- a/runtime/sym.c +++ b/runtime/sym.c @@ -20,10 +20,11 @@ * @{ */ +/* XXX: this needs to be address-space-specific. */ 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; + static struct _stp_section *last_sec; unsigned long flags; unsigned i, j; @@ -42,7 +43,7 @@ unsigned long _stp_module_relocate(const char *module, const char *section, unsi /* 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->name)) { offset += last_sec->addr; dbug_sym(1, "cached address=%lx\n", offset); return offset; @@ -55,7 +56,7 @@ unsigned long _stp_module_relocate(const char *module, const char *section, unsi continue; for (j = 0; j < last->num_sections; j++) { last_sec = &last->sections[j]; - if (!strcmp(section, last_sec->symbol)) { + if (!strcmp(section, last_sec->name)) { if (last_sec->addr == 0) /* module/section not in memory */ continue; @@ -72,73 +73,69 @@ unsigned long _stp_module_relocate(const char *module, const char *section, unsi } -/* Return the module that likely contains the given address. */ -/* XXX: This query only makes sense with respect to a particular - address space. A more general interface would have to identify - the address space, and also pass back the section. */ -static struct _stp_module *_stp_find_module_by_addr(unsigned long addr) -{ - unsigned i; - struct _stp_module *closest_module = NULL; - unsigned long closest_module_offset = ~0; /* minimum[addr - module->.text] */ - - for (i=0; i<_stp_num_modules; i++) - { - unsigned long module_text_addr, this_module_offset; - - if (_stp_modules[i]->num_sections < 1) continue; - module_text_addr = _stp_modules[i]->sections[0].addr; /* XXX: assume section[0]=>text */ - if (addr < module_text_addr) continue; - this_module_offset = module_text_addr - addr; - - if (this_module_offset < closest_module_offset) - { - closest_module = _stp_modules[i]; - closest_module_offset = this_module_offset; - } - } - - return closest_module; -} - - - +/* XXX: needs to be address-space-specific. */ static const char *_stp_kallsyms_lookup(unsigned long addr, unsigned long *symbolsize, - unsigned long *offset, char **modname, char *namebuf) + unsigned long *offset, + const char **modname, + /* char ** secname? */ + char *namebuf) { - struct _stp_module *m; - struct _stp_symbol *s; + struct _stp_module *m = NULL; + struct _stp_section *sec = NULL; + struct _stp_symbol *s = NULL; unsigned long flags; unsigned end, begin = 0; - m = _stp_find_module_by_addr(addr); - if (unlikely(m == NULL)) { - return NULL; - } - - /* NB: relativize the address to the (XXX) presumed text section. */ - addr -= m->sections[0].addr; - end = m->num_symbols; + /* Find the closest section (and its owner module); fill in m & sec. */ + { + unsigned midx = 0; + unsigned long closest_section_offset = ~0; + for (midx = 0; midx < _stp_num_modules; midx++) + { + unsigned secidx; + for (secidx = 0; secidx < _stp_modules[midx]->num_sections; secidx++) + { + unsigned long this_section_addr = _stp_modules[midx]->sections[secidx].addr; + unsigned long this_section_offset; + if (addr < this_section_addr) continue; + this_section_offset = this_section_addr - addr; + if (this_section_offset < closest_section_offset) + { + closest_section_offset = this_section_offset; + m = _stp_modules[midx]; + sec = & m->sections[secidx]; + } + } + } + } + + if (unlikely (m == NULL || sec == NULL)) + return NULL; + + /* NB: relativize the address to the section. */ + addr -= sec->addr; + end = sec->num_symbols; /* binary search for symbols within the module */ do { unsigned mid = (begin + end) / 2; - if (addr < m->symbols[mid].addr) + if (addr < sec->symbols[mid].addr) end = mid; else begin = mid; } while (begin + 1 < end); /* result index in $begin */ - s = &m->symbols[begin]; + s = & sec->symbols[begin]; if (likely(addr >= s->addr)) { if (offset) *offset = addr - s->addr; if (modname) *modname = m->name; + /* We could also pass sec->name here. */ if (symbolsize) { - if ((begin + 1) < m->num_symbols) - *symbolsize = m->symbols[begin + 1].addr - s->addr; + if ((begin + 1) < sec->num_symbols) + *symbolsize = sec->symbols[begin + 1].addr - s->addr; else *symbolsize = 0; // NB: This is only a heuristic. Sometimes there are large @@ -163,7 +160,7 @@ static const char *_stp_kallsyms_lookup(unsigned long addr, unsigned long *symbo void _stp_symbol_print(unsigned long address) { - char *modname; + const char *modname; const char *name; unsigned long offset, size; @@ -182,7 +179,7 @@ void _stp_symbol_print(unsigned long address) /* Like _stp_symbol_print, except only print if the address is a valid function address */ int _stp_func_print(unsigned long address, int verbose, int exact) { - char *modname; + const char *modname; const char *name; unsigned long offset, size; char *exstr; @@ -210,7 +207,7 @@ int _stp_func_print(unsigned long address, int verbose, int exact) void _stp_symbol_snprint(char *str, size_t len, unsigned long address) { - char *modname; + const char *modname; const char *name; unsigned long offset, size; diff --git a/runtime/sym.h b/runtime/sym.h index c7caacae..b2fb8ee9 100644 --- a/runtime/sym.h +++ b/runtime/sym.h @@ -10,28 +10,30 @@ #ifndef _STP_SYM_H_ #define _STP_SYM_H_ -#define STP_MODULE_NAME_LEN 64 - struct _stp_symbol { unsigned long addr; const char *symbol; }; +struct _stp_section { + const char *name; + unsigned long addr; /* XXX: belongs in per-address-space tables */ + struct _stp_symbol *symbols; /* ordered by address */ + unsigned num_symbols; +}; + + struct _stp_module { - /* the module name, or "" for kernel */ - char name[STP_MODULE_NAME_LEN]; - + const char* name; + struct _stp_section *sections; + unsigned num_sections; + /* A pointer to the struct module. Note that we cannot */ /* trust this because as of 2.6.19, there are not yet */ /* any notifier hooks that will tell us when a module */ /* is unloading. */ unsigned long module; /* XXX: why not struct module * ? */ - struct _stp_symbol *sections; - unsigned num_sections; - struct _stp_symbol *symbols; /* ordered by address */ - unsigned num_symbols; - /* the stack unwind data for this module */ void *unwind_data; void *unwind_hdr; @@ -43,13 +45,8 @@ struct _stp_module { /* Defined by translator-generated stap-symbols.h. */ struct _stp_module *_stp_modules []; -int _stp_num_modules; - +unsigned _stp_num_modules; -#if 0 -/* the array of modules ordered by addresses */ -struct _stp_module *_stp_modules_by_addr[STP_MAX_MODULES]; -#endif /* the number of modules in the arrays */ @@ -57,4 +54,5 @@ static unsigned long _stp_kretprobe_trampoline = 0; unsigned long _stp_module_relocate (const char *module, const char *section, unsigned long offset); static struct _stp_module *_stp_get_unwind_info (unsigned long addr); + #endif /* _STP_SYM_H_ */ diff --git a/runtime/transport/ChangeLog b/runtime/transport/ChangeLog index f766e138..693f06d1 100644 --- a/runtime/transport/ChangeLog +++ b/runtime/transport/ChangeLog @@ -1,3 +1,7 @@ +2008-07-17 Frank Ch. Eigler <fche@elastic.org> + + * symbols.c (_stp_do_relocation): Adapt to stp_module decl changes. + 2008-07-12 Frank Ch. Eigler <fche@elastic.org> PR 6738. diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c index c868c5fd..4bdd0904 100644 --- a/runtime/transport/symbols.c +++ b/runtime/transport/symbols.c @@ -53,7 +53,7 @@ static void _stp_do_relocation(const char __user *buf, size_t count) for (si=0; si<_stp_modules[mi]->num_sections; si++) { - if (strcmp (_stp_modules[mi]->sections[si].symbol, msg.reloc)) + if (strcmp (_stp_modules[mi]->sections[si].name, msg.reloc)) continue; _stp_modules[mi]->sections[si].addr = msg.address; @@ -62,29 +62,6 @@ static void _stp_do_relocation(const char __user *buf, size_t count) } -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; - return 1; -} - -static void _stp_swap_symbol(void *x, void *y, int size) -{ - struct _stp_symbol *a = (struct _stp_symbol *)x; - struct _stp_symbol *b = (struct _stp_symbol *)y; - unsigned long addr = a->addr; - const char *symbol = a->symbol; - a->addr = b->addr; - a->symbol = b->symbol; - b->addr = addr; - b->symbol = symbol; -} - static void u32_swap(void *a, void *b, int size) { u32 t = *(u32 *)a; diff --git a/translate.cxx b/translate.cxx index 90d5536c..c69dc201 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4344,7 +4344,7 @@ dump_unwindsyms (Dwfl_Module *m, { unwindsym_dump_context* c = (unwindsym_dump_context*) arg; assert (c); - unsigned real_stpmodules_index = c->stp_module_index; + unsigned stpmod_idx = c->stp_module_index; string modname = name; @@ -4356,14 +4356,16 @@ dump_unwindsyms (Dwfl_Module *m, if (c->session.verbose > 1) clog << "dump_unwindsyms " << name - << " index=" << real_stpmodules_index + << " index=" << stpmod_idx << " base=0x" << hex << base << dec << endl; // We want to extract several bits of information: + // // - parts of the program-header that map the file's physical offsets to the text section // - section table: just a list of section (relocation) base addresses - // - symbol table of the text section, with all addresses relativized to .text base + // - symbol table of the text-like sections, with all addresses relativized to each base // - the contents of .debug_frame section, for unwinding purposes + // // In the future, we'll also care about data symbols. int syments = dwfl_module_getsymtab(m); @@ -4374,22 +4376,16 @@ dump_unwindsyms (Dwfl_Module *m, dwfl_assert ("dwfl_module_relocations", n >= 0); - c->output << "struct _stp_symbol _stp_module_" << real_stpmodules_index<< "_sections[] = {" << endl; - if (n > 0 && modname != "kernel") - c->output << " { 0, \".text\" }, " << endl; // XXX - else if (n >= 0 && modname == "kernel") - c->output << " { 0, \"_stext\" }, " << endl; - c->output << "};" << endl; - // XXX: unfortunate duplication with tapsets.cxx:emit_address() typedef map<Dwarf_Addr,const char*> addrmap_t; // NB: plain map, sorted by address - addrmap_t addrmap; // NB: plain map, sorted by address - + vector<string> seclist; // encountered relocation bases (section names) + map<unsigned, addrmap_t> addrmap; // per-relocation-base sorted addrmap + Dwarf_Addr extra_offset = 0; - for (int i = 1; i < syments; ++i) + for (int i = 1 /* XXX: why not 0? */ ; i < syments; ++i) { GElf_Sym sym; const char *name = dwfl_module_getsym(m, i, &sym, NULL); @@ -4423,52 +4419,69 @@ dump_unwindsyms (Dwfl_Module *m, if (n == 1 && modname == "kernel" && secname && secname[0] == '\0') { // This is a symbol within a relocatable kernel image. - secname = "_stext"; // not actually used + secname = "_stext"; // NB: don't subtract session.sym_stext, which could be inconveniently NULL. + // Instead, sym_addr will get compensated later via extra_offset. } - else if (n > 0 && strcmp (secname, ".text")) /* XXX: only care about .text-related relocations for now. */ + else if (n > 0) { - if (c->session.verbose > 2) - clog << "Skipped symbol " << name << ", due to non-.text relocation section " << secname << endl; - continue; + assert (secname != NULL); + // secname adequately set } - else if (n == 0) + else { + assert (n == 0); // sym_addr is absolute, as it must be since there are no relocation bases + secname = ".absolute"; // sentinel } - else - { - // sym_addr has already been relocated relative to .text - } - addrmap[sym_addr] = name; + // Compute our section number + unsigned secidx; + for (secidx=0; secidx<seclist.size(); secidx++) + if (seclist[secidx]==secname) break; + + if (secidx == seclist.size()) // new section name + seclist.push_back (secname); + + (addrmap[secidx])[sym_addr] = name; } } } - // We write out a *sorted* symbol table, so the runtime doesn't have to sort them later. - c->output << "struct _stp_symbol _stp_module_" << real_stpmodules_index<< "_symbols[] = {" << endl; - for (addrmap_t::iterator it = addrmap.begin(); it != addrmap.end(); it++) + for (unsigned secidx = 0; secidx < seclist.size(); secidx++) { - if (it->first < extra_offset) - continue; // skip symbols that occur before our chosen base address + c->output << "struct _stp_symbol " + << "_stp_module_" << stpmod_idx<< "_symbols_" << secidx << "[] = {" << endl; - c->output << " { 0x" << hex << it->first-extra_offset << dec - << ", " << lex_cast_qstring (it->second) << " }," << endl; + // We write out a *sorted* symbol table, so the runtime doesn't have to sort them later. + for (addrmap_t::iterator it = addrmap[secidx].begin(); it != addrmap[secidx].end(); it++) + { + if (it->first < extra_offset) + continue; // skip symbols that occur before our chosen base address + + c->output << " { 0x" << hex << it->first-extra_offset << dec + << ", " << lex_cast_qstring (it->second) << " }," << endl; + } + c->output << "};" << endl; + } + + c->output << "struct _stp_section _stp_module_" << stpmod_idx<< "_sections[] = {" << endl; + for (unsigned secidx = 0; secidx < seclist.size(); secidx++) + { + c->output << "{" << endl + << ".name = " << lex_cast_qstring(seclist[secidx]) << "," << endl + << ".symbols = _stp_module_" << stpmod_idx << "_symbols_" << secidx << "," << endl + << ".num_symbols = sizeof(_stp_module_" << stpmod_idx << "_symbols_" << secidx << ")/sizeof(struct _stp_symbol)" << endl + << "}," << endl; } c->output << "};" << endl; - c->output << "struct _stp_module _stp_module_" << real_stpmodules_index << " = {" << endl; + c->output << "struct _stp_module _stp_module_" << stpmod_idx << " = {" << endl; c->output << ".name = " << lex_cast_qstring (modname) << ", " << endl; - - c->output << ".sections = _stp_module_" << real_stpmodules_index << "_sections" << ", " << endl; - c->output << ".num_sections = sizeof(_stp_module_" << real_stpmodules_index << "_sections)/" - << "sizeof(struct _stp_symbol), " << endl; + c->output << ".sections = _stp_module_" << stpmod_idx << "_sections" << ", " << endl; + c->output << ".num_sections = sizeof(_stp_module_" << stpmod_idx << "_sections)/" + << "sizeof(struct _stp_section), " << endl; - c->output << ".symbols = _stp_module_" << real_stpmodules_index << "_symbols" << ", " << endl; - c->output << ".num_symbols = sizeof(_stp_module_" << real_stpmodules_index << "_symbols)/" - << "sizeof(struct _stp_symbol), " << endl; - c->output << "};" << endl << endl; c->undone_unwindsym_modules.erase (modname); @@ -4552,7 +4565,7 @@ emit_symbol_data (systemtap_session& s) dwfl_report_begin (dwfl); Dwfl_Module* mod = dwfl_report_offline (dwfl, modname.c_str(), modname.c_str(), -1); dwfl_report_end (dwfl, NULL, NULL); - if (mod != 0) // tolerate missing data; will inform user + if (mod != 0) // tolerate missing data; will warn below { ptrdiff_t off = 0; do @@ -4575,7 +4588,7 @@ emit_symbol_data (systemtap_session& s) kallsyms_out << "& _stp_module_" << i << "," << endl; } kallsyms_out << "};" << endl; - kallsyms_out << "int _stp_num_modules = " << ctx.stp_module_index << ";" << endl; + kallsyms_out << "unsigned _stp_num_modules = " << ctx.stp_module_index << ";" << endl; // Some nonexistent modules may have been identified with "-d". Note them. for (set<string>::iterator it = ctx.undone_unwindsym_modules.begin(); |