[LLDB] - Add support for DW_FORM_rnglistx and relative DW_RLE_* entries.

This adds support for DW_RLE_base_addressx, DW_RLE_startx_endx,
DW_RLE_startx_length, DW_FORM_rnglistx.

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

llvm-svn: 345958
This commit is contained in:
George Rimar 2018-11-02 09:03:25 +00:00
parent 15da7684db
commit 5497f6580e
7 changed files with 175 additions and 21 deletions

View File

@ -0,0 +1,57 @@
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Entry: 0x0000000000201000
Sections:
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x0000000000201000
AddressAlign: 0x0000000000000010
Content: 31ED4989D15E4889E24883E4F0505449C7C08011200048C7C11011200048C7C700112000E897010000F4CCCCCCCCCCCC55B810202000483D102020004889E57417B8000000004885C0740D5DBF10202000FFE00F1F4400005DC3660F1F440000BE10202000554881EE102020004889E548C1FE034889F048C1E83F4801C648D1FE7415B8000000004885C0740B5DBF10202000FFE00F1F005DC3660F1F440000803D592F0000007517554889E5E87EFFFFFFC605472F0000015DC30F1F440000F3C30F1F4000662E0F1F840000000000554889E55DEB89CCCCCCCCCCCCCCCCCCC3CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC3CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC31C0C3CCCCCCCCCCCCCCCCCCCCCCCCCC415741564189FF415541544C8D25E61E000055488D2DE61E0000534989F64989D54C29E54883EC0848C1FD03E8430000004885ED742031DB0F1F8400000000004C89EA4C89F64489FF41FF14DC4883C3014839EB75EA4883C4085B5D415C415D415E415FC390662E0F1F840000000000F3C3
- Name: .debug_str_offsets
Type: SHT_PROGBITS
AddressAlign: 0x0000000000000001
Content: 28000000050000003000000067000000000000002800000076000000240000006F0000007400000022000000
- Name: .debug_str
Type: SHT_PROGBITS
Flags: [ SHF_MERGE, SHF_STRINGS ]
AddressAlign: 0x0000000000000001
Content: 2F686F6D652F756D622F74657374735F323031382F3131345F726E676C69737473007900696E74005F5A336261726900636C616E672076657273696F6E20382E302E3020287472756E6B203334353639392920286C6C766D2F7472756E6B203334353530362900746573742E6363006D61696E00780062617200
- Name: .debug_loclists
Type: SHT_PROGBITS
AddressAlign: 0x0000000000000001
Content: '15000000050008000000000003000301005503020101005000'
- Name: .debug_abbrev
Type: SHT_PROGBITS
AddressAlign: 0x0000000000000001
Content: 011101252513050325721710171B2573171101552374178C01170000022E01111B120640187A196E2503253A0B3B0B49133F190000030500021703253A0B3B0B49130000042E01111B120640187A1903253A0B3B0B49133F1900000534001C0D03253A0B3B0B4913000006240003253E0B0B0B000000
- Name: .debug_info
Type: SHT_PROGBITS
AddressAlign: 0x0000000000000001
Content: 6600000005000108000000000100040001080000000000000002080000000000000000000000000C0000000C00000002000400000001570304010365000000030C0000000701036500000000040106000000015706010765000000050108010865000000000605050400
- Name: .debug_rnglists
Type: SHT_PROGBITS
AddressAlign: 0x0000000000000001
Content: '1300000005000800010000000400000003000403010600'
- Name: .debug_macinfo
Type: SHT_PROGBITS
AddressAlign: 0x0000000000000001
Content: '00'
- Name: .debug_addr
Type: SHT_PROGBITS
AddressAlign: 0x0000000000000001
Content: 1C00000005000800E010200000000000F010200000000000E310200000000000
- Name: .debug_line
Type: SHT_PROGBITS
AddressAlign: 0x0000000000000001
Content: 82000000050008004C000000010101FB0E0D00010101010000000100000101011F010000000003011F020F051E022200000000FC42F1EAF1396417A8FBE442FBADC7032200000000FC42F1EAF1396417A8FBE442FBADC703000902E01020000000000014050B0A130504063C0201000101000902F0102000000000001805030A140206000101
- Name: .debug_line_str
Type: SHT_PROGBITS
Flags: [ SHF_MERGE, SHF_STRINGS ]
AddressAlign: 0x0000000000000001
Content: 2F686F6D652F756D622F74657374735F323031382F3131345F726E676C6973747300746573742E636300
Symbols:

View File

@ -0,0 +1,28 @@
# RUN: yaml2obj %p/Inputs/debug_rnglistx_rlex.yaml > %ttest
# RUN: lldb-test breakpoints %ttest %s | FileCheck %s
# The following code and invocation were used.
# clang -gdwarf-5 test.cc -o test_v5 -fuse-ld=lld -fno-rtti -O2 -ffunction-sections
# Then output was converted to yaml and reduced.
#
# int bar(int x) {
# return ++x;
# }
#
# int main() {
# int y = 1;
# return bar(y);
# }
#
# clang and LLD versions were 8.0.0 (trunk 345699)
#
# Output file contains DW_FORM_rnglistx and DW_RLE_startx_length.
b bar
b main
# CHECK-LABEL: b bar
# CHECK: Address: {{.*}}`bar(int) at test.cc:4:11
# CHECK-LABEL: b main
# CHECK: Address: {{.*}}`main at test.cc:9:3

View File

@ -157,6 +157,7 @@ bool DWARFDebugInfoEntry::FastExtract(
// signed or unsigned LEB 128 values
case DW_FORM_addrx:
case DW_FORM_rnglistx:
case DW_FORM_sdata:
case DW_FORM_udata:
case DW_FORM_ref_udata:
@ -387,6 +388,13 @@ void DWARFDebugInfoEntry::DumpAncestry(SymbolFileDWARF *dwarf2Data,
Dump(dwarf2Data, cu, s, recurse_depth);
}
static dw_offset_t GetRangesOffset(const DWARFDebugRangesBase *debug_ranges,
DWARFFormValue &form_value) {
if (form_value.Form() == DW_FORM_rnglistx)
return debug_ranges->GetOffset(form_value.Unsigned());
return form_value.Unsigned();
}
//----------------------------------------------------------------------
// GetDIENamesAndRanges
//
@ -464,7 +472,7 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges(
case DW_AT_ranges: {
const DWARFDebugRangesBase *debug_ranges = dwarf2Data->DebugRanges();
if (debug_ranges)
debug_ranges->FindRanges(cu, form_value.Unsigned(), ranges);
debug_ranges->FindRanges(cu, GetRangesOffset(debug_ranges, form_value), ranges);
else
cu->GetSymbolFileDWARF()->GetObjectFile()->GetModule()->ReportError(
"{0x%8.8x}: DIE has DW_AT_ranges(0x%" PRIx64
@ -748,11 +756,13 @@ void DWARFDebugInfoEntry::DumpAttribute(
} break;
case DW_AT_ranges: {
lldb::offset_t ranges_offset = form_value.Unsigned();
if (!dwarf2Data)
break;
lldb::offset_t ranges_offset =
GetRangesOffset(dwarf2Data->DebugRanges(), form_value);
dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0;
if (dwarf2Data)
DWARFDebugRanges::Dump(s, dwarf2Data->get_debug_ranges_data(),
&ranges_offset, base_addr);
DWARFDebugRanges::Dump(s, dwarf2Data->get_debug_ranges_data(),
&ranges_offset, base_addr);
} break;
default:
@ -1062,12 +1072,11 @@ size_t DWARFDebugInfoEntry::GetAttributeAddressRanges(
bool check_specification_or_abstract_origin) const {
ranges.Clear();
dw_offset_t debug_ranges_offset = GetAttributeValueAsUnsigned(
dwarf2Data, cu, DW_AT_ranges, DW_INVALID_OFFSET,
check_specification_or_abstract_origin);
if (debug_ranges_offset != DW_INVALID_OFFSET) {
DWARFFormValue form_value;
if (GetAttributeValue(dwarf2Data, cu, DW_AT_ranges, form_value)) {
if (DWARFDebugRangesBase *debug_ranges = dwarf2Data->DebugRanges())
debug_ranges->FindRanges(cu, debug_ranges_offset, ranges);
debug_ranges->FindRanges(cu, GetRangesOffset(debug_ranges, form_value),
ranges);
} else if (check_hi_lo_pc) {
dw_addr_t lo_pc = LLDB_INVALID_ADDRESS;
dw_addr_t hi_pc = LLDB_INVALID_ADDRESS;
@ -1718,12 +1727,12 @@ bool DWARFDebugInfoEntry::LookupAddress(const dw_addr_t address,
((function_die != NULL) || (block_die != NULL));
}
} else {
dw_offset_t debug_ranges_offset = GetAttributeValueAsUnsigned(
dwarf2Data, cu, DW_AT_ranges, DW_INVALID_OFFSET);
if (debug_ranges_offset != DW_INVALID_OFFSET) {
DWARFFormValue form_value;
if (GetAttributeValue(dwarf2Data, cu, DW_AT_ranges, form_value)) {
DWARFRangeList ranges;
DWARFDebugRangesBase *debug_ranges = dwarf2Data->DebugRanges();
debug_ranges->FindRanges(cu, debug_ranges_offset, ranges);
debug_ranges->FindRanges(
cu, GetRangesOffset(debug_ranges, form_value), ranges);
if (ranges.FindEntryThatContains(address)) {
found_address = true;

View File

@ -128,6 +128,11 @@ bool DWARFDebugRanges::FindRanges(const DWARFUnit *cu,
return false;
}
uint64_t DWARFDebugRanges::GetOffset(size_t Index) const {
lldbassert(false && "DW_FORM_rnglistx is not present before DWARF5");
return 0;
}
bool DWARFDebugRngLists::ExtractRangeList(
const DWARFDataExtractor &data, uint8_t addrSize,
lldb::offset_t *offset_ptr, std::vector<RngListEntry> &rangeList) {
@ -166,9 +171,27 @@ bool DWARFDebugRngLists::ExtractRangeList(
break;
}
case DW_RLE_base_addressx: {
dw_addr_t base = data.GetULEB128(offset_ptr);
rangeList.push_back({DW_RLE_base_addressx, base, 0});
break;
}
case DW_RLE_startx_endx: {
dw_addr_t start = data.GetULEB128(offset_ptr);
dw_addr_t end = data.GetULEB128(offset_ptr);
rangeList.push_back({DW_RLE_startx_endx, start, end});
break;
}
case DW_RLE_startx_length: {
dw_addr_t start = data.GetULEB128(offset_ptr);
dw_addr_t length = data.GetULEB128(offset_ptr);
rangeList.push_back({DW_RLE_startx_length, start, length});
break;
}
default:
// Next encodings are not yet supported:
// DW_RLE_base_addressx, DW_RLE_startx_endx, DW_RLE_startx_length.
lldbassert(0 && "unknown range list entry encoding");
error = true;
}
@ -177,6 +200,15 @@ bool DWARFDebugRngLists::ExtractRangeList(
return false;
}
static uint64_t ReadAddressFromDebugAddrSection(const DWARFUnit *cu,
uint32_t index) {
uint32_t index_size = cu->GetAddressByteSize();
dw_offset_t addr_base = cu->GetAddrBase();
lldb::offset_t offset = addr_base + index * index_size;
return cu->GetSymbolFileDWARF()->get_debug_addr_data().GetMaxU64(&offset,
index_size);
}
bool DWARFDebugRngLists::FindRanges(const DWARFUnit *cu,
dw_offset_t debug_ranges_offset,
DWARFRangeList &range_list) const {
@ -200,6 +232,21 @@ bool DWARFDebugRngLists::FindRanges(const DWARFUnit *cu,
range_list.Append(
DWARFRangeList::Entry(BaseAddr + E.value0, E.value1 - E.value0));
break;
case DW_RLE_base_addressx: {
BaseAddr = ReadAddressFromDebugAddrSection(cu, E.value0);
break;
}
case DW_RLE_startx_endx: {
dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0);
dw_addr_t end = ReadAddressFromDebugAddrSection(cu, E.value1);
range_list.Append(DWARFRangeList::Entry(start, end - start));
break;
}
case DW_RLE_startx_length: {
dw_addr_t start = ReadAddressFromDebugAddrSection(cu, E.value0);
range_list.Append(DWARFRangeList::Entry(start, E.value1));
break;
}
default:
llvm_unreachable("unexpected encoding");
}
@ -214,7 +261,8 @@ void DWARFDebugRngLists::Extract(SymbolFileDWARF *dwarf2Data) {
lldb::offset_t offset = 0;
uint64_t length = data.GetU32(&offset);
if (length == 0xffffffff)
bool isDwarf64 = (length == 0xffffffff);
if (isDwarf64)
length = data.GetU64(&offset);
lldb::offset_t end = offset + length;
@ -232,7 +280,7 @@ void DWARFDebugRngLists::Extract(SymbolFileDWARF *dwarf2Data) {
uint32_t offsetsAmount = data.GetU32(&offset);
for (uint32_t i = 0; i < offsetsAmount; ++i)
Offsets.push_back(data.GetPointer(&offset));
Offsets.push_back(data.GetMaxU64(&offset, isDwarf64 ? 8 : 4));
lldb::offset_t listOffset = offset;
std::vector<RngListEntry> rangeList;
@ -241,3 +289,7 @@ void DWARFDebugRngLists::Extract(SymbolFileDWARF *dwarf2Data) {
listOffset = offset;
}
}
uint64_t DWARFDebugRngLists::GetOffset(size_t Index) const {
return Offsets[Index];
}

View File

@ -22,15 +22,17 @@ public:
virtual void Extract(SymbolFileDWARF *dwarf2Data) = 0;
virtual bool FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset,
DWARFRangeList &range_list) const = 0;
virtual uint64_t GetOffset(size_t Index) const = 0;
};
class DWARFDebugRanges final : public DWARFDebugRangesBase {
public:
DWARFDebugRanges();
virtual void Extract(SymbolFileDWARF *dwarf2Data) override;
virtual bool FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset,
DWARFRangeList &range_list) const override;
void Extract(SymbolFileDWARF *dwarf2Data) override;
bool FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset,
DWARFRangeList &range_list) const override;
uint64_t GetOffset(size_t Index) const override;
static void Dump(lldb_private::Stream &s,
const lldb_private::DWARFDataExtractor &debug_ranges_data,
@ -58,6 +60,7 @@ public:
void Extract(SymbolFileDWARF *dwarf2Data) override;
bool FindRanges(const DWARFUnit *cu, dw_offset_t debug_ranges_offset,
DWARFRangeList &range_list) const override;
uint64_t GetOffset(size_t Index) const override;
protected:
bool ExtractRangeList(const lldb_private::DWARFDataExtractor &data,

View File

@ -248,6 +248,7 @@ bool DWARFFormValue::ExtractValue(const DWARFDataExtractor &data,
m_value.value.uval = data.GetU64(offset_ptr);
break;
case DW_FORM_addrx:
case DW_FORM_rnglistx:
case DW_FORM_strx:
case DW_FORM_udata:
case DW_FORM_ref_udata:
@ -393,6 +394,7 @@ bool DWARFFormValue::SkipValue(dw_form_t form,
// signed or unsigned LEB 128 values
case DW_FORM_addrx:
case DW_FORM_rnglistx:
case DW_FORM_sdata:
case DW_FORM_udata:
case DW_FORM_ref_udata:
@ -777,6 +779,7 @@ bool DWARFFormValue::FormIsSupported(dw_form_t form) {
switch (form) {
case DW_FORM_addr:
case DW_FORM_addrx:
case DW_FORM_rnglistx:
case DW_FORM_block2:
case DW_FORM_block4:
case DW_FORM_data2:

View File

@ -309,6 +309,8 @@ void DWARFUnit::ExtractDIEsEndCheck(lldb::offset_t offset) const {
void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) {
SetAddrBase(
cu_die.GetAttributeValueAsUnsigned(m_dwarf, this, DW_AT_addr_base, 0));
SetRangesBase(cu_die.GetAttributeValueAsUnsigned(m_dwarf, this,
DW_AT_rnglists_base, 0));
uint64_t base_addr = cu_die.GetAttributeValueAsAddress(
m_dwarf, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS);