mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[DWARF v5] Improved support for .debug_rnglists (consumer). Enables any consumer to
extract DWARF v5 encoded rangelists. Reviewer: JDevlieghere Differential Revision: https://reviews.llvm.org/D45549 llvm-svn: 332759
This commit is contained in:
parent
ef40796261
commit
fd2b373e39
@ -10,6 +10,7 @@
|
||||
#ifndef LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H
|
||||
#define LLVM_DEBUGINFO_DWARFDEBUGRNGLISTS_H
|
||||
|
||||
#include "llvm/BinaryFormat/Dwarf.h"
|
||||
#include "llvm/DebugInfo/DIContext.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
|
||||
@ -30,6 +31,8 @@ public:
|
||||
uint32_t Offset;
|
||||
/// The DWARF encoding (DW_RLE_*).
|
||||
uint8_t EntryKind;
|
||||
/// The index of the section this range belongs to.
|
||||
uint64_t SectionIndex;
|
||||
/// The values making up the range list entry. Most represent a range with
|
||||
/// a start and end address or a start address and a length. Others are
|
||||
/// single value base addresses or end-of-list with no values. The unneeded
|
||||
@ -51,6 +54,9 @@ public:
|
||||
void clear() { Entries.clear(); }
|
||||
Error extract(DWARFDataExtractor Data, uint32_t HeaderOffset, uint32_t End,
|
||||
uint32_t *OffsetPtr);
|
||||
/// Build a DWARFAddressRangesVector from a rangelist.
|
||||
DWARFAddressRangesVector
|
||||
getAbsoluteRanges(llvm::Optional<BaseAddress> BaseAddr) const;
|
||||
};
|
||||
|
||||
/// A class representing a table of range lists as specified in DWARF v5.
|
||||
@ -77,6 +83,7 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
dwarf::DwarfFormat Format;
|
||||
uint32_t HeaderOffset;
|
||||
Header HeaderData;
|
||||
std::vector<uint32_t> Offsets;
|
||||
@ -88,8 +95,31 @@ public:
|
||||
Error extractHeaderAndOffsets(DWARFDataExtractor Data, uint32_t *OffsetPtr);
|
||||
/// Extract an entire table, including all rangelists.
|
||||
Error extract(DWARFDataExtractor Data, uint32_t *OffsetPtr);
|
||||
/// Look up a rangelist based on a given offset. Extract it and enter it into
|
||||
/// the ranges map if necessary.
|
||||
Optional<DWARFDebugRnglist> findRangeList(DWARFDataExtractor Data,
|
||||
uint32_t Offset);
|
||||
uint32_t getHeaderOffset() const { return HeaderOffset; }
|
||||
uint8_t getAddrSize() const { return HeaderData.AddrSize; }
|
||||
void dump(raw_ostream &OS, DIDumpOptions DumpOpts) const;
|
||||
/// Return the contents of the offset entry designated by a given index.
|
||||
Optional<uint32_t> getOffsetEntry(uint32_t Index) const {
|
||||
if (Index < Offsets.size())
|
||||
return Offsets[Index];
|
||||
return None;
|
||||
}
|
||||
/// Return the size of the table header including the length but not including
|
||||
/// the offsets. This is dependent on the table format, which is unambiguously
|
||||
/// derived from parsing the table.
|
||||
uint8_t getHeaderSize() const {
|
||||
switch (Format) {
|
||||
case dwarf::DwarfFormat::DWARF32:
|
||||
return 12;
|
||||
case dwarf::DwarfFormat::DWARF64:
|
||||
return 20;
|
||||
}
|
||||
llvm_unreachable("Invalid DWARF format (expected DWARF32 or DWARF64");
|
||||
}
|
||||
|
||||
/// Returns the length of this table, including the length field, or 0 if the
|
||||
/// length has not been determined (e.g. because the table has not yet been
|
||||
|
@ -63,6 +63,7 @@ public:
|
||||
return Dummy;
|
||||
}
|
||||
virtual const DWARFSection &getRangeDWOSection() const { return Dummy; }
|
||||
virtual const DWARFSection &getRnglistsDWOSection() const { return Dummy; }
|
||||
virtual const DWARFSection &getAddrSection() const { return Dummy; }
|
||||
virtual const DWARFSection &getAppleNamesSection() const { return Dummy; }
|
||||
virtual const DWARFSection &getAppleTypesSection() const { return Dummy; }
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "llvm/BinaryFormat/Dwarf.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
|
||||
@ -261,6 +262,9 @@ class DWARFUnit {
|
||||
/// offsets table (DWARF v5).
|
||||
Optional<StrOffsetsContributionDescriptor> StringOffsetsTableContribution;
|
||||
|
||||
/// A table of range lists (DWARF v5 and later).
|
||||
Optional<DWARFDebugRnglistTable> RngListTable;
|
||||
|
||||
mutable const DWARFAbbreviationDeclarationSet *Abbrevs;
|
||||
llvm::Optional<BaseAddress> BaseAddr;
|
||||
/// The compile unit debug information entry items.
|
||||
@ -430,6 +434,24 @@ public:
|
||||
const char *getCompilationDir();
|
||||
Optional<uint64_t> getDWOId();
|
||||
|
||||
/// Return a vector of address ranges resulting from a (possibly encoded)
|
||||
/// range list starting at a given offset in the appropriate ranges section.
|
||||
DWARFAddressRangesVector findRnglistFromOffset(uint32_t Offset);
|
||||
|
||||
/// Return a vector of address ranges retrieved from an encoded range
|
||||
/// list whose offset is found via a table lookup given an index (DWARF v5
|
||||
/// and later).
|
||||
DWARFAddressRangesVector findRnglistFromIndex(uint32_t Index);
|
||||
|
||||
/// Return a rangelist's offset based on an index. The index designates
|
||||
/// an entry in the rangelist table's offset array and is supplied by
|
||||
/// DW_FORM_rnglistx.
|
||||
Optional<uint32_t> getRnglistOffset(uint32_t Index) {
|
||||
if (RngListTable)
|
||||
return RngListTable->getOffsetEntry(Index);
|
||||
return None;
|
||||
}
|
||||
|
||||
void collectAddressRanges(DWARFAddressRangesVector &CURanges);
|
||||
|
||||
/// Returns subprogram DIE with address range encompassing the provided
|
||||
|
@ -248,6 +248,28 @@ static void dumpStringOffsetsSection(
|
||||
}
|
||||
}
|
||||
|
||||
// Dump the .debug_rnglists or .debug_rnglists.dwo section (DWARF v5).
|
||||
static void dumpRnglistsSection(raw_ostream &OS,
|
||||
DWARFDataExtractor &rnglistData,
|
||||
DIDumpOptions DumpOpts) {
|
||||
uint32_t Offset = 0;
|
||||
while (rnglistData.isValidOffset(Offset)) {
|
||||
llvm::DWARFDebugRnglistTable Rnglists;
|
||||
uint32_t TableOffset = Offset;
|
||||
if (Error Err = Rnglists.extract(rnglistData, &Offset)) {
|
||||
WithColor::error() << toString(std::move(Err)) << '\n';
|
||||
uint64_t Length = Rnglists.length();
|
||||
// Keep going after an error, if we can, assuming that the length field
|
||||
// could be read. If it couldn't, stop reading the section.
|
||||
if (Length == 0)
|
||||
break;
|
||||
Offset = TableOffset + Length;
|
||||
} else {
|
||||
Rnglists.dump(OS, DumpOpts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DWARFContext::dump(
|
||||
raw_ostream &OS, DIDumpOptions DumpOpts,
|
||||
std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets) {
|
||||
@ -455,24 +477,16 @@ void DWARFContext::dump(
|
||||
|
||||
if (shouldDump(Explicit, ".debug_rnglists", DIDT_ID_DebugRnglists,
|
||||
DObj->getRnglistsSection().Data)) {
|
||||
DWARFDataExtractor rnglistData(*DObj, DObj->getRnglistsSection(),
|
||||
DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsSection(),
|
||||
isLittleEndian(), 0);
|
||||
uint32_t Offset = 0;
|
||||
while (rnglistData.isValidOffset(Offset)) {
|
||||
DWARFDebugRnglistTable Rnglists;
|
||||
uint32_t TableOffset = Offset;
|
||||
if (Error Err = Rnglists.extract(rnglistData, &Offset)) {
|
||||
WithColor::error() << toString(std::move(Err)) << '\n';
|
||||
uint64_t Length = Rnglists.length();
|
||||
// Keep going after an error, if we can, assuming that the length field
|
||||
// could be read. If it couldn't, stop reading the section.
|
||||
if (Length == 0)
|
||||
break;
|
||||
Offset = TableOffset + Length;
|
||||
} else {
|
||||
Rnglists.dump(OS, DumpOpts);
|
||||
}
|
||||
}
|
||||
dumpRnglistsSection(OS, RnglistData, DumpOpts);
|
||||
}
|
||||
|
||||
if (shouldDump(ExplicitDWO, ".debug_rnglists.dwo", DIDT_ID_DebugRnglists,
|
||||
DObj->getRnglistsDWOSection().Data)) {
|
||||
DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsDWOSection(),
|
||||
isLittleEndian(), 0);
|
||||
dumpRnglistsSection(OS, RnglistData, DumpOpts);
|
||||
}
|
||||
|
||||
if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames,
|
||||
@ -1173,6 +1187,7 @@ class DWARFObjInMemory final : public DWARFObject {
|
||||
DWARFSectionMap LocDWOSection;
|
||||
DWARFSectionMap StringOffsetDWOSection;
|
||||
DWARFSectionMap RangeDWOSection;
|
||||
DWARFSectionMap RnglistsDWOSection;
|
||||
DWARFSectionMap AddrSection;
|
||||
DWARFSectionMap AppleNamesSection;
|
||||
DWARFSectionMap AppleTypesSection;
|
||||
@ -1192,6 +1207,7 @@ class DWARFObjInMemory final : public DWARFObject {
|
||||
.Case("debug_loc.dwo", &LocDWOSection)
|
||||
.Case("debug_line.dwo", &LineDWOSection)
|
||||
.Case("debug_names", &DebugNamesSection)
|
||||
.Case("debug_rnglists.dwo", &RnglistsDWOSection)
|
||||
.Case("debug_str_offsets.dwo", &StringOffsetDWOSection)
|
||||
.Case("debug_addr", &AddrSection)
|
||||
.Case("apple_names", &AppleNamesSection)
|
||||
@ -1450,6 +1466,9 @@ public:
|
||||
const DWARFSection &getRangeDWOSection() const override {
|
||||
return RangeDWOSection;
|
||||
}
|
||||
const DWARFSection &getRnglistsDWOSection() const override {
|
||||
return RnglistsDWOSection;
|
||||
}
|
||||
const DWARFSection &getAddrSection() const override { return AddrSection; }
|
||||
StringRef getCUIndexSection() const override { return CUIndexSection; }
|
||||
StringRef getGdbIndexSection() const override { return GdbIndexSection; }
|
||||
|
@ -8,8 +8,8 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
|
||||
|
||||
#include "llvm/BinaryFormat/Dwarf.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@ -44,6 +44,7 @@ Error DWARFDebugRnglistTable::extractHeaderAndOffsets(DWARFDataExtractor Data,
|
||||
return createError(
|
||||
"DWARF64 is not supported in .debug_rnglists at offset 0x%" PRIx32,
|
||||
HeaderOffset);
|
||||
Format = dwarf::DwarfFormat::DWARF32;
|
||||
if (HeaderData.Length + sizeof(uint32_t) < sizeof(Header))
|
||||
return createError(".debug_rnglists table at offset 0x%" PRIx32
|
||||
" has too small length (0x%" PRIx32
|
||||
@ -90,6 +91,7 @@ Error DWARFDebugRnglist::RangeListEntry::extract(DWARFDataExtractor Data,
|
||||
uint32_t End,
|
||||
uint32_t *OffsetPtr) {
|
||||
Offset = *OffsetPtr;
|
||||
SectionIndex = -1ULL;
|
||||
// The caller should guarantee that we have at least 1 byte available, so
|
||||
// we just assert instead of revalidate.
|
||||
assert(*OffsetPtr < End &&
|
||||
@ -128,7 +130,7 @@ Error DWARFDebugRnglist::RangeListEntry::extract(DWARFDataExtractor Data,
|
||||
return createError("insufficient space remaining in table for "
|
||||
"DW_RLE_base_address encoding at offset 0x%" PRIx32,
|
||||
*OffsetPtr - 1);
|
||||
Value0 = Data.getAddress(OffsetPtr);
|
||||
Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
|
||||
break;
|
||||
}
|
||||
case dwarf::DW_RLE_start_end: {
|
||||
@ -137,13 +139,13 @@ Error DWARFDebugRnglist::RangeListEntry::extract(DWARFDataExtractor Data,
|
||||
"DW_RLE_start_end encoding "
|
||||
"at offset 0x%" PRIx32,
|
||||
*OffsetPtr - 1);
|
||||
Value0 = Data.getAddress(OffsetPtr);
|
||||
Value1 = Data.getAddress(OffsetPtr);
|
||||
Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
|
||||
Value1 = Data.getRelocatedAddress(OffsetPtr);
|
||||
break;
|
||||
}
|
||||
case dwarf::DW_RLE_start_length: {
|
||||
uint32_t PreviousOffset = *OffsetPtr - 1;
|
||||
Value0 = Data.getAddress(OffsetPtr);
|
||||
Value0 = Data.getRelocatedAddress(OffsetPtr, &SectionIndex);
|
||||
Value1 = Data.getULEB128(OffsetPtr);
|
||||
if (End < *OffsetPtr)
|
||||
return createError("read past end of table when reading "
|
||||
@ -161,6 +163,49 @@ Error DWARFDebugRnglist::RangeListEntry::extract(DWARFDataExtractor Data,
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
|
||||
llvm::Optional<BaseAddress> BaseAddr) const {
|
||||
DWARFAddressRangesVector Res;
|
||||
for (const RangeListEntry &RLE : Entries) {
|
||||
if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
|
||||
break;
|
||||
if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
|
||||
BaseAddr = {RLE.Value0, RLE.SectionIndex};
|
||||
continue;
|
||||
}
|
||||
|
||||
DWARFAddressRange E;
|
||||
E.SectionIndex = RLE.SectionIndex;
|
||||
if (BaseAddr && E.SectionIndex == -1ULL)
|
||||
E.SectionIndex = BaseAddr->SectionIndex;
|
||||
|
||||
switch (RLE.EntryKind) {
|
||||
case dwarf::DW_RLE_offset_pair:
|
||||
E.LowPC = RLE.Value0;
|
||||
E.HighPC = RLE.Value1;
|
||||
if (BaseAddr) {
|
||||
E.LowPC += BaseAddr->Address;
|
||||
E.HighPC += BaseAddr->Address;
|
||||
}
|
||||
break;
|
||||
case dwarf::DW_RLE_start_end:
|
||||
E.LowPC = RLE.Value0;
|
||||
E.HighPC = RLE.Value1;
|
||||
break;
|
||||
case dwarf::DW_RLE_start_length:
|
||||
E.LowPC = RLE.Value0;
|
||||
E.HighPC = E.LowPC + RLE.Value1;
|
||||
break;
|
||||
default:
|
||||
// Unsupported encodings should have been reported during extraction,
|
||||
// so we should not run into any here.
|
||||
llvm_unreachable("Unsupported range list encoding");
|
||||
}
|
||||
Res.push_back(E);
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
Error DWARFDebugRnglist::extract(DWARFDataExtractor Data, uint32_t HeaderOffset,
|
||||
uint32_t End, uint32_t *OffsetPtr) {
|
||||
Entries.clear();
|
||||
@ -305,3 +350,22 @@ uint32_t DWARFDebugRnglistTable::length() const {
|
||||
// TODO: DWARF64 support.
|
||||
return HeaderData.Length + sizeof(uint32_t);
|
||||
}
|
||||
|
||||
Optional<DWARFDebugRnglist>
|
||||
DWARFDebugRnglistTable::findRangeList(DWARFDataExtractor Data,
|
||||
uint32_t Offset) {
|
||||
auto Entry = Ranges.find(Offset);
|
||||
if (Entry != Ranges.end())
|
||||
return Entry->second;
|
||||
|
||||
// Extract the rangelist from the section and enter it into the ranges map.
|
||||
DWARFDebugRnglist RngList;
|
||||
uint32_t End = HeaderOffset + length();
|
||||
uint32_t StartingOffset = Offset;
|
||||
if (Error E = RngList.extract(Data, HeaderOffset, End, &Offset)) {
|
||||
llvm::consumeError(std::move(E));
|
||||
return None;
|
||||
}
|
||||
Ranges[StartingOffset] = RngList;
|
||||
return RngList;
|
||||
}
|
||||
|
@ -257,6 +257,16 @@ static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
|
||||
dumpApplePropertyAttribute(OS, *OptVal);
|
||||
} else if (Attr == DW_AT_ranges) {
|
||||
const DWARFObject &Obj = Die.getDwarfUnit()->getContext().getDWARFObj();
|
||||
// For DW_FORM_rnglistx we need to dump the offset separately, since
|
||||
// we have only dumped the index so far.
|
||||
Optional<DWARFFormValue> Value = Die.find(DW_AT_ranges);
|
||||
if (Value && Value->getForm() == DW_FORM_rnglistx)
|
||||
if (auto RangeListOffset =
|
||||
U->getRnglistOffset(*Value->getAsSectionOffset())) {
|
||||
DWARFFormValue FV(dwarf::DW_FORM_sec_offset);
|
||||
FV.setUValue(*RangeListOffset);
|
||||
FV.dump(OS, DumpOpts);
|
||||
}
|
||||
dumpRanges(Obj, OS, Die.getAddressRanges(), U->getAddressByteSize(),
|
||||
sizeof(BaseIndent) + Indent + 4, DumpOpts);
|
||||
}
|
||||
@ -380,12 +390,11 @@ DWARFAddressRangesVector DWARFDie::getAddressRanges() const {
|
||||
if (getLowAndHighPC(LowPC, HighPC, Index))
|
||||
return {{LowPC, HighPC, Index}};
|
||||
|
||||
// Multiple ranges from .debug_ranges section.
|
||||
auto RangesOffset = toSectionOffset(find(DW_AT_ranges));
|
||||
if (RangesOffset) {
|
||||
DWARFDebugRangeList RangeList;
|
||||
if (U->extractRangeList(*RangesOffset, RangeList))
|
||||
return RangeList.getAbsoluteRanges(U->getBaseAddress());
|
||||
Optional<DWARFFormValue> Value = find(DW_AT_ranges);
|
||||
if (Value) {
|
||||
if (Value->getForm() == DW_FORM_rnglistx)
|
||||
return U->findRnglistFromIndex(*Value->getAsSectionOffset());
|
||||
return U->findRnglistFromOffset(*Value->getAsSectionOffset());
|
||||
}
|
||||
return DWARFAddressRangesVector();
|
||||
}
|
||||
|
@ -280,6 +280,7 @@ bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
|
||||
break;
|
||||
case DW_FORM_udata:
|
||||
case DW_FORM_ref_udata:
|
||||
case DW_FORM_rnglistx:
|
||||
Value.uval = Data.getULEB128(OffsetPtr);
|
||||
break;
|
||||
case DW_FORM_string:
|
||||
@ -483,6 +484,10 @@ void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
|
||||
OS << "DW_FORM_indirect";
|
||||
break;
|
||||
|
||||
case DW_FORM_rnglistx:
|
||||
OS << format("indexed (0x%x) rangelist = ", (uint32_t)UValue);
|
||||
break;
|
||||
|
||||
// Should be formatted to 64-bit for DWARF64.
|
||||
case DW_FORM_sec_offset:
|
||||
AddrOS << format("0x%08x", (uint32_t)UValue);
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
|
||||
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
|
||||
#include "llvm/Support/DataExtractor.h"
|
||||
@ -150,6 +151,29 @@ bool DWARFUnitHeader::extract(DWARFContext &Context,
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parse the rangelist table header, including the optional array of offsets
|
||||
// following it (DWARF v5 and later).
|
||||
static Expected<DWARFDebugRnglistTable>
|
||||
parseRngListTableHeader(DWARFDataExtractor &DA, uint32_t Offset) {
|
||||
// TODO: Support DWARF64
|
||||
// We are expected to be called with Offset 0 or pointing just past the table
|
||||
// header, which is 12 bytes long for DWARF32.
|
||||
if (Offset > 0) {
|
||||
if (Offset < 12U) {
|
||||
std::string Buffer;
|
||||
raw_string_ostream Stream(Buffer);
|
||||
Stream << format(
|
||||
"Did not detect a valid range list table with base = 0x%x", Offset);
|
||||
return make_error<StringError>(Stream.str(), inconvertibleErrorCode());
|
||||
}
|
||||
Offset -= 12U;
|
||||
}
|
||||
llvm::DWARFDebugRnglistTable Table;
|
||||
if (Error E = Table.extractHeaderAndOffsets(DA, &Offset))
|
||||
return E;
|
||||
return Table;
|
||||
}
|
||||
|
||||
bool DWARFUnit::extractRangeList(uint32_t RangeListOffset,
|
||||
DWARFDebugRangeList &RangeList) const {
|
||||
// Require that compile unit is extracted.
|
||||
@ -281,6 +305,32 @@ size_t DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
|
||||
StringOffsetsTableContribution = determineStringOffsetsTableContribution(
|
||||
DA, StringOffsetsContributionBase);
|
||||
|
||||
// DWARF v5 uses the .debug_rnglists and .debug_rnglists.dwo sections to
|
||||
// describe address ranges.
|
||||
if (getVersion() >= 5) {
|
||||
if (isDWO)
|
||||
setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0);
|
||||
else
|
||||
setRangesSection(&Context.getDWARFObj().getRnglistsSection(),
|
||||
toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0));
|
||||
// Parse the range list table header. Individual range lists are
|
||||
// extracted lazily.
|
||||
DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection,
|
||||
isLittleEndian, 0);
|
||||
if (auto TableOrError =
|
||||
parseRngListTableHeader(RangesDA, RangeSectionBase))
|
||||
RngListTable = TableOrError.get();
|
||||
else
|
||||
WithColor::error() << "parsing a range list table: "
|
||||
<< toString(std::move(TableOrError.takeError()))
|
||||
<< '\n';
|
||||
|
||||
// In a split dwarf unit, there is no DW_AT_rnglists_base attribute.
|
||||
// Adjust RangeSectionBase to point past the table header.
|
||||
if (isDWO && RngListTable)
|
||||
RangeSectionBase = RngListTable->getHeaderSize();
|
||||
}
|
||||
|
||||
// Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for
|
||||
// skeleton CU DIE, so that DWARF users not aware of it are not broken.
|
||||
}
|
||||
@ -319,8 +369,23 @@ bool DWARFUnit::parseDWO() {
|
||||
DWO = std::shared_ptr<DWARFCompileUnit>(std::move(DWOContext), DWOCU);
|
||||
// Share .debug_addr and .debug_ranges section with compile unit in .dwo
|
||||
DWO->setAddrOffsetSection(AddrOffsetSection, AddrOffsetSectionBase);
|
||||
auto DWORangesBase = UnitDie.getRangesBaseAttribute();
|
||||
DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0);
|
||||
if (getVersion() >= 5) {
|
||||
DWO->setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0);
|
||||
DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection,
|
||||
isLittleEndian, 0);
|
||||
if (auto TableOrError = parseRngListTableHeader(RangesDA, RangeSectionBase))
|
||||
DWO->RngListTable = TableOrError.get();
|
||||
else
|
||||
WithColor::error() << "parsing a range list table: "
|
||||
<< toString(std::move(TableOrError.takeError()))
|
||||
<< '\n';
|
||||
if (DWO->RngListTable)
|
||||
DWO->RangeSectionBase = DWO->RngListTable->getHeaderSize();
|
||||
} else {
|
||||
auto DWORangesBase = UnitDie.getRangesBaseAttribute();
|
||||
DWO->setRangesSection(RangeSection, DWORangesBase ? *DWORangesBase : 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -331,6 +396,28 @@ void DWARFUnit::clearDIEs(bool KeepCUDie) {
|
||||
}
|
||||
}
|
||||
|
||||
DWARFAddressRangesVector DWARFUnit::findRnglistFromOffset(uint32_t Offset) {
|
||||
if (getVersion() <= 4) {
|
||||
DWARFDebugRangeList RangeList;
|
||||
if (extractRangeList(Offset, RangeList))
|
||||
return RangeList.getAbsoluteRanges(getBaseAddress());
|
||||
return DWARFAddressRangesVector();
|
||||
}
|
||||
if (RngListTable) {
|
||||
DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
|
||||
isLittleEndian, RngListTable->getAddrSize());
|
||||
if (auto RangeList = RngListTable->findRangeList(RangesData, Offset))
|
||||
return RangeList->getAbsoluteRanges(getBaseAddress());
|
||||
}
|
||||
return DWARFAddressRangesVector();
|
||||
}
|
||||
|
||||
DWARFAddressRangesVector DWARFUnit::findRnglistFromIndex(uint32_t Index) {
|
||||
if (auto Offset = getRnglistOffset(Index))
|
||||
return findRnglistFromOffset(*Offset + RangeSectionBase);
|
||||
return DWARFAddressRangesVector();
|
||||
}
|
||||
|
||||
void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) {
|
||||
DWARFDie UnitDie = getUnitDIE();
|
||||
if (!UnitDie)
|
||||
|
192
test/DebugInfo/X86/dwarfdump-rnglists.s
Normal file
192
test/DebugInfo/X86/dwarfdump-rnglists.s
Normal file
@ -0,0 +1,192 @@
|
||||
# RUN: llvm-mc -triple x86_64-unknown-linux %s -filetype=obj -o %t.o
|
||||
# RUN: llvm-dwarfdump -v -debug-info %t.o 2> %t.err | FileCheck %s
|
||||
# RUN: FileCheck %s --input-file %t.err --check-prefix=ERR
|
||||
|
||||
# Test object to verify dwarfdump handles v5 range lists.
|
||||
# We use very simplified compile unit dies.
|
||||
# There are 2 full CUs with DW_AT_rnglists_base, one with a DW_AT_ranges
|
||||
# attribute using DW_FORM_sec_offset, the other with DW_AT_ranges using
|
||||
# DW_FORM_rnglistx.
|
||||
|
||||
.section .debug_abbrev,"",@progbits
|
||||
.byte 0x01 # Abbrev code
|
||||
.byte 0x11 # DW_TAG_compile_unit
|
||||
.byte 0x00 # DW_CHILDREN_no
|
||||
.byte 0x74 # DW_AT_rnglists_base
|
||||
.byte 0x17 # DW_FORM_sec_offset
|
||||
.byte 0x55 # DW_AT_ranges
|
||||
.byte 0x17 # DW_FORM_sec_offset
|
||||
.byte 0x00 # EOM(1)
|
||||
.byte 0x00 # EOM(2)
|
||||
.byte 0x02 # Abbrev code
|
||||
.byte 0x11 # DW_TAG_compile_unit
|
||||
.byte 0x00 # DW_CHILDREN_no
|
||||
.byte 0x74 # DW_AT_rnglists_base
|
||||
.byte 0x17 # DW_FORM_sec_offset
|
||||
.byte 0x55 # DW_AT_ranges
|
||||
.byte 0x23 # DW_FORM_rnglistx
|
||||
.byte 0x00 # EOM(1)
|
||||
.byte 0x00 # EOM(2)
|
||||
.byte 0x00 # EOM(3)
|
||||
|
||||
# The split CU uses DW_FORM_rnglistx (the only correct option).
|
||||
# There is no DW_AT_rnglists_base in split units.
|
||||
.section .debug_abbrev.dwo,"",@progbits
|
||||
.byte 0x01 # Abbrev code
|
||||
.byte 0x11 # DW_TAG_compile_unit
|
||||
.byte 0x00 # DW_CHILDREN_no
|
||||
.byte 0x55 # DW_AT_ranges
|
||||
.byte 0x23 # DW_FORM_rnglistx
|
||||
.byte 0x00 # EOM(1)
|
||||
.byte 0x00 # EOM(2)
|
||||
.byte 0x00 # EOM(3)
|
||||
|
||||
.section .debug_info,"",@progbits
|
||||
# DWARF v5 CU header.
|
||||
.long CU1_5_end-CU1_5_version # Length of Unit
|
||||
CU1_5_version:
|
||||
.short 5 # DWARF version number
|
||||
.byte 1 # DWARF Unit Type
|
||||
.byte 4 # Address Size (in bytes)
|
||||
.long .debug_abbrev # Offset Into Abbrev. Section
|
||||
# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges.
|
||||
.byte 1 # Abbreviation code
|
||||
.long Rnglist_Table0_base # DW_AT_rnglists_base
|
||||
.long Rnglist_Table0_Rnglist0 # DW_AT_ranges
|
||||
.byte 0 # NULL
|
||||
.byte 0 # NULL
|
||||
CU1_5_end:
|
||||
|
||||
# DWARF v5 CU header
|
||||
.long CU2_5_end-CU2_5_version # Length of Unit
|
||||
CU2_5_version:
|
||||
.short 5 # DWARF version number
|
||||
.byte 1 # DWARF Unit Type
|
||||
.byte 4 # Address Size (in bytes)
|
||||
.long .debug_abbrev # Offset Into Abbrev. Section
|
||||
# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges.
|
||||
.byte 2 # Abbreviation code
|
||||
.long Rnglist_Table0_base # DW_AT_rnglists_base
|
||||
.uleb128 1 # DW_AT_ranges
|
||||
.byte 0 # NULL
|
||||
CU2_5_end:
|
||||
# A CU with an invalid DW_AT_rnglists_base attribute
|
||||
.long CU3_5_end-CU3_5_version # Length of Unit
|
||||
CU3_5_version:
|
||||
.short 5 # DWARF version number
|
||||
.byte 1 # DWARF Unit Type
|
||||
.byte 4 # Address Size (in bytes)
|
||||
.long .debug_abbrev # Offset Into Abbrev. Section
|
||||
# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges.
|
||||
.byte 2 # Abbreviation code
|
||||
.long 0x8 # DW_AT_rnglists_base
|
||||
.long 0 # DW_AT_ranges
|
||||
.byte 0 # NULL
|
||||
CU3_5_end:
|
||||
|
||||
.section .debug_info.dwo,"",@progbits
|
||||
|
||||
# DWARF v5 split CU header.
|
||||
.long CU_split_5_end-CU_split_5_version # Length of Unit
|
||||
CU_split_5_version:
|
||||
.short 5 # DWARF version number
|
||||
.byte 5 # DWARF Unit Type
|
||||
.byte 4 # Address Size (in bytes)
|
||||
.long 0 # Offset Into Abbrev Section
|
||||
# The compile-unit DIE, which has DW_AT_rnglists_base and DW_AT_ranges.
|
||||
.byte 1 # Abbreviation code
|
||||
.uleb128 1 # DW_AT_ranges
|
||||
.byte 0 # NULL
|
||||
CU_split_5_end:
|
||||
|
||||
.section .debug_rnglists,"",@progbits
|
||||
# A rnglist table with 2 range lists. The first one uses DW_RLE_start_end
|
||||
# and DW_RLE_start_length. The second one uses DW_RLE_base_address and
|
||||
# DW_RLE_offset_pair. The range lists have entries in the offset table.
|
||||
.long Rnglist_Table0_end - Rnglist_Table0 # table length
|
||||
Rnglist_Table0:
|
||||
.short 5 # version
|
||||
.byte 4 # address size
|
||||
.byte 0 # segment selector size
|
||||
.long 2 # offset entry count
|
||||
Rnglist_Table0_base:
|
||||
# 2 offset entries which can be used by DW_FORM_rnglistx.
|
||||
.long Rnglist_Table0_Rnglist0 - Rnglist_Table0_base
|
||||
.long Rnglist_Table0_Rnglist1 - Rnglist_Table0_base
|
||||
Rnglist_Table0_Rnglist0:
|
||||
.byte 6 # DW_RLE_start_end
|
||||
.long Range0_start
|
||||
.long Range0_end
|
||||
.byte 7 # DW_RLE_start_length
|
||||
.long Range1_start
|
||||
.uleb128 Range1_end - Range1_start
|
||||
.byte 0 # DW_RLE_end_of_list
|
||||
Rnglist_Table0_Rnglist1:
|
||||
.byte 5 # DW_RLE_base_address
|
||||
.long Range0_start
|
||||
.byte 4 # DW_RLE_offset_pair
|
||||
.uleb128 Range1_start - Range0_start
|
||||
.uleb128 Range1_end - Range0_start
|
||||
.byte 0 # DW_RLE_end_of_list
|
||||
Rnglist_Table0_end:
|
||||
|
||||
# A rnglist table for the split unit with an empty rangelist and one that
|
||||
# uses DW_RLE_base_address and DW_RLE_offset_pair. The ranges have entries
|
||||
# in the offset table. We use the empty range list so we can test
|
||||
# DW_FORM_rnglistx with an index other than 0.
|
||||
.section .debug_rnglists.dwo,"",@progbits
|
||||
.long Rnglist_Table0_dwo_end - Rnglist_Table0_dwo # table length
|
||||
Rnglist_Table0_dwo:
|
||||
.short 5 # version
|
||||
.byte 4 # address size
|
||||
.byte 0 # segment selector size
|
||||
.long 2 # offset entry count
|
||||
Rnglist_Table0_base_dwo:
|
||||
# 2 offset entries which can be used by DW_FORM_rnglistx.
|
||||
.long Rnglist_Table0_Rnglist0_dwo - Rnglist_Table0_base_dwo
|
||||
.long Rnglist_Table0_Rnglist1_dwo - Rnglist_Table0_base_dwo
|
||||
Rnglist_Table0_Rnglist0_dwo:
|
||||
.byte 0 # DW_RLE_start_end
|
||||
Rnglist_Table0_Rnglist1_dwo:
|
||||
.byte 5 # DW_RLE_base_address
|
||||
.long Range0_start - .text
|
||||
.byte 4 # DW_RLE_offset_pair
|
||||
.uleb128 Range1_start - Range0_start
|
||||
.uleb128 Range1_end - Range0_start
|
||||
.byte 0 # DW_RLE_end_of_list
|
||||
Rnglist_Table0_dwo_end:
|
||||
|
||||
.text
|
||||
.space 20
|
||||
Range0_start: # Range0: 0x14 - 0x1c
|
||||
.space 10
|
||||
Range0_end:
|
||||
.space 12
|
||||
Range1_start: # Range1: 0x2a - 0x34
|
||||
.space 10
|
||||
Range1_end:
|
||||
|
||||
# CHECK: .debug_info contents:
|
||||
# CHECK: Compile Unit:
|
||||
# CHECK-NOT: Compile Unit:
|
||||
# CHECK: DW_TAG_compile_unit
|
||||
# CHECK-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c)
|
||||
# CHECK-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000014
|
||||
# CHECK-NEXT: [0x00000014, 0x0000001e) ".text"
|
||||
# CHECK-NEXT: [0x0000002a, 0x00000034) ".text")
|
||||
|
||||
# CHECK: Compile Unit:
|
||||
# CHECK-NOT: Compile Unit:
|
||||
# CHECK: DW_TAG_compile_unit
|
||||
# CHECK-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c)
|
||||
# CHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x00000018
|
||||
# CHECK-NEXT: [0x0000002a, 0x00000034) ".text")
|
||||
|
||||
# CHECK: .debug_info.dwo contents:
|
||||
# CHECK: Compile Unit:
|
||||
# CHECK-NOT: contents:
|
||||
# CHECK: DW_TAG_compile_unit
|
||||
# CHECK-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x00000009
|
||||
# CHECK-NEXT: [0x0000002a, 0x00000034))
|
||||
|
||||
#ERR: error: parsing a range list table: Did not detect a valid range list table with base = 0x8
|
Loading…
x
Reference in New Issue
Block a user