mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-28 02:37:37 +00:00
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
This commit is contained in:
parent
bd7defeb94
commit
ccf5a44917
@ -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;
|
||||
};
|
||||
|
@ -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 @@ public:
|
||||
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 {
|
||||
|
@ -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.
|
||||
|
@ -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: []
|
||||
...
|
Loading…
Reference in New Issue
Block a user