summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dwflpp.cxx61
-rw-r--r--dwflpp.h3
2 files changed, 52 insertions, 12 deletions
diff --git a/dwflpp.cxx b/dwflpp.cxx
index 7e9894e1..ba8dcec7 100644
--- a/dwflpp.cxx
+++ b/dwflpp.cxx
@@ -502,12 +502,52 @@ dwflpp::func_is_inline()
}
-int
-dwflpp::cu_inl_function_caching_callback (Dwarf_Die* func, void *arg)
+void
+dwflpp::cache_inline_instances (Dwarf_Die* die)
{
- vector<Dwarf_Die>* v = static_cast<vector<Dwarf_Die>*>(arg);
- v->push_back (* func);
- return DWARF_CB_OK;
+ // If this is an inline instance, link it back to its origin
+ Dwarf_Die origin;
+ if (dwarf_tag(die) == DW_TAG_inlined_subroutine &&
+ dwarf_attr_die(die, DW_AT_abstract_origin, &origin))
+ {
+ vector<Dwarf_Die>*& v = cu_inl_function_cache[origin.addr];
+ if (!v)
+ v = new vector<Dwarf_Die>;
+ v->push_back(*die);
+ }
+
+ // Recurse through other scopes that may contain inlines
+ Dwarf_Die child, import;
+ if (dwarf_child(die, &child) == 0)
+ do
+ {
+ switch (dwarf_tag (&child))
+ {
+ // tags that could contain inlines
+ 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:
+ cache_inline_instances(&child);
+ break;
+
+ // imported dies should be followed
+ case DW_TAG_imported_unit:
+ if (dwarf_attr_die(&child, DW_AT_import, &import))
+ cache_inline_instances(&import);
+ break;
+
+ // nothing to do for other tags
+ default:
+ break;
+ }
+ }
+ while (dwarf_siblingof(&child, &child) == 0);
}
@@ -518,13 +558,12 @@ dwflpp::iterate_over_inline_instances (int (* callback)(Dwarf_Die * die, void *
assert (function);
assert (func_is_inline ());
+ if (cu_inl_function_cache_done.insert(cu->addr).second)
+ cache_inline_instances(cu);
+
vector<Dwarf_Die>* v = cu_inl_function_cache[function->addr];
- if (v == 0)
- {
- v = new vector<Dwarf_Die>;
- cu_inl_function_cache[function->addr] = v;
- dwarf_func_inline_instances (function, cu_inl_function_caching_callback, v);
- }
+ if (!v)
+ return;
for (vector<Dwarf_Die>::iterator i = v->begin(); i != v->end(); ++i)
{
diff --git a/dwflpp.h b/dwflpp.h
index 073b9bfc..047ad602 100644
--- a/dwflpp.h
+++ b/dwflpp.h
@@ -296,8 +296,9 @@ private:
module_cu_cache_t module_cu_cache;
+ std::set<void*> cu_inl_function_cache_done; // CUs that are already cached
cu_inl_function_cache_t cu_inl_function_cache;
- static int cu_inl_function_caching_callback (Dwarf_Die* func, void *arg);
+ void cache_inline_instances (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