Skip to content

Commit

Permalink
[DebugInfo] - Fix for lld DWARF parsing of base address selection ent…
Browse files Browse the repository at this point in the history
…ries in range lists.

It solves issue of wrong section index evaluating for ranges when
base address is used.

Based on David Blaikie's patch D36097.

Differential revision: https://reviews.llvm.org/D37214

llvm-svn: 312477
  • Loading branch information
George Rimar committed Sep 4, 2017
1 parent 8703e38 commit 2f95c8b
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 16 deletions.
4 changes: 3 additions & 1 deletion llvm/include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h
Expand Up @@ -18,6 +18,7 @@

namespace llvm {

struct BaseAddress;
class raw_ostream;

struct DWARFAddressRange {
Expand Down Expand Up @@ -85,7 +86,8 @@ class DWARFDebugRangeList {
/// getAbsoluteRanges - Returns absolute address ranges defined by this range
/// list. Has to be passed base address of the compile unit referencing this
/// range list.
DWARFAddressRangesVector getAbsoluteRanges(uint64_t BaseAddress) const;
DWARFAddressRangesVector
getAbsoluteRanges(llvm::Optional<BaseAddress> BaseAddr) const;
};

} // end namespace llvm
Expand Down
14 changes: 9 additions & 5 deletions llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
Expand Up @@ -110,6 +110,12 @@ class DWARFUnitSection final : public SmallVector<std::unique_ptr<UnitType>, 1>,
}
};

/// Represents base address of the CU.
struct BaseAddress {
uint64_t Address;
uint64_t SectionIndex;
};

class DWARFUnit {
DWARFContext &Context;
/// Section containing this DWARFUnit.
Expand All @@ -135,7 +141,7 @@ class DWARFUnit {
uint32_t Length;
const DWARFAbbreviationDeclarationSet *Abbrevs;
uint8_t UnitType;
uint64_t BaseAddr;
llvm::Optional<BaseAddress> BaseAddr;
/// The compile unit debug information entry items.
std::vector<DWARFDebugInfoEntry> DieArray;

Expand Down Expand Up @@ -259,11 +265,9 @@ class DWARFUnit {
llvm_unreachable("Invalid UnitType.");
}

uint64_t getBaseAddress() const { return BaseAddr; }
llvm::Optional<BaseAddress> getBaseAddress() const { return BaseAddr; }

void setBaseAddress(uint64_t base_addr) {
BaseAddr = base_addr;
}
void setBaseAddress(BaseAddress BaseAddr) { this->BaseAddr = BaseAddr; }

DWARFDie getUnitDIE(bool ExtractUnitDIEOnly = true) {
extractDIEsIfNeeded(ExtractUnitDIEOnly);
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
Expand Up @@ -14,6 +14,8 @@ using namespace llvm;

uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint32_t *Off,
uint64_t *SecNdx) const {
if (SecNdx)
*SecNdx = -1ULL;
if (!Section)
return getUnsigned(Off, Size);
Optional<RelocAddrEntry> Rel = Obj->find(*Section, *Off);
Expand Down
25 changes: 19 additions & 6 deletions llvm/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
Expand Up @@ -63,16 +63,29 @@ void DWARFDebugRangeList::dump(raw_ostream &OS) const {
OS << format("%08x <End of list>\n", Offset);
}

DWARFAddressRangesVector
DWARFDebugRangeList::getAbsoluteRanges(uint64_t BaseAddress) const {
DWARFAddressRangesVector DWARFDebugRangeList::getAbsoluteRanges(
llvm::Optional<BaseAddress> BaseAddr) const {
DWARFAddressRangesVector Res;
for (const RangeListEntry &RLE : Entries) {
if (RLE.isBaseAddressSelectionEntry(AddressSize)) {
BaseAddress = RLE.EndAddress;
} else {
Res.push_back({BaseAddress + RLE.StartAddress,
BaseAddress + RLE.EndAddress, RLE.SectionIndex});
BaseAddr = {RLE.EndAddress, RLE.SectionIndex};
continue;
}

DWARFAddressRange E;
E.LowPC = RLE.StartAddress;
E.HighPC = RLE.EndAddress;
E.SectionIndex = RLE.SectionIndex;
// Base address of a range list entry is determined by the closest preceding
// base address selection entry in the same range list. It defaults to the
// base address of the compilation unit if there is no such entry.
if (BaseAddr) {
E.LowPC += BaseAddr->Address;
E.HighPC += BaseAddr->Address;
if (E.SectionIndex == -1ULL)
E.SectionIndex = BaseAddr->SectionIndex;
}
Res.push_back(E);
}
return Res;
}
9 changes: 5 additions & 4 deletions llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
Expand Up @@ -160,7 +160,7 @@ void DWARFUnit::clear() {
Length = 0;
Abbrevs = nullptr;
FormParams = DWARFFormParams({0, 0, DWARF32});
BaseAddr = 0;
BaseAddr.reset();
RangeSectionBase = 0;
AddrOffsetSectionBase = 0;
clearDIEs(false);
Expand Down Expand Up @@ -242,9 +242,10 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
// If CU DIE was just parsed, copy several attribute values from it.
if (!HasCUDie) {
DWARFDie UnitDie = getUnitDIE();
auto BaseAddr = toAddress(UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc}));
if (BaseAddr)
setBaseAddress(*BaseAddr);
Optional<DWARFFormValue> PC = UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc});
if (Optional<uint64_t> Addr = toAddress(PC))
setBaseAddress({*Addr, PC->getSectionIndex()});

if (!isDWO) {
assert(AddrOffsetSectionBase == 0);
assert(RangeSectionBase == 0);
Expand Down
Binary file not shown.
13 changes: 13 additions & 0 deletions llvm/test/DebugInfo/X86/dwarfdump-ranges-baseaddr-exe.s
@@ -0,0 +1,13 @@
# RUN: llvm-dwarfdump %S/../Inputs/dwarfdump-ranges-baseaddr-exe.elf-x86-64 \
# RUN: | FileCheck %s

## Executable binary for test produced from object built in
## dwarfdump-ranges-baseaddr.s testcase.

# CHECK: .debug_info contents:
# CHECK: 0x0000000b: DW_TAG_compile_unit [1]
# CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000000400078)
# CHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000
# CHECK-NEXT: [0x0000000000400078 - 0x0000000000400079)
# CHECK-NEXT: [0x000000000040007b - 0x000000000040007e)
# CHECK-NEXT: [0x000000000040007f - 0x0000000000400080))
82 changes: 82 additions & 0 deletions llvm/test/DebugInfo/X86/dwarfdump-ranges-baseaddr.s
@@ -0,0 +1,82 @@
# RUN: llvm-mc -triple x86_64-pc-linux -filetype=obj %s -o %t
# RUN: llvm-dwarfdump %t | FileCheck %s

# CHECK: .debug_info contents:
# CHECK: 0x0000000b: DW_TAG_compile_unit [1]
# CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000)
# CHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000
# CHECK-NEXT: [0x0000000000000000 - 0x0000000000000001) ".text"
# CHECK-NEXT: [0x0000000000000003 - 0x0000000000000006) ".text"
# CHECK-NEXT: [0x0000000000000001 - 0x0000000000000002) ".text.foo1")

.text
.globl foo
.type foo,@function
foo:
.Lfunc_begin0:
nop
.Ltmp0:
nop
nop
.Ltmp1:
nop
nop
nop
.Ltmp2:

.section .text.foo1,"ax",@progbits
.Ltmp3:
nop
.Ltmp4:
nop
.Ltmp5:

.section .debug_abbrev,"",@progbits
.byte 1 # Abbreviation Code
.byte 17 # DW_TAG_compile_unit
.byte 0 # DW_CHILDREN_no
.byte 37 # DW_AT_producer
.byte 14 # DW_FORM_strp
.byte 19 # DW_AT_language
.byte 5 # DW_FORM_data2
.byte 3 # DW_AT_name
.byte 14 # DW_FORM_strp
.byte 16 # DW_AT_stmt_list
.byte 23 # DW_FORM_sec_offset
.byte 27 # DW_AT_comp_dir
.byte 14 # DW_FORM_strp
.byte 17 # DW_AT_low_pc
.byte 1 # DW_FORM_addr
.byte 85 # DW_AT_ranges
.byte 23 # DW_FORM_sec_offset
.byte 0 # EOM(1)
.byte 0 # EOM(2)
.byte 0 # EOM(3)

.section .debug_info,"",@progbits
.Lcu_begin0:
.long 38 # Length of Unit
.short 4 # DWARF version number
.long .debug_abbrev # Offset Into Abbrev. Section
.byte 8 # Address Size (in bytes)
.byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit
.long 0 # DW_AT_producer
.short 4 # DW_AT_language
.long 0 # DW_AT_name
.long 0 # DW_AT_stmt_list
.long 0 # DW_AT_comp_dir
.quad .Lfunc_begin0 # DW_AT_low_pc
.long .Ldebug_ranges0 # DW_AT_ranges

.section .debug_ranges,"",@progbits
.Ldebug_ranges0:
.quad .Lfunc_begin0-.Lfunc_begin0
.quad .Ltmp0-.Lfunc_begin0
.quad .Ltmp1-.Lfunc_begin0
.quad .Ltmp2-.Lfunc_begin0
.quad 0xFFFFFFFFFFFFFFFF
.quad .text.foo1
.quad .Ltmp4-.text.foo1
.quad .Ltmp5-.text.foo1
.quad 0
.quad 0

0 comments on commit 2f95c8b

Please sign in to comment.