diff options
Diffstat (limited to 'tapsets.cxx')
-rw-r--r-- | tapsets.cxx | 168 |
1 files changed, 79 insertions, 89 deletions
diff --git a/tapsets.cxx b/tapsets.cxx index 7db0fc0a..a2e75420 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -15,6 +15,7 @@ #include "session.h" #include "util.h" #include "dwarf_wrappers.h" +#include "auto_free.h" #include <cstdlib> #include <algorithm> @@ -488,6 +489,27 @@ func_info Dwarf_Addr addr; Dwarf_Addr prologue_end; bool weak; + // Comparison functor for list of functions sorted by address. The + // two versions that take a Dwarf_Addr let us use the STL algorithms + // upper_bound, equal_range et al., but we don't know whether the + // searched-for value will be passed as the first or the second + // argument. + struct Compare + { + bool operator() (const func_info* f1, const func_info* f2) const + { + return f1->addr < f2->addr; + } + // For doing lookups by address. + bool operator() (Dwarf_Addr addr, const func_info* f2) const + { + return addr < f2->addr; + } + bool operator() (const func_info* f1, Dwarf_Addr addr) const + { + return f1->addr < addr; + } + }; }; struct @@ -566,12 +588,16 @@ symbol_table module_info *mod_info; // associated module map<string, func_info*> map_by_name; vector<func_info*> list_by_addr; + typedef vector<func_info*>::iterator iterator_t; + typedef pair<iterator_t, iterator_t> range_t; #ifdef __powerpc__ GElf_Word opd_section; #endif - + // add_symbol doesn't leave symbol table in order; call + // symbol_table::sort() when done adding symbols. void add_symbol(const char *name, bool weak, Dwarf_Addr addr, Dwarf_Addr *high_addr); + void sort(); enum info_status read_symbols(FILE *f, const string& path); enum info_status read_from_elf_file(const string& path); enum info_status read_from_text_file(const string& path); @@ -583,7 +609,6 @@ symbol_table func_info *lookup_symbol(const string& name); Dwarf_Addr lookup_symbol_address(const string& name); func_info *get_func_containing_address(Dwarf_Addr addr); - int get_index_for_address(Dwarf_Addr addr); symbol_table(module_info *mi) : mod_info(mi) {} ~symbol_table(); @@ -1183,7 +1208,7 @@ struct dwflpp dwarf_getsrc_file (module_dwarf, srcfile, l, 0, &srcsp, &nsrcs)); - + auto_free srcsp_af(srcsp); if (line_type == WILDCARD || line_type == RANGE) { Dwarf_Addr line_addr; @@ -1247,24 +1272,15 @@ struct dwflpp throw semantic_error (advice.str()); } - try - { - for (size_t i = 0; i < nsrcs; ++i) - { - if (pending_interrupts) return; - if (srcsp [i]) // skip over mismatched lines - callback (dwarf_line_t(srcsp[i]), data); - } - } - catch (...) - { - free (srcsp); - throw; - } - if (line_type != WILDCARD || l == lines[1]) - break; + for (size_t i = 0; i < nsrcs; ++i) + { + if (pending_interrupts) return; + if (srcsp [i]) // skip over mismatched lines + callback (dwarf_line_t(srcsp[i]), data); + } + if (line_type != WILDCARD || l == lines[1]) + break; } - free (srcsp); } @@ -2695,12 +2711,12 @@ dwarf_query::query_module_symtab() << endl; return; } - - size_t i; - size_t nsyms = sym_table->list_by_addr.size(); - for (i = 0; i < nsyms; i++) + symbol_table::iterator_t iter; + for (iter = sym_table->list_by_addr.begin(); + iter != sym_table->list_by_addr.end(); + ++iter) { - fi = sym_table->list_by_addr.at(i); + fi = *iter; if (!null_die(&fi->die)) continue; // already handled in query_module_dwarf() if (dw.function_name_matches_pattern(fi->name, function_str_val)) @@ -4741,14 +4757,8 @@ dwarf_builder::build(systemtap_session & sess, symbol_table::~symbol_table() { - // map::clear() and vector::clear() don't call destructors for - // pointers, only for objects. - int i; - int nsym = (int) list_by_addr.size(); - for (i = 0; i < nsym; i++) - delete list_by_addr.at(i); - list_by_addr.clear(); - map_by_name.clear(); + for (iterator_t i = list_by_addr.begin(); i != list_by_addr.end(); ++i) + delete *i; } void @@ -4767,18 +4777,7 @@ symbol_table::add_symbol(const char *name, bool weak, Dwarf_Addr addr, map_by_name[fi->name] = fi; // TODO: Use a multimap in case there are multiple static // functions with the same name? - if (addr >= *high_addr) - { - list_by_addr.push_back(fi); - *high_addr = addr; - } - else - { - // Symbols aren't in numerical order. FWIW, sort(1) doesn't - // handle hex numbers without the leading 0x. - int index = get_index_for_address(fi->addr); - list_by_addr.insert(list_by_addr.begin()+(index+1), fi); - } + list_by_addr.push_back(fi); } enum info_status @@ -4786,7 +4785,8 @@ symbol_table::read_symbols(FILE *f, const string& path) { // Based on do_kernel_symbols() in runtime/staprun/symbols.c int ret; - char *name, *mod; + char *name = 0; + char *mod = 0; char type; unsigned long long addr; Dwarf_Addr high_addr = 0; @@ -4795,6 +4795,8 @@ symbol_table::read_symbols(FILE *f, const string& path) // %as (non-POSIX) mallocs space for the string and stores its address. while ((ret = fscanf(f, "%llx %c %as [%as", &addr, &type, &name, &mod)) > 0) { + auto_free free_name(name); + auto_free free_mod(mod); line++; if (ret < 3) { @@ -4806,26 +4808,23 @@ symbol_table::read_symbols(FILE *f, const string& path) // Caller should delete symbol_table object. return info_absent; } - if (ret > 3) + else if (ret > 3) { // Modules are loaded above the kernel, so if we're getting // modules, we're done. - free(name); - free(mod); - goto done; + break; } if (type == 'T' || type == 't' || type == 'W') add_symbol(name, (type == 'W'), (Dwarf_Addr) addr, &high_addr); - free(name); } -done: if (list_by_addr.size() < 1) { cerr << "Symbol table error: " << path << " contains no function symbols." << endl; return info_absent; } + sort(); return info_present; } @@ -4937,6 +4936,7 @@ symbol_table::get_from_elf() add_symbol(name, (GELF_ST_BIND(sym.st_info) == STB_WEAK), sym.st_value, &high_addr); } + sort(); return info_present; } @@ -4978,35 +4978,12 @@ symbol_table::mark_dwarf_redundancies(dwflpp *dw) func_info * symbol_table::get_func_containing_address(Dwarf_Addr addr) { - int index = get_index_for_address(addr); - if (index < 0) + iterator_t iter = upper_bound(list_by_addr.begin(), list_by_addr.end(), addr, + func_info::Compare()); + if (iter == list_by_addr.begin()) return NULL; - return list_by_addr.at(index); -} - -// Find the index in list_by_addr of the last element whose address -// is <= addr. Returns -1 if addr is less than the first address in -// list_by_addr. -int -symbol_table::get_index_for_address(Dwarf_Addr addr) -{ - // binary search from runtime/sym.c - int begin = 0; - int mid; - int end = list_by_addr.size(); - - if (end == 0 || addr < list_by_addr.at(0)->addr) - return -1; - do - { - mid = (begin + end) / 2; - if (addr < list_by_addr.at(mid)->addr) - end = mid; - else - begin = mid; - } - while (begin + 1 < end); - return begin; + else + return *(iter - 1); } func_info * @@ -5041,17 +5018,30 @@ symbol_table::purge_syscall_stubs() Dwarf_Addr stub_addr = lookup_symbol_address("sys_ni_syscall"); if (stub_addr == 0) return; - for (size_t i = 0; i < list_by_addr.size(); i++) - { - func_info *fi = list_by_addr.at(i); - if (fi->weak && fi->addr == stub_addr && fi->name != "sys_ni_syscall") + range_t purge_range = equal_range(list_by_addr.begin(), list_by_addr.end(), + stub_addr, func_info::Compare()); + for (iterator_t iter = purge_range.first; + iter != purge_range.second; + ++iter) + { + func_info *fi = *iter; + if (fi->weak && fi->name != "sys_ni_syscall") { - list_by_addr.erase(list_by_addr.begin()+i); - map_by_name.erase(fi->name); - delete fi; - i--; - } + map_by_name.erase(fi->name); + delete fi; + *iter = 0; + } } + // Range might have null pointer entries that should be erased. + list_by_addr.erase(remove(purge_range.first, purge_range.second, + (func_info*)0), + purge_range.second); +} + +void +symbol_table::sort() +{ + stable_sort(list_by_addr.begin(), list_by_addr.end(), func_info::Compare()); } void |