summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--runtime/ChangeLog7
-rw-r--r--runtime/sym.c101
-rw-r--r--runtime/sym.h30
-rw-r--r--runtime/transport/ChangeLog4
-rw-r--r--runtime/transport/symbols.c25
-rw-r--r--translate.cxx97
7 files changed, 138 insertions, 134 deletions
diff --git a/ChangeLog b/ChangeLog
index c1765617..edae2994 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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();