[llvm] ccf5a44 - Fix the verification of DIEs with DW_AT_ranges.

Greg Clayton via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 22 13:14:13 PDT 2020


Author: Greg Clayton
Date: 2020-06-22T13:13:48-07:00
New Revision: ccf5a44917fcb3e57d18d7f73bef06607ec7a20d

URL: https://github.com/llvm/llvm-project/commit/ccf5a44917fcb3e57d18d7f73bef06607ec7a20d
DIFF: https://github.com/llvm/llvm-project/commit/ccf5a44917fcb3e57d18d7f73bef06607ec7a20d.diff

LOG: Fix the verification of DIEs with DW_AT_ranges.

Summary: Previous code would try to verify DW_AT_ranges and if any ranges would overlap, it would stop attributing any ranges after this to the DIE which caused incorrect errors to be reported that a DIE's address ranges were not contained in the parent DIE's ranges. Added a fix and a test.

Reviewers: aprantl, labath, probinson, JDevlieghere, jhenderson

Subscribers: hiraditya, MaskRay, cmtice, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D79962

Added: 
    llvm/test/tools/llvm-dwarfdump/X86/verify_overlapping_cu_ranges.yaml

Modified: 
    llvm/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h
    llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
    llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h
index 7a728c2508cc..154f7893aa17 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFAddressRange.h
@@ -45,6 +45,24 @@ struct DWARFAddressRange {
     return LowPC < RHS.HighPC && RHS.LowPC < HighPC;
   }
 
+  /// Union two address ranges if they intersect.
+  ///
+  /// This function will union two address ranges if they intersect by
+  /// modifying this range to be the union of both ranges. If the two ranges
+  /// don't intersect this range will be left alone.
+  ///
+  /// \param RHS Another address range to combine with.
+  ///
+  /// \returns false if the ranges don't intersect, true if they do and the
+  /// ranges were combined.
+  bool merge(const DWARFAddressRange &RHS) {
+    if (!intersects(RHS))
+      return false;
+    LowPC = std::min<uint64_t>(LowPC, RHS.LowPC);
+    HighPC = std::max<uint64_t>(HighPC, RHS.HighPC);
+    return true;
+  }
+
   void dump(raw_ostream &OS, uint32_t AddressSize, DIDumpOptions DumpOpts = {},
             const DWARFObject *Obj = nullptr) const;
 };

diff  --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
index a4a3a11d441b..22b1d722fc89 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFVerifier.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H
 #define LLVM_DEBUGINFO_DWARF_DWARFVERIFIER_H
 
+#include "llvm/ADT/Optional.h"
 #include "llvm/DebugInfo/DIContext.h"
 #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
 #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
@@ -56,11 +57,13 @@ class DWARFVerifier {
     typedef std::set<DieRangeInfo>::const_iterator die_range_info_iterator;
 
     /// Inserts the address range. If the range overlaps with an existing
-    /// range, the range is *not* added and an iterator to the overlapping
-    /// range is returned.
+    /// range, the range that it overlaps with will be returned and the two
+    /// address ranges will be unioned together in "Ranges".
     ///
-    /// This is used for finding overlapping ranges within the same DIE.
-    address_range_iterator insert(const DWARFAddressRange &R);
+    /// This is used for finding overlapping ranges in the DW_AT_ranges
+    /// attribute of a DIE. It is also used as a set of address ranges that
+    /// children address ranges must all be contained in.
+    Optional<DWARFAddressRange> insert(const DWARFAddressRange &R);
 
     /// Finds an address range in the sorted vector of ranges.
     address_range_iterator findRange(const DWARFAddressRange &R) const {

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
index a6dadd7f8021..3a83317a73a3 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFVerifier.cpp
@@ -26,24 +26,26 @@ using namespace llvm;
 using namespace dwarf;
 using namespace object;
 
-DWARFVerifier::DieRangeInfo::address_range_iterator
+Optional<DWARFAddressRange>
 DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) {
   auto Begin = Ranges.begin();
   auto End = Ranges.end();
   auto Pos = std::lower_bound(Begin, End, R);
 
   if (Pos != End) {
-    if (Pos->intersects(R))
-      return std::move(Pos);
-    if (Pos != Begin) {
-      auto Iter = Pos - 1;
-      if (Iter->intersects(R))
-        return std::move(Iter);
-    }
+    DWARFAddressRange Range(*Pos);
+    if (Pos->merge(R))
+      return Range;
+  }
+  if (Pos != Begin) {
+    auto Iter = Pos - 1;
+    DWARFAddressRange Range(*Iter);
+    if (Iter->merge(R))
+      return Range;
   }
 
   Ranges.insert(Pos, R);
-  return Ranges.end();
+  return None;
 }
 
 DWARFVerifier::DieRangeInfo::die_range_info_iterator
@@ -397,22 +399,30 @@ unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,
   // processing an object file.
 
   if (!IsObjectFile || IsMachOObject || Die.getTag() != DW_TAG_compile_unit) {
+    bool DumpDieAfterError = false;
     for (auto Range : Ranges) {
       if (!Range.valid()) {
         ++NumErrors;
         error() << "Invalid address range " << Range << "\n";
+        DumpDieAfterError = true;
         continue;
       }
 
-      // Verify that ranges don't intersect.
-      const auto IntersectingRange = RI.insert(Range);
-      if (IntersectingRange != RI.Ranges.end()) {
+      // Verify that ranges don't intersect and also build up the DieRangeInfo
+      // address ranges. Don't break out of the loop below early, or we will
+      // think this DIE doesn't have all of the address ranges it is supposed
+      // to have. Compile units often have DW_AT_ranges that can contain one or
+      // more dead stripped address ranges which tend to all be at the same
+      // address: 0 or -1.
+      if (auto PrevRange = RI.insert(Range)) {
         ++NumErrors;
-        error() << "DIE has overlapping address ranges: " << Range << " and "
-                << *IntersectingRange << "\n";
-        break;
+        error() << "DIE has overlapping ranges in DW_AT_ranges attribute: "
+                << *PrevRange << " and " << Range << '\n';
+        DumpDieAfterError = true;
       }
     }
+    if (DumpDieAfterError)
+      dump(Die, 2) << '\n';
   }
 
   // Verify that children don't intersect.

diff  --git a/llvm/test/tools/llvm-dwarfdump/X86/verify_overlapping_cu_ranges.yaml b/llvm/test/tools/llvm-dwarfdump/X86/verify_overlapping_cu_ranges.yaml
new file mode 100644
index 000000000000..37cc139115a4
--- /dev/null
+++ b/llvm/test/tools/llvm-dwarfdump/X86/verify_overlapping_cu_ranges.yaml
@@ -0,0 +1,260 @@
+# This test verifies that if a DW_TAG_compile_unit has DW_AT_ranges that
+# overlap, that it doesn't end up producing invalid errors claiming a child
+# DW_TAG_subprogram DIE is not in the parant (CU) ranges. Prior to the commit
+# that fixed this, a loop was iterating over all DW_AT_ranges for a DIE and
+# stopping the loop if any intersecting ranges were found. This would cause
+# the DW_TAG_subprogram DIEs, like "stripped2" and "main", to improperly report
+# that they were not contained in the parent's address ranges
+#
+# The DWARF looks like:
+# 0x0000000b: DW_TAG_compile_unit
+#               DW_AT_name	("/tmp/main.c")
+#               DW_AT_language	(DW_LANG_C)
+#               DW_AT_low_pc	(0x0000000000000000)
+#               DW_AT_ranges	(0x00000000
+#                  [0x0000000000002000, 0x0000000000003000)
+#                  [0x0000000000000000, 0x0000000000000020)
+#                  [0x0000000000000000, 0x0000000000000030)
+#                  [0x0000000000001000, 0x0000000000002000))
+#
+# 0x0000001e:   DW_TAG_subprogram
+#                 DW_AT_name	("stripped1")
+#                 DW_AT_low_pc	(0x0000000000000000)
+#                 DW_AT_high_pc	(0x0000000000000020)
+#
+# 0x0000002f:   DW_TAG_subprogram
+#                 DW_AT_name	("stripped2")
+#                 DW_AT_low_pc	(0x0000000000000000)
+#                 DW_AT_high_pc	(0x0000000000000030)
+#
+# 0x00000044:   DW_TAG_subprogram
+#                 DW_AT_name	("main")
+#                 DW_AT_low_pc	(0x0000000000001000)
+#                 DW_AT_high_pc	(0x0000000000002000)
+#
+# 0x00000055:   DW_TAG_subprogram
+#                 DW_AT_name	("foo")
+#                 DW_AT_low_pc	(0x0000000000002000)
+#                 DW_AT_high_pc	(0x0000000000003000)
+#
+# 0x00000066:   NULL
+
+# RUN: yaml2obj %s | not llvm-dwarfdump --verify - | FileCheck %s --implicit-check-not=error:
+
+# CHECK: error: DIE has overlapping ranges in DW_AT_ranges attribute: [0x0000000000000000, 0x0000000000000020) and [0x0000000000000000, 0x0000000000000030)
+
+# CHECK: 0x0000000b:   DW_TAG_compile_unit
+# CHECK-NEXT:                DW_AT_name      ("/tmp/main.c")
+# CHECK-NEXT:                DW_AT_language  (DW_LANG_C)
+# CHECK-NEXT:                DW_AT_low_pc    (0x0000000000000000)
+# CHECK-NEXT:                DW_AT_ranges    (0x00000000
+# CHECK-NEXT:                   [0x0000000000002000, 0x0000000000003000)
+# CHECK-NEXT:                   [0x0000000000000000, 0x0000000000000020)
+# CHECK-NEXT:                   [0x0000000000000000, 0x0000000000000030)
+# CHECK-NEXT:                   [0x0000000000001000, 0x0000000000002000))
+
+# CHECK: error: DIEs have overlapping address ranges:
+# CHECK: 0x0000002f: DW_TAG_subprogram
+# CHECK-NEXT:              DW_AT_name        ("stripped2")
+# CHECK-NEXT:              DW_AT_low_pc      (0x0000000000000000)
+# CHECK-NEXT:              DW_AT_high_pc     (0x0000000000000030)
+
+# CHECK: 0x0000001e: DW_TAG_subprogram
+# CHECK-NEXT:              DW_AT_name        ("stripped1")
+# CHECK-NEXT:              DW_AT_low_pc      (0x0000000000000000)
+# CHECK-NEXT:              DW_AT_high_pc     (0x0000000000000020)
+
+# CHECK: Verifying .debug_info references...
+
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x01000007
+  cpusubtype:      0x00000003
+  filetype:        0x00000001
+  ncmds:           4
+  sizeofcmds:      464
+  flags:           0x00002000
+  reserved:        0x00000000
+LoadCommands:
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         392
+    segname:         ''
+    vmaddr:          0
+    vmsize:          261
+    fileoff:         528
+    filesize:        261
+    maxprot:         7
+    initprot:        7
+    nsects:          4
+    flags:           0
+    Sections:
+      - sectname:        __debug_abbrev
+        segname:         __DWARF
+        addr:            0x0000000000000000
+        size:            36
+        offset:          0x00000210
+        align:           0
+        reloff:          0x00000000
+        nreloc:          0
+        flags:           0x00000000
+        reserved1:       0x00000000
+        reserved2:       0x00000000
+        reserved3:       0x00000000
+        content:         011101030E1305110155170000022E00030E110112060000032E00030E11011201000000
+      - sectname:        __debug_info
+        segname:         __DWARF
+        addr:            0x0000000000000024
+        size:            103
+        offset:          0x00000234
+        align:           0
+        reloff:          0x00000000
+        nreloc:          0
+        flags:           0x00000000
+        reserved1:       0x00000000
+        reserved2:       0x00000000
+        reserved3:       0x00000000
+        content:         630000000400000000000801010000000200000000000000000000000000020D0000000000000000000000200000000317000000000000000000000030000000000000000221000000001000000000000000100000022600000000200000000000000010000000
+      - sectname:        __debug_ranges
+        segname:         __DWARF
+        addr:            0x000000000000008B
+        size:            80
+        offset:          0x0000029B
+        align:           0
+        reloff:          0x00000000
+        nreloc:          0
+        flags:           0x00000000
+        reserved1:       0x00000000
+        reserved2:       0x00000000
+        reserved3:       0x00000000
+        content:         '0020000000000000003000000000000000000000000000002000000000000000000000000000000030000000000000000010000000000000002000000000000000000000000000000000000000000000'
+      - sectname:        __debug_str
+        segname:         __DWARF
+        addr:            0x00000000000000DB
+        size:            42
+        offset:          0x000002EB
+        align:           0
+        reloff:          0x00000000
+        nreloc:          0
+        flags:           0x00000000
+        reserved1:       0x00000000
+        reserved2:       0x00000000
+        reserved3:       0x00000000
+        content:         002F746D702F6D61696E2E630073747269707065643100737472697070656432006D61696E00666F6F00
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          0
+    nsyms:           0
+    stroff:          792
+    strsize:         8
+  - cmd:             LC_BUILD_VERSION
+    cmdsize:         32
+    platform:        1
+    minos:           658944
+    sdk:             658944
+    ntools:          1
+    Tools:
+      - tool:            3
+        version:         34734080
+  - cmd:             LC_DATA_IN_CODE
+    cmdsize:         16
+    dataoff:         792
+    datasize:        0
+LinkEditData:
+  StringTable:
+    - ' '
+    - ''
+    - ''
+    - ''
+    - ''
+    - ''
+    - ''
+DWARF:
+  debug_str:
+    - ''
+    - '/tmp/main.c'
+    - stripped1
+    - stripped2
+    - main
+    - foo
+  debug_abbrev:
+    - Code:            0x00000001
+      Tag:             DW_TAG_compile_unit
+      Children:        DW_CHILDREN_yes
+      Attributes:
+        - Attribute:       DW_AT_name
+          Form:            DW_FORM_strp
+        - Attribute:       DW_AT_language
+          Form:            DW_FORM_data2
+        - Attribute:       DW_AT_low_pc
+          Form:            DW_FORM_addr
+        - Attribute:       DW_AT_ranges
+          Form:            DW_FORM_sec_offset
+    - Code:            0x00000002
+      Tag:             DW_TAG_subprogram
+      Children:        DW_CHILDREN_no
+      Attributes:
+        - Attribute:       DW_AT_name
+          Form:            DW_FORM_strp
+        - Attribute:       DW_AT_low_pc
+          Form:            DW_FORM_addr
+        - Attribute:       DW_AT_high_pc
+          Form:            DW_FORM_data4
+    - Code:            0x00000003
+      Tag:             DW_TAG_subprogram
+      Children:        DW_CHILDREN_no
+      Attributes:
+        - Attribute:       DW_AT_name
+          Form:            DW_FORM_strp
+        - Attribute:       DW_AT_low_pc
+          Form:            DW_FORM_addr
+        - Attribute:       DW_AT_high_pc
+          Form:            DW_FORM_addr
+  debug_ranges:
+    - Offset:          0x00000000
+      AddrSize:        0x08
+      Entries:
+        - LowOffset:       0x0000000000002000
+          HighOffset:      0x0000000000003000
+        - LowOffset:       0x0000000000000000
+          HighOffset:      0x0000000000000020
+        - LowOffset:       0x0000000000000000
+          HighOffset:      0x0000000000000030
+        - LowOffset:       0x0000000000001000
+          HighOffset:      0x0000000000002000
+  debug_info:
+    - Length:
+        TotalLength:     99
+      Version:         4
+      AbbrOffset:      0
+      AddrSize:        8
+      Entries:
+        - AbbrCode:        0x00000001
+          Values:
+            - Value:           0x0000000000000001
+            - Value:           0x0000000000000002
+            - Value:           0x0000000000000000
+            - Value:           0x0000000000000000
+        - AbbrCode:        0x00000002
+          Values:
+            - Value:           0x000000000000000D
+            - Value:           0x0000000000000000
+            - Value:           0x0000000000000020
+        - AbbrCode:        0x00000003
+          Values:
+            - Value:           0x0000000000000017
+            - Value:           0x0000000000000000
+            - Value:           0x0000000000000030
+        - AbbrCode:        0x00000002
+          Values:
+            - Value:           0x0000000000000021
+            - Value:           0x0000000000001000
+            - Value:           0x0000000000001000
+        - AbbrCode:        0x00000002
+          Values:
+            - Value:           0x0000000000000026
+            - Value:           0x0000000000002000
+            - Value:           0x0000000000001000
+        - AbbrCode:        0x00000000
+          Values:          []
+...


        


More information about the llvm-commits mailing list