]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
readdwarf3: Skip units without addresses when looking for inlined functions
authorMark Wielaard <mark@klomp.org>
Thu, 16 Sep 2021 20:01:47 +0000 (22:01 +0200)
committerMark Wielaard <mark@klomp.org>
Fri, 24 Sep 2021 20:28:12 +0000 (22:28 +0200)
When a unit doesn't cover any addresses skip it because no actual code
will be inside. Also use skip_DIE instead of read_DIE when not parsing
(skipping) children.

coregrind/m_debuginfo/readdwarf3.c

index 968c37bd637fa2005e70b84c0be8eb72e4a0a7c3..cf8270c8cf537991b7710cbe4a696371f96d013c 100644 (file)
@@ -3127,8 +3127,9 @@ static Bool parse_inl_DIE (
 
    UWord saved_die_c_offset  = get_position_of_Cursor( c_die );
 
-   /* Get info about DW_TAG_compile_unit and DW_TAG_partial_unit 'which
-      in theory could also contain inlined fn calls).  */
+   /* Get info about DW_TAG_compile_unit and DW_TAG_partial_unit which in theory
+      could also contain inlined fn calls, if they cover an address range.  */
+   Bool unit_has_addrs = False;
    if (dtag == DW_TAG_compile_unit || dtag == DW_TAG_partial_unit) {
       Bool have_lo    = False;
       Addr ip_lo    = 0;
@@ -3145,7 +3146,10 @@ static Bool parse_inl_DIE (
          if (attr == DW_AT_low_pc && cts.szB > 0) {
             ip_lo   = cts.u.val;
             have_lo = True;
+            unit_has_addrs = True;
          }
+         if (attr == DW_AT_ranges && cts.szB > 0)
+            unit_has_addrs = True;
          if (attr == DW_AT_comp_dir) {
             if (cts.szB >= 0)
                cc->barf("parse_inl_DIE compdir: expecting indirect string");
@@ -3278,9 +3282,10 @@ static Bool parse_inl_DIE (
 
    // Only recursively parse the (possible) children for the DIE which
    // might maybe contain a DW_TAG_inlined_subroutine:
-   return dtag == DW_TAG_lexical_block || dtag == DW_TAG_subprogram
-      || dtag == DW_TAG_inlined_subroutine
-      || dtag == DW_TAG_compile_unit || dtag == DW_TAG_partial_unit;
+   Bool ret = (unit_has_addrs
+               || dtag == DW_TAG_lexical_block || dtag == DW_TAG_subprogram
+               || dtag == DW_TAG_inlined_subroutine);
+   return ret;
 
   bad_DIE:
    dump_bad_die_and_barf("parse_inl_DIE", dtag, posn, level,
@@ -4759,9 +4764,36 @@ static void read_DIE (
          while (True) {
             atag = peek_ULEB128( c );
             if (atag == 0) break;
-            read_DIE( rangestree, tyents, tempvars, gexprs,
-                      typarser, varparser, inlparser,
-                      c, td3, cc, level+1 );
+            if (parse_children) {
+               read_DIE( rangestree, tyents, tempvars, gexprs,
+                         typarser, varparser, inlparser,
+                         c, td3, cc, level+1 );
+            } else {
+               Int skip_level = level + 1;
+               while (True) {
+                  atag = peek_ULEB128( c );
+                  if (atag == 0) {
+                     skip_level--;
+                     if (skip_level == level) break;
+                     /* Eat the terminating zero and continue skipping the
+                        children one level up.  */
+                     atag = get_ULEB128( c );
+                     vg_assert(atag == 0);
+                     continue;
+                  }
+
+                  abbv_code = get_ULEB128( c );
+                  abbv = get_abbv(cc, abbv_code);
+                  sibling = 0;
+                  skip_DIE (&sibling, c, abbv, cc);
+                  if (abbv->has_children) {
+                     if (sibling == 0)
+                        skip_level++;
+                     else
+                        set_position_of_Cursor( c, sibling );
+                  }
+               }
+            }
          }
          /* Now we need to eat the terminating zero */
          atag = get_ULEB128( c );