Imported Upstream version 0.160
[platform/upstream/elfutils.git] / libdw / libdw_visit_scopes.c
index ea0c6b4..487375d 100644 (file)
 #include "libdwP.h"
 #include <dwarf.h>
 
-enum die_class { ignore, match, match_inline, walk, imported };
 
-static enum die_class
-classify_die (Dwarf_Die *die)
+static bool
+may_have_scopes (Dwarf_Die *die)
 {
   switch (INTUSE(dwarf_tag) (die))
     {
@@ -48,31 +47,21 @@ classify_die (Dwarf_Die *die)
     case DW_TAG_catch_block:
     case DW_TAG_try_block:
     case DW_TAG_entry_point:
-      return match;
     case DW_TAG_inlined_subroutine:
-      return match_inline;
     case DW_TAG_subprogram:
-      /* This might be a concrete out-of-line instance of an inline, in
-        which case it is not guaranteed to be owned by the right scope and
-        we will search for its origin as for DW_TAG_inlined_subroutine.  */
-      return (INTUSE(dwarf_hasattr) (die, DW_AT_abstract_origin)
-             ? match_inline : match);
+      return true;
 
       /* DIEs without addresses that can own DIEs with addresses.  */
     case DW_TAG_namespace:
     case DW_TAG_class_type:
     case DW_TAG_structure_type:
-      return walk;
-
-      /* Special indirection required.  */
-    case DW_TAG_imported_unit:
-      return imported;
+      return true;
 
       /* Other DIEs we have no reason to descend.  */
     default:
       break;
     }
-  return ignore;
+  return false;
 }
 
 int
@@ -84,10 +73,11 @@ __libdw_visit_scopes (depth, root, previsit, postvisit, arg)
      void *arg;
 {
   struct Dwarf_Die_Chain child;
+  int ret;
 
   child.parent = root;
-  if (INTUSE(dwarf_child) (&root->die, &child.die) != 0)
-    return -1;
+  if ((ret = INTUSE(dwarf_child) (&root->die, &child.die)) != 0)
+    return ret < 0 ? -1 : 0; // Having zero children is legal.
 
   inline int recurse (void)
     {
@@ -95,63 +85,63 @@ __libdw_visit_scopes (depth, root, previsit, postvisit, arg)
                                   previsit, postvisit, arg);
     }
 
-  do
-    {
-      child.prune = false;
-
-      if (previsit != NULL)
-       {
-         int result = (*previsit) (depth + 1, &child, arg);
-         if (result != DWARF_CB_OK)
-           return result;
-       }
-
-      if (!child.prune)
-       switch (classify_die (&child.die))
+  inline int walk_children ()
+  {
+    do
+      {
+       /* For an imported unit, it is logically as if the children of
+          that unit are siblings of the other children.  So don't do
+          a full recursion into the imported unit, but just walk the
+          children in place before moving to the next real child.  */
+       while (INTUSE(dwarf_tag) (&child.die) == DW_TAG_imported_unit)
          {
-         case match:
-         case match_inline:
-         case walk:
-           if (INTUSE(dwarf_haschildren) (&child.die))
+           Dwarf_Die orig_child_die = child.die;
+           Dwarf_Attribute attr_mem;
+           Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child.die,
+                                                       DW_AT_import,
+                                                       &attr_mem);
+           if (INTUSE(dwarf_formref_die) (attr, &child.die) != NULL
+                && INTUSE(dwarf_child) (&child.die, &child.die) == 0)
              {
-               int result = recurse ();
+               int result = walk_children ();
                if (result != DWARF_CB_OK)
                  return result;
              }
-           break;
-
-         case imported:
-           {
-             /* This imports another compilation unit to appear
-                as part of this one, inside the current scope.
-                Recurse to search the referenced unit, but without
-                recording it as an inner scoping level.  */
-
-             Dwarf_Attribute attr_mem;
-             Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child.die,
-                                                         DW_AT_import,
-                                                         &attr_mem);
-             if (INTUSE(dwarf_formref_die) (attr, &child.die) != NULL)
-               {
-                 int result = recurse ();
-                 if (result != DWARF_CB_OK)
-                   return result;
-               }
-           }
-           break;
-
-         default:
-           break;
+
+           /* Any "real" children left?  */
+           if ((ret = INTUSE(dwarf_siblingof) (&orig_child_die,
+                                               &child.die)) != 0)
+             return ret < 0 ? -1 : 0;
+         };
+
+       child.prune = false;
+
+       if (previsit != NULL)
+         {
+           int result = (*previsit) (depth + 1, &child, arg);
+           if (result != DWARF_CB_OK)
+             return result;
          }
 
-      if (postvisit != NULL)
-       {
-         int result = (*postvisit) (depth + 1, &child, arg);
-         if (result != DWARF_CB_OK)
-           return result;
-       }
-    }
-  while (INTUSE(dwarf_siblingof) (&child.die, &child.die) == 0);
+       if (!child.prune && may_have_scopes (&child.die)
+           && INTUSE(dwarf_haschildren) (&child.die))
+         {
+           int result = recurse ();
+           if (result != DWARF_CB_OK)
+             return result;
+         }
+
+       if (postvisit != NULL)
+         {
+           int result = (*postvisit) (depth + 1, &child, arg);
+           if (result != DWARF_CB_OK)
+             return result;
+         }
+      }
+    while ((ret = INTUSE(dwarf_siblingof) (&child.die, &child.die)) == 0);
+
+    return ret < 0 ? -1 : 0;
+  }
 
-  return 0;
+  return walk_children ();
 }