diff --git a/dwflpp.cxx b/dwflpp.cxx
index 176b602..ccb6f2f 100644
--- a/dwflpp.cxx
+++ b/dwflpp.cxx
@@ -510,55 +510,6 @@ dwflpp::func_is_exported()
 }
 
 void
-dwflpp::cache_inline_instances (Dwarf_Die* die)
-{
-  // 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);
-}
-
-
-void
 dwflpp::iterate_over_inline_instances (int (* callback)(Dwarf_Die * die, void * arg),
                                        void * data)
 {
@@ -566,7 +517,7 @@ dwflpp::iterate_over_inline_instances (int (* callback)(Dwarf_Die * die, void *
   assert (func_is_inline ());
 
   if (cu_inl_function_cache_done.insert(cu->addr).second)
-    cache_inline_instances(cu);
+    build_cu_caches(cu);
 
   vector<Dwarf_Die>* v = cu_inl_function_cache[function->addr];
   if (!v)
@@ -583,16 +534,39 @@ 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)
+dwflpp::cache_dies(cu_die_parent_cache_t* parents,
+                   cu_function_cache_t* functions,
+                   Dwarf_Die* die)
 {
   // Record and recurse through DIEs we care about
-  Dwarf_Die child, import;
+  const char* name;
+  Dwarf_Die child, import, origin;
   if (dwarf_child(die, &child) == 0)
     do
       {
+        bool record_child = false, recurse = false;
+
         switch (dwarf_tag (&child))
           {
-          // normal tags to recurse
+          case DW_TAG_subprogram:
+            record_child = recurse = true;
+            if (!dwarf_hasattr(&child, DW_AT_declaration)
+                && (name = dwarf_diename(&child)))
+              functions->insert(make_pair(string(name), child));
+            break;
+
+          case DW_TAG_inlined_subroutine:
+            record_child = recurse = true;
+            if (dwarf_attr_die(&child, 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(child);
+              }
+            break;
+
+          // normal tags to record and recurse
           case DW_TAG_compile_unit:
           case DW_TAG_module:
           case DW_TAG_lexical_block:
@@ -600,18 +574,15 @@ dwflpp::cache_die_parents(cu_die_parent_cache_t* parents, Dwarf_Die* die)
           case DW_TAG_catch_block:
           case DW_TAG_try_block:
           case DW_TAG_entry_point:
-          case DW_TAG_inlined_subroutine:
-          case DW_TAG_subprogram:
           case DW_TAG_namespace:
           case DW_TAG_class_type:
           case DW_TAG_structure_type:
-            parents->insert(make_pair(child.addr, *die));
-            cache_die_parents(parents, &child);
+            record_child = recurse = true;
             break;
 
           // record only, nothing to recurse
           case DW_TAG_label:
-            parents->insert(make_pair(child.addr, *die));
+            record_child = true;
             break;
 
           // imported dies should be followed
@@ -619,7 +590,7 @@ dwflpp::cache_die_parents(cu_die_parent_cache_t* parents, Dwarf_Die* die)
             if (dwarf_attr_die(&child, DW_AT_import, &import))
               {
                 parents->insert(make_pair(import.addr, *die));
-                cache_die_parents(parents, &import);
+                cache_dies(parents, functions, &import);
               }
             break;
 
@@ -627,25 +598,50 @@ dwflpp::cache_die_parents(cu_die_parent_cache_t* parents, Dwarf_Die* die)
           default:
             break;
           }
+
+        if (record_child)
+          parents->insert(make_pair(child.addr, *die));
+        if (recurse)
+          cache_dies(parents, functions, &child);
       }
     while (dwarf_siblingof(&child, &child) == 0);
 }
 
 
-cu_die_parent_cache_t*
-dwflpp::get_die_parents()
+void
+dwflpp::build_cu_caches(Dwarf_Die* cu)
 {
-  assert (cu);
-
   cu_die_parent_cache_t *& parents = cu_die_parent_cache[cu->addr];
   if (!parents)
     {
+      // [invariant] functions and parents are always built together for a CU
+      cu_function_cache_t *& functions = cu_function_cache[cu->addr];
+      assert(!functions);
+
       parents = new cu_die_parent_cache_t;
-      cache_die_parents(parents, cu);
+      functions = new cu_function_cache_t;
+      cache_dies(parents, functions, cu);
       if (sess.verbose > 4)
-        clog << _F("die parent cache %s:%s size %zu", module_name.c_str(),
-                   cu_name().c_str(), parents->size()) << endl;
+        {
+          const char* cu_name = dwarf_diename(cu);
+          clog << _F("die parent cache %s:%s size %zu", module_name.c_str(),
+                     cu_name, parents->size()) << endl;
+          clog << _F("function cache %s:%s size %zu", module_name.c_str(),
+                     cu_name, functions->size()) << endl;
+        }
+      mod_info->update_symtab(functions);
     }
+}
+
+
+cu_die_parent_cache_t*
+dwflpp::get_die_parents()
+{
+  assert (cu);
+
+  cu_die_parent_cache_t *& parents = cu_die_parent_cache[cu->addr];
+  if (!parents)
+    build_cu_caches(cu);
   return parents;
 }
 
@@ -931,24 +927,13 @@ dwflpp::declaration_resolve(Dwarf_Die *type)
 }
 
 
-int
-dwflpp::cu_function_caching_callback (Dwarf_Die* func, void *arg)
+cu_function_cache_t*
+dwflpp::get_cu_functions(Dwarf_Die* cu)
 {
-  cu_function_cache_t* v = static_cast<cu_function_cache_t*>(arg);
-  const char *name = dwarf_diename(func);
-  if (!name)
-    return DWARF_CB_OK;
-
-  v->insert(make_pair(string(name), *func));
-  return DWARF_CB_OK;
-}
-
-
-int
-dwflpp::mod_function_caching_callback (Dwarf_Die* cu, void *arg)
-{
-  dwarf_getfuncs (cu, cu_function_caching_callback, arg, 0);
-  return DWARF_CB_OK;
+  cu_function_cache_t *& functions = cu_function_cache[cu->addr];
+  if (!functions)
+    build_cu_caches(cu);
+  return functions;
 }
 
 
@@ -960,17 +945,7 @@ dwflpp::iterate_over_functions (int (* callback)(Dwarf_Die * func, base_query *
   assert (module);
   assert (cu);
 
-  cu_function_cache_t *v = cu_function_cache[cu->addr];
-  if (v == 0)
-    {
-      v = new cu_function_cache_t;
-      cu_function_cache[cu->addr] = v;
-      dwarf_getfuncs (cu, cu_function_caching_callback, v, 0);
-      if (sess.verbose > 4)
-        clog << _F("function cache %s:%s size %zu", module_name.c_str(),
-                   cu_name().c_str(), v->size()) << endl;
-      mod_info->update_symtab(v);
-    }
+  cu_function_cache_t *v = get_cu_functions(cu);
 
   cu_function_cache_t::iterator it;
   cu_function_cache_range_t range = v->equal_range(function);
@@ -1037,6 +1012,17 @@ dwflpp::iterate_over_functions (int (* callback)(Dwarf_Die * func, base_query *
 
 
 int
+dwflpp::mod_function_caching_callback (Dwarf_Die* cu, void *arg)
+{
+  dwflpp* o = static_cast<dwflpp*>(arg);
+  cu_function_cache_t * functions = o->get_cu_functions(cu);
+  cu_function_cache_t * mod_functions = o->mod_function_cache[o->module_dwarf];
+  mod_functions->insert(functions->begin(), functions->end());
+  return DWARF_CB_OK;
+}
+
+
+int
 dwflpp::iterate_single_function (int (* callback)(Dwarf_Die * func, base_query * q),
                                  base_query * q, const string& function)
 {
@@ -1047,12 +1033,11 @@ dwflpp::iterate_single_function (int (* callback)(Dwarf_Die * func, base_query *
   if (!module_dwarf)
     return rc;
 
-  cu_function_cache_t *v = mod_function_cache[module_dwarf];
+  cu_function_cache_t *& v = mod_function_cache[module_dwarf];
   if (v == 0)
     {
       v = new cu_function_cache_t;
-      mod_function_cache[module_dwarf] = v;
-      iterate_over_cus (mod_function_caching_callback, v, false);
+      iterate_over_cus (mod_function_caching_callback, this, false);
       if (sess.verbose > 4)
         clog << _F("module function cache %s size %zu", module_name.c_str(),
                    v->size()) << endl;
diff --git a/dwflpp.h b/dwflpp.h
index ba5e9bd..908286b 100644
--- a/dwflpp.h
+++ b/dwflpp.h
@@ -345,12 +345,15 @@ private:
 
   std::set<void*> cu_inl_function_cache_done; // CUs that are already cached
   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);
   cu_die_parent_cache_t *get_die_parents();
 
+  void cache_dies(cu_die_parent_cache_t* parents,
+                  cu_function_cache_t* functions,
+                  Dwarf_Die* die);
+  void build_cu_caches(Dwarf_Die* cu);
+
   Dwarf_Die* get_parent_scope(Dwarf_Die* die);
 
   /* The global alias cache is used to resolve any DIE found in a
@@ -374,8 +377,8 @@ private:
                                                   const std::string&, void *),
                                  void * data);
 
+  cu_function_cache_t* get_cu_functions(Dwarf_Die* cu);
   static int mod_function_caching_callback (Dwarf_Die* func, void *arg);
-  static int cu_function_caching_callback (Dwarf_Die* func, void *arg);
 
   bool has_single_line_record (dwarf_query * q, char const * srcfile, int lineno);
 
