From 9aa8ffcea9980d24cc9c9f13d9dd51e46e6283bf Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 9 Sep 2009 15:45:28 -0700 Subject: PR10594: Provide a cached dwarf_getscopes_die This avoids repeated DIE traversal by caching all parents on the first call, so future calls are just a simple walk up parent links. * dwflpp.cxx (dwflpp::getscopes_die): New cached function that mimics libdw's dwarf_getscopes_die using cached parent links. (dwflpp::cache_die_parents): New function to build the parent cache. (dwflpp::~dwflpp): Clean up the parent caches. (dwflpp::iterate_over_labels): Use the cached getscopes_die. (dwflpp::find_variable_and_frame_base): Ditto. * tapsets.cxx (dwarf_derived_probe::saveargs): Ditto. (uprobe_derived_probe::saveargs): Ditto. (dwarf_var_expanding_visitor::visit_target_symbol_context): Ditto. --- dwflpp.cxx | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- dwflpp.h | 11 +++++++ tapsets.cxx | 27 +++++++--------- 3 files changed, 121 insertions(+), 20 deletions(-) diff --git a/dwflpp.cxx b/dwflpp.cxx index 2437630e..d96f3eda 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -56,6 +56,10 @@ extern "C" { } +// debug flag to compare to the uncached version from libdw +// #define DEBUG_DWFLPP_GETSCOPES 1 + + using namespace std; using namespace __gnu_cxx; @@ -110,6 +114,10 @@ dwflpp::~dwflpp() it != global_alias_cache.end(); ++it) delete it->second; + for (mod_cu_die_parent_cache_t::iterator it = cu_die_parent_cache.begin(); + it != cu_die_parent_cache.end(); ++it) + delete it->second; + if (dwfl) dwfl_end(dwfl); } @@ -591,6 +599,89 @@ dwflpp::iterate_over_inline_instances (int (* callback)(Dwarf_Die * die, void * } +void +dwflpp::cache_die_parents(cu_die_parent_cache_t* parents, Dwarf_Die* die) +{ + // Record and recurse through DIEs we care about + Dwarf_Die child, import; + if (dwarf_child(die, &child) == 0) + do + { + switch (dwarf_tag (&child)) + { + // normal tags to recurse + case DW_TAG_compile_unit: + case DW_TAG_module: + case DW_TAG_lexical_block: + case DW_TAG_with_stmt: + case DW_TAG_catch_block: + case DW_TAG_try_block: + case DW_TAG_entry_point: + case DW_TAG_inlined_subroutine: + case DW_TAG_subprogram: + parents->insert(make_pair(child.addr, *die)); + cache_die_parents(parents, &child); + break; + + // record only, nothing to recurse + case DW_TAG_label: + parents->insert(make_pair(child.addr, *die)); + break; + + // imported dies should be followed + case DW_TAG_imported_unit: + if (dwarf_attr_die(&child, DW_AT_import, &import)) + { + parents->insert(make_pair(import.addr, *die)); + cache_die_parents(parents, &import); + } + break; + + // nothing to do for other tags + default: + break; + } + } + while (dwarf_siblingof(&child, &child) == 0); +} + + +vector +dwflpp::getscopes_die(Dwarf_Die* die) +{ + assert (cu); + + cu_die_parent_cache_t *parents = cu_die_parent_cache[cu->addr]; + if (!parents) + { + parents = new cu_die_parent_cache_t; + cu_die_parent_cache[cu->addr] = parents; + cache_die_parents(parents, cu); + if (sess.verbose > 4) + clog << "die parent cache " << module_name << ":" << cu_name() + << " size " << parents->size() << endl; + } + + vector scopes; + scopes.push_back(*die); + for (cu_die_parent_cache_t::iterator it = parents->find(die->addr); + it != parents->end(); it = parents->find(it->second.addr)) + scopes.push_back(it->second); + +#ifdef DEBUG_DWFLPP_GETSCOPES + Dwarf_Die *dscopes; + int nscopes = dwarf_getscopes_die(die, &dscopes); + + assert(nscopes == (int)scopes.size()); + for (unsigned i = 0; i < scopes.size(); ++i) + assert(scopes[i].addr == dscopes[i].addr); + free(dscopes); +#endif + + return scopes; +} + + int dwflpp::global_alias_caching_callback(Dwarf_Die *die, void *arg) { @@ -1025,9 +1116,8 @@ dwflpp::iterate_over_labels (Dwarf_Die *begin_die, Dwarf_Addr stmt_addr; if (dwarf_lowpc (&die, &stmt_addr) == 0) { - Dwarf_Die *scopes; - int nscopes = dwarf_getscopes_die (&die, &scopes); - if (nscopes > 1) + vector scopes = getscopes_die(&die); + if (scopes.size() > 1) callback(current_function, name, file, dline, &scopes[1], stmt_addr, q); } @@ -1491,6 +1581,7 @@ dwflpp::find_variable_and_frame_base (Dwarf_Die *scope_die, * as returned by dwarf_getscopes for the address, starting with the * declaring_scope that the variable was found in. */ + vector vscopes; for (int inner = declaring_scope; inner < nscopes && fb_attr == NULL; ++inner) @@ -1511,8 +1602,10 @@ dwflpp::find_variable_and_frame_base (Dwarf_Die *scope_die, * subroutine is inlined to find the appropriate frame base. */ if (declaring_scope != -1) { - nscopes = dwarf_getscopes_die (&scopes[inner], &scopes); - if (nscopes == -1) + vscopes = getscopes_die(&scopes[inner]); + scopes = &vscopes[0]; + nscopes = vscopes.size(); + if (!nscopes) throw semantic_error ("unable to get die scopes for '" + local + "' in an inlined subroutines", e->tok); diff --git a/dwflpp.h b/dwflpp.h index 74a3ae00..e047fcba 100644 --- a/dwflpp.h +++ b/dwflpp.h @@ -65,6 +65,12 @@ typedef unordered_map mod_cu_function_cache_t; // inline function die -> instance die[] typedef unordered_map*> cu_inl_function_cache_t; +// die -> parent die +typedef unordered_map cu_die_parent_cache_t; + +// cu die -> (die -> parent die) +typedef unordered_map mod_cu_die_parent_cache_t; + typedef std::vector func_info_map_t; typedef std::vector inline_instance_map_t; @@ -201,6 +207,8 @@ struct dwflpp void iterate_over_inline_instances (int (* callback)(Dwarf_Die * die, void * arg), void * data); + std::vector getscopes_die(Dwarf_Die* die); + Dwarf_Die *declaration_resolve(const char *name); mod_cu_function_cache_t cu_function_cache; @@ -292,6 +300,9 @@ private: cu_inl_function_cache_t cu_inl_function_cache; void cache_inline_instances (Dwarf_Die* die); + mod_cu_die_parent_cache_t cu_die_parent_cache; + void cache_die_parents(cu_die_parent_cache_t* parents, Dwarf_Die* die); + /* The global alias cache is used to resolve any DIE found in a * module that is stubbed out with DW_AT_declaration with a defining * DIE found in a different module. The current assumption is that diff --git a/tapsets.cxx b/tapsets.cxx index 7912ed99..346fa7f3 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -355,7 +355,7 @@ struct dwarf_derived_probe: public derived_probe void emit_probe_local_init(translator_output * o); string args; - void saveargs(Dwarf_Die* scope_die); + void saveargs(dwarf_query& q, Dwarf_Die* scope_die); void printargs(std::ostream &o) const; // Pattern registration helpers. @@ -401,7 +401,7 @@ struct uprobe_derived_probe: public derived_probe bool return_p); string args; - void saveargs(Dwarf_Die* scope_die); + void saveargs(dwarf_query& q, Dwarf_Die* scope_die); void printargs(std::ostream &o) const; void printsig (std::ostream &o) const; @@ -2110,10 +2110,8 @@ dwarf_var_expanding_visitor::visit_target_symbol_saved_return (target_symbol* e) void dwarf_var_expanding_visitor::visit_target_symbol_context (target_symbol* e) { - Dwarf_Die *scopes; - if (dwarf_getscopes_die (scope_die, &scopes) == 0) + if (null_die(scope_die)) return; - auto_free free_scopes(scopes); target_symbol *tsym = new target_symbol; print_format* pf = new print_format; @@ -2161,6 +2159,7 @@ dwarf_var_expanding_visitor::visit_target_symbol_context (target_symbol* e) // non-.return probe: support $$parms, $$vars, $$locals bool first = true; Dwarf_Die result; + vector scopes = q.dw.getscopes_die(scope_die); if (dwarf_child (&scopes[0], &result) == 0) do { @@ -2745,7 +2744,7 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, // Save the local variables for listing mode if (q.sess.listing_mode_vars) - saveargs(scope_die); + saveargs(q, scope_die); // Reset the sole element of the "locations" vector as a // "reverse-engineered" form of the incoming (q.base_loc) probe @@ -2812,12 +2811,10 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, void -dwarf_derived_probe::saveargs(Dwarf_Die* scope_die) +dwarf_derived_probe::saveargs(dwarf_query& q, Dwarf_Die* scope_die) { - Dwarf_Die *scopes; - if (!null_die(scope_die) && dwarf_getscopes_die (scope_die, &scopes) == 0) + if (null_die(scope_die)) return; - auto_free free_scopes(scopes); stringstream argstream; string type_name; @@ -2829,6 +2826,7 @@ dwarf_derived_probe::saveargs(Dwarf_Die* scope_die) argstream << " $return:" << type_name; Dwarf_Die arg; + vector scopes = q.dw.getscopes_die(scope_die); if (dwarf_child (&scopes[0], &arg) == 0) do { @@ -4232,7 +4230,7 @@ uprobe_derived_probe::uprobe_derived_probe (const string& function, // Save the local variables for listing mode if (q.sess.listing_mode_vars) - saveargs(scope_die); + saveargs(q, scope_die); // Reset the sole element of the "locations" vector as a // "reverse-engineered" form of the incoming (q.base_loc) probe @@ -4308,14 +4306,12 @@ uprobe_derived_probe::uprobe_derived_probe (probe *base, void -uprobe_derived_probe::saveargs(Dwarf_Die* scope_die) +uprobe_derived_probe::saveargs(dwarf_query& q, Dwarf_Die* scope_die) { // same as dwarf_derived_probe::saveargs - Dwarf_Die *scopes; - if (!null_die(scope_die) && dwarf_getscopes_die (scope_die, &scopes) == 0) + if (null_die(scope_die)) return; - auto_free free_scopes(scopes); stringstream argstream; string type_name; @@ -4327,6 +4323,7 @@ uprobe_derived_probe::saveargs(Dwarf_Die* scope_die) argstream << " $return:" << type_name; Dwarf_Die arg; + vector scopes = q.dw.getscopes_die(scope_die); if (dwarf_child (&scopes[0], &arg) == 0) do { -- cgit From c9efa5c99498ccb3d2f0f87bc373da7dfd1cc067 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 9 Sep 2009 16:13:16 -0700 Subject: Simplify deleting all map values * util.h (delete_map): New templated map deleter. * dwflpp.cxx (dwflpp::~dwflpp): Use it. * tapsets.cxx (symbol_table::~symbol_table): Use it. --- dwflpp.cxx | 24 +++++------------------- tapsets.cxx | 3 +-- util.h | 12 ++++++++++++ 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/dwflpp.cxx b/dwflpp.cxx index d96f3eda..36b016c7 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -98,25 +98,11 @@ dwflpp::~dwflpp() { free(cached_scopes); - for (module_cu_cache_t::iterator it = module_cu_cache.begin(); - it != module_cu_cache.end(); ++it) - delete it->second; - - for (mod_cu_function_cache_t::iterator it = cu_function_cache.begin(); - it != cu_function_cache.end(); ++it) - delete it->second; - - for (cu_inl_function_cache_t::iterator it = cu_inl_function_cache.begin(); - it != cu_inl_function_cache.end(); ++it) - delete it->second; - - for (mod_cu_type_cache_t::iterator it = global_alias_cache.begin(); - it != global_alias_cache.end(); ++it) - delete it->second; - - for (mod_cu_die_parent_cache_t::iterator it = cu_die_parent_cache.begin(); - it != cu_die_parent_cache.end(); ++it) - delete it->second; + delete_map(module_cu_cache); + delete_map(cu_function_cache); + delete_map(cu_inl_function_cache); + delete_map(global_alias_cache); + delete_map(cu_die_parent_cache); if (dwfl) dwfl_end(dwfl); diff --git a/tapsets.cxx b/tapsets.cxx index 346fa7f3..fc8cb88b 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -3820,8 +3820,7 @@ dwarf_builder::build(systemtap_session & sess, symbol_table::~symbol_table() { - for (iterator_t i = map_by_addr.begin(); i != map_by_addr.end(); ++i) - delete i->second; + delete_map(map_by_addr); } void diff --git a/util.h b/util.h index b38d01fd..24845545 100644 --- a/util.h +++ b/util.h @@ -97,4 +97,16 @@ lex_cast_qstring(std::string const & in) return out; } + +// Delete all values from a map-like container and clear it +// (The template is permissive -- be good!) +template +void delete_map(T& t) +{ + for (typename T::iterator i = t.begin(); i != t.end(); ++i) + delete i->second; + t.clear(); +} + + /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */ -- cgit From 729455a739d4755269f20b73d2db231db2a1fdd7 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 10 Sep 2009 17:06:11 -0700 Subject: PR10594 cont'd: Use parent die cache for variable lookup Variable lookup is usually done through the scopes from dwarf_getscopes at a particular pc. This requires an expensive traversal to find the inner-most die containing the pc. For cases where that containing die is known, e.g. at a particular function entry, we can do much better with our die_parent_cache. This may also help get more accurate variable scopes in cases where multiple dies contain a pc and the innermost isn't what we're trying to probe. For example, an inlined call chain of foo->bar->baz may all have the same entry pc, but if the probe was on function("bar"), we would want the variables in bar's scope, not baz's. * dwflpp.h (struct dwflpp): Remove pc_cached_scopes, num_cached_scopes, and cached_scopes, as they are now remembered by the caller. * dwflpp.cxx (dwflpp::getscopes): New - the DIE version uses the parent cache, and the pc version just defers to dwarf_getscopes. (dwflpp::print_locals, literal_stmt_for_local): Take a scopes vector. (dwflpp::find_variable_and_frame_base): Take a scopes vector from the caller instead of computing it every time. (dwflpp::dwarf_getscopes_cached): Removed. * tapsets.cxx (dwarf_var_expanding_visitor::getscopes): New cached lookup function which gets the scopes from the DIE if possible. (dwarf_var_expanding_visitor::visit_target_symbol): Call getscopes. --- dwflpp.cxx | 181 +++++++++++++++++++++++++++++++++++++++--------------------- dwflpp.h | 14 ++--- tapsets.cxx | 36 +++++++++++- 3 files changed, 158 insertions(+), 73 deletions(-) diff --git a/dwflpp.cxx b/dwflpp.cxx index 36b016c7..3e451916 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -70,8 +70,7 @@ static string TOK_KERNEL("kernel"); dwflpp::dwflpp(systemtap_session & session, const string& name, bool kernel_p): sess(session), module(NULL), module_bias(0), mod_info(NULL), module_start(0), module_end(0), cu(NULL), dwfl(NULL), - module_dwarf(NULL), function(NULL), blacklist_enabled(false), - pc_cached_scopes(0), num_cached_scopes(0), cached_scopes(NULL) + module_dwarf(NULL), function(NULL), blacklist_enabled(false) { if (kernel_p) setup_kernel(name); @@ -87,8 +86,7 @@ dwflpp::dwflpp(systemtap_session & session, const string& name, bool kernel_p): dwflpp::dwflpp(systemtap_session & session, const vector& names): sess(session), module(NULL), module_bias(0), mod_info(NULL), module_start(0), module_end(0), cu(NULL), dwfl(NULL), - module_dwarf(NULL), function(NULL), blacklist_enabled(false), - pc_cached_scopes(0), num_cached_scopes(0), cached_scopes(NULL) + module_dwarf(NULL), function(NULL), blacklist_enabled(false) { setup_user(names); } @@ -96,8 +94,6 @@ dwflpp::dwflpp(systemtap_session & session, const vector& names): dwflpp::~dwflpp() { - free(cached_scopes); - delete_map(module_cu_cache); delete_map(cu_function_cache); delete_map(cu_inl_function_cache); @@ -179,9 +175,6 @@ dwflpp::focus_on_cu(Dwarf_Die * c) // Reset existing pointers and names function_name.clear(); function = NULL; - - free(cached_scopes); - cached_scopes = NULL; } @@ -632,30 +625,42 @@ dwflpp::cache_die_parents(cu_die_parent_cache_t* parents, Dwarf_Die* die) } -vector -dwflpp::getscopes_die(Dwarf_Die* die) +cu_die_parent_cache_t* +dwflpp::get_die_parents() { assert (cu); - cu_die_parent_cache_t *parents = cu_die_parent_cache[cu->addr]; + cu_die_parent_cache_t *& parents = cu_die_parent_cache[cu->addr]; if (!parents) { parents = new cu_die_parent_cache_t; - cu_die_parent_cache[cu->addr] = parents; cache_die_parents(parents, cu); if (sess.verbose > 4) clog << "die parent cache " << module_name << ":" << cu_name() << " size " << parents->size() << endl; } + return parents; +} + + +vector +dwflpp::getscopes_die(Dwarf_Die* die) +{ + cu_die_parent_cache_t *parents = get_die_parents(); vector scopes; - scopes.push_back(*die); - for (cu_die_parent_cache_t::iterator it = parents->find(die->addr); - it != parents->end(); it = parents->find(it->second.addr)) - scopes.push_back(it->second); + Dwarf_Die *scope = die; + cu_die_parent_cache_t::iterator it; + do + { + scopes.push_back(*scope); + it = parents->find(scope->addr); + scope = &it->second; + } + while (it != parents->end()); #ifdef DEBUG_DWFLPP_GETSCOPES - Dwarf_Die *dscopes; + Dwarf_Die *dscopes = NULL; int nscopes = dwarf_getscopes_die(die, &dscopes); assert(nscopes == (int)scopes.size()); @@ -668,6 +673,83 @@ dwflpp::getscopes_die(Dwarf_Die* die) } +std::vector +dwflpp::getscopes(Dwarf_Die* die) +{ + cu_die_parent_cache_t *parents = get_die_parents(); + + vector scopes; + + Dwarf_Die origin; + Dwarf_Die *scope = die; + cu_die_parent_cache_t::iterator it; + do + { + scopes.push_back(*scope); + if (dwarf_tag(scope) == DW_TAG_inlined_subroutine && + dwarf_attr_die(scope, DW_AT_abstract_origin, &origin)) + scope = &origin; + + it = parents->find(scope->addr); + scope = &it->second; + } + while (it != parents->end()); + +#ifdef DEBUG_DWFLPP_GETSCOPES + // there isn't an exact libdw equivalent, but if dwarf_getscopes on the + // entrypc returns the same first die, then all the scopes should match + Dwarf_Addr pc; + if (die_entrypc(die, &pc)) + { + Dwarf_Die *dscopes = NULL; + int nscopes = dwarf_getscopes(cu, pc, &dscopes); + if (nscopes > 0 && dscopes[0].addr == die->addr) + { + assert(nscopes == (int)scopes.size()); + for (unsigned i = 0; i < scopes.size(); ++i) + assert(scopes[i].addr == dscopes[i].addr); + } + free(dscopes); + } +#endif + + return scopes; +} + + +std::vector +dwflpp::getscopes(Dwarf_Addr pc) +{ + // The die_parent_cache doesn't help us without knowing where the pc is + // contained, so we have to do this one the old fashioned way. + + assert (cu); + + vector scopes; + + Dwarf_Die* dwarf_scopes; + int nscopes = dwarf_getscopes(cu, pc, &dwarf_scopes); + if (nscopes > 0) + { + scopes.assign(dwarf_scopes, dwarf_scopes + nscopes); + free(dwarf_scopes); + } + +#ifdef DEBUG_DWFLPP_GETSCOPES + // check that getscopes on the starting die gets the same result + if (!scopes.empty()) + { + vector other = getscopes(&scopes[0]); + assert(scopes.size() == other.size()); + for (unsigned i = 0; i < scopes.size(); ++i) + assert(scopes[i].addr == other[i].addr); + } +#endif + + return scopes; +} + + int dwflpp::global_alias_caching_callback(Dwarf_Die *die, void *arg) { @@ -1488,11 +1570,13 @@ dwflpp::loc2c_emit_address (void *arg, struct obstack *pool, void -dwflpp::print_locals(Dwarf_Die *die, ostream &o) +dwflpp::print_locals(vector& scopes, ostream &o) { + // XXX Shouldn't this be walking up to outer scopes too? + // Try to get the first child of die. Dwarf_Die child; - if (dwarf_child (die, &child) == 0) + if (dwarf_child (&scopes[0], &child) == 0) { do { @@ -1517,34 +1601,19 @@ dwflpp::print_locals(Dwarf_Die *die, ostream &o) Dwarf_Attribute * -dwflpp::find_variable_and_frame_base (Dwarf_Die *scope_die, +dwflpp::find_variable_and_frame_base (vector& scopes, Dwarf_Addr pc, string const & local, const target_symbol *e, Dwarf_Die *vardie, Dwarf_Attribute *fb_attr_mem) { - Dwarf_Die *scopes; - int nscopes = 0; + Dwarf_Die *scope_die = &scopes[0]; Dwarf_Attribute *fb_attr = NULL; assert (cu); - nscopes = dwarf_getscopes_cached (pc, &scopes); - if (nscopes <= 0) - { - throw semantic_error ("unable to find any scopes containing " - + lex_cast_hex(pc) - + ((scope_die == NULL) ? "" - : (string (" in ") - + (dwarf_diename(scope_die) ?: "") - + "(" + (dwarf_diename(cu) ?: "") - + ")")) - + " while searching for local '" + local + "'", - e->tok); - } - - int declaring_scope = dwarf_getscopevar (scopes, nscopes, + int declaring_scope = dwarf_getscopevar (&scopes[0], scopes.size(), local.c_str(), 0, NULL, 0, 0, vardie); @@ -1567,18 +1636,19 @@ dwflpp::find_variable_and_frame_base (Dwarf_Die *scope_die, * as returned by dwarf_getscopes for the address, starting with the * declaring_scope that the variable was found in. */ - vector vscopes; - for (int inner = declaring_scope; - inner < nscopes && fb_attr == NULL; + vector physcopes, *fbscopes = &scopes; + for (size_t inner = declaring_scope; + inner < fbscopes->size() && fb_attr == NULL; ++inner) { - switch (dwarf_tag (&scopes[inner])) + Dwarf_Die& scope = (*fbscopes)[inner]; + switch (dwarf_tag (&scope)) { default: continue; case DW_TAG_subprogram: case DW_TAG_entry_point: - fb_attr = dwarf_attr_integrate (&scopes[inner], + fb_attr = dwarf_attr_integrate (&scope, DW_AT_frame_base, fb_attr_mem); break; @@ -1588,13 +1658,12 @@ dwflpp::find_variable_and_frame_base (Dwarf_Die *scope_die, * subroutine is inlined to find the appropriate frame base. */ if (declaring_scope != -1) { - vscopes = getscopes_die(&scopes[inner]); - scopes = &vscopes[0]; - nscopes = vscopes.size(); - if (!nscopes) + physcopes = getscopes_die(&scope); + if (physcopes.empty()) throw semantic_error ("unable to get die scopes for '" + local + "' in an inlined subroutines", e->tok); + fbscopes = &physcopes; inner = 0; // zero is current scope, for look will increase. declaring_scope = -1; } @@ -2172,7 +2241,7 @@ dwflpp::express_as_string (string prelude, string -dwflpp::literal_stmt_for_local (Dwarf_Die *scope_die, +dwflpp::literal_stmt_for_local (vector& scopes, Dwarf_Addr pc, string const & local, const target_symbol *e, @@ -2182,7 +2251,7 @@ dwflpp::literal_stmt_for_local (Dwarf_Die *scope_die, Dwarf_Die vardie; Dwarf_Attribute fb_attr_mem, *fb_attr = NULL; - fb_attr = find_variable_and_frame_base (scope_die, pc, local, e, + fb_attr = find_variable_and_frame_base (scopes, pc, local, e, &vardie, &fb_attr_mem); if (sess.verbose>2) @@ -2685,20 +2754,6 @@ dwflpp::literal_addr_to_sym_addr(Dwarf_Addr lit_addr) return lit_addr; } -int -dwflpp::dwarf_getscopes_cached (Dwarf_Addr pc, Dwarf_Die **scopes) -{ - if (!cached_scopes || pc != pc_cached_scopes) - { - free(cached_scopes); - cached_scopes = NULL; - pc_cached_scopes = pc; - num_cached_scopes = dwarf_getscopes(cu, pc, &cached_scopes); - } - *scopes = cached_scopes; - return num_cached_scopes; -} - /* Returns the call frame address operations for the given program counter * in the libdw address space. */ diff --git a/dwflpp.h b/dwflpp.h index e047fcba..d379b265 100644 --- a/dwflpp.h +++ b/dwflpp.h @@ -208,6 +208,8 @@ struct dwflpp void * data); std::vector getscopes_die(Dwarf_Die* die); + std::vector getscopes(Dwarf_Die* die); + std::vector getscopes(Dwarf_Addr pc); Dwarf_Die *declaration_resolve(const char *name); @@ -253,7 +255,7 @@ struct dwflpp bool die_has_pc (Dwarf_Die & die, Dwarf_Addr pc); - std::string literal_stmt_for_local (Dwarf_Die *scope_die, + std::string literal_stmt_for_local (std::vector& scopes, Dwarf_Addr pc, std::string const & local, const target_symbol *e, @@ -302,6 +304,7 @@ private: mod_cu_die_parent_cache_t cu_die_parent_cache; void cache_die_parents(cu_die_parent_cache_t* parents, Dwarf_Die* die); + cu_die_parent_cache_t *get_die_parents(); /* The global alias cache is used to resolve any DIE found in a * module that is stubbed out with DW_AT_declaration with a defining @@ -328,10 +331,10 @@ private: static void loc2c_emit_address (void *arg, struct obstack *pool, Dwarf_Addr address); - void print_locals(Dwarf_Die *die, std::ostream &o); + void print_locals(std::vector& scopes, std::ostream &o); void print_members(Dwarf_Die *vardie, std::ostream &o); - Dwarf_Attribute *find_variable_and_frame_base (Dwarf_Die *scope_die, + Dwarf_Attribute *find_variable_and_frame_base (std::vector& scopes, Dwarf_Addr pc, std::string const & local, const target_symbol *e, @@ -385,11 +388,6 @@ private: void build_blacklist(); std::string get_blacklist_section(Dwarf_Addr addr); - Dwarf_Addr pc_cached_scopes; - int num_cached_scopes; - Dwarf_Die *cached_scopes; - int dwarf_getscopes_cached (Dwarf_Addr pc, Dwarf_Die **scopes); - // Returns the call frame address operations for the given program counter. Dwarf_Op *get_cfa_ops (Dwarf_Addr pc); diff --git a/tapsets.cxx b/tapsets.cxx index fc8cb88b..deb1e795 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -1761,7 +1761,8 @@ struct dwarf_var_expanding_visitor: public var_expanding_visitor Dwarf_Addr addr; block *add_block; probe *add_probe; - std::map return_ts_map; + map return_ts_map; + vector scopes; bool visited; dwarf_var_expanding_visitor(dwarf_query & q, Dwarf_Die *sd, Dwarf_Addr a): @@ -1770,6 +1771,8 @@ struct dwarf_var_expanding_visitor: public var_expanding_visitor void visit_target_symbol_context (target_symbol* e); void visit_target_symbol (target_symbol* e); void visit_cast_op (cast_op* e); +private: + vector& getscopes(target_symbol *e); }; @@ -2281,7 +2284,7 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e) } else { - ec->code = q.dw.literal_stmt_for_local (scope_die, + ec->code = q.dw.literal_stmt_for_local (getscopes(e), addr, e->base_name.substr(1), e, @@ -2391,6 +2394,35 @@ dwarf_var_expanding_visitor::visit_cast_op (cast_op *e) } +vector& +dwarf_var_expanding_visitor::getscopes(target_symbol *e) +{ + if (scopes.empty()) + { + // If the address is at the beginning of the scope_die, we can do a fast + // getscopes from there. Otherwise we need to look it up by address. + Dwarf_Addr entrypc; + if (q.dw.die_entrypc(scope_die, &entrypc) && entrypc == addr) + scopes = q.dw.getscopes(scope_die); + else + scopes = q.dw.getscopes(addr); + + if (scopes.empty()) + throw semantic_error ("unable to find any scopes containing " + + lex_cast_hex(addr) + + ((scope_die == NULL) ? "" + : (string (" in ") + + (dwarf_diename(scope_die) ?: "") + + "(" + (dwarf_diename(q.dw.cu) ?: "") + + ")")) + + " while searching for local '" + + e->base_name.substr(1) + "'", + e->tok); + } + return scopes; +} + + struct dwarf_cast_query : public base_query { cast_op& e; -- cgit