[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