Errors found processing the DW_AT_ranges attribute are propagated by lower level
routines and reported by their callers.
Reviewer: JDevlieghere
Differential Revision: https://reviews.llvm.org/D48344
llvm-svn: 335188
void clear();
void dump(raw_ostream &OS) const;
- bool extract(const DWARFDataExtractor &data, uint32_t *offset_ptr);
+ Error extract(const DWARFDataExtractor &data, uint32_t *offset_ptr);
const std::vector<RangeListEntry> &getEntries() { return Entries; }
/// getAbsoluteRanges - Returns absolute address ranges defined by this range
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,
+ Expected<DWARFDebugRnglist> findRangeList(DWARFDataExtractor Data,
uint32_t Offset);
uint32_t getHeaderOffset() const { return HeaderOffset; }
uint8_t getAddrSize() const { return HeaderData.AddrSize; }
///
/// \returns a address range vector that might be empty if no address range
/// information is available.
- DWARFAddressRangesVector getAddressRanges() const;
+ Expected<DWARFAddressRangesVector> getAddressRanges() const;
/// Get all address ranges for any DW_TAG_subprogram DIEs in this DIE or any
/// of its children.
return DataExtractor(StringSection, false, 0);
}
- /// extractRangeList - extracts the range list referenced by this compile
- /// unit from .debug_ranges section. Returns true on success.
- /// Requires that compile unit is already extracted.
- bool extractRangeList(uint32_t RangeListOffset,
- DWARFDebugRangeList &RangeList) const;
+ /// Extract the range list referenced by this compile unit from the
+ /// .debug_ranges section. If the extraction is unsuccessful, an error
+ /// is returned. Successful extraction requires that the compile unit
+ /// has already been extracted.
+ Error extractRangeList(uint32_t RangeListOffset,
+ DWARFDebugRangeList &RangeList) const;
void clear();
const Optional<StrOffsetsContributionDescriptor> &
/// 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);
+ Expected<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);
+ Expected<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
isLittleEndian(), savedAddressByteSize);
uint32_t offset = 0;
DWARFDebugRangeList rangeList;
- while (rangeList.extract(rangesData, &offset))
+ while (rangesData.isValidOffset(offset)) {
+ if (Error E = rangeList.extract(rangesData, &offset)) {
+ WithColor::error() << toString(std::move(E)) << '\n';
+ break;
+ }
rangeList.dump(OS);
+ }
}
if (shouldDump(Explicit, ".debug_rnglists", DIDT_ID_DebugRnglists,
using namespace llvm;
+// FIXME: There are several versions of this. Consolidate them.
+template <typename... Ts>
+static Error createError(char const *Fmt, const Ts &... Vals) {
+ std::string Buffer;
+ raw_string_ostream Stream(Buffer);
+ Stream << format(Fmt, Vals...);
+ return make_error<StringError>(Stream.str(), inconvertibleErrorCode());
+}
+
void DWARFDebugRangeList::clear() {
Offset = -1U;
AddressSize = 0;
Entries.clear();
}
-bool DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
- uint32_t *offset_ptr) {
+Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
+ uint32_t *offset_ptr) {
clear();
if (!data.isValidOffset(*offset_ptr))
- return false;
+ return createError("invalid range list offset 0x%" PRIx32, *offset_ptr);
+
AddressSize = data.getAddressSize();
if (AddressSize != 4 && AddressSize != 8)
- return false;
+ return createError("invalid address size: %d", AddressSize);
Offset = *offset_ptr;
while (true) {
RangeListEntry Entry;
// Check that both values were extracted correctly.
if (*offset_ptr != prev_offset + 2 * AddressSize) {
clear();
- return false;
+ return createError("invalid range list entry at offset 0x%" PRIx32,
+ prev_offset);
}
if (Entry.isEndOfListEntry())
break;
Entries.push_back(Entry);
}
- return true;
+ return Error::success();
}
void DWARFDebugRangeList::dump(raw_ostream &OS) const {
Error DWARFDebugRnglist::extract(DWARFDataExtractor Data, uint32_t HeaderOffset,
uint32_t End, uint32_t *OffsetPtr) {
+ if (*OffsetPtr < HeaderOffset || *OffsetPtr >= End)
+ return createError("invalid range list offset 0x%" PRIx32, *OffsetPtr);
Entries.clear();
while (*OffsetPtr < End) {
RangeListEntry Entry{0, 0, 0, 0, 0};
return HeaderData.Length + sizeof(uint32_t);
}
-Optional<DWARFDebugRnglist>
+Expected<DWARFDebugRnglist>
DWARFDebugRnglistTable::findRangeList(DWARFDataExtractor Data,
uint32_t Offset) {
auto Entry = Ranges.find(Offset);
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;
- }
+ if (Error E = RngList.extract(Data, HeaderOffset, End, &Offset))
+ return std::move(E);
Ranges[StartingOffset] = RngList;
return RngList;
}
FV.setUValue(*RangeListOffset);
FV.dump(OS, DumpOpts);
}
- dumpRanges(Obj, OS, Die.getAddressRanges(), U->getAddressByteSize(),
- sizeof(BaseIndent) + Indent + 4, DumpOpts);
+ if (auto RangesOrError = Die.getAddressRanges())
+ dumpRanges(Obj, OS, RangesOrError.get(), U->getAddressByteSize(),
+ sizeof(BaseIndent) + Indent + 4, DumpOpts);
+ else
+ WithColor::error() << "decoding address ranges: "
+ << toString(RangesOrError.takeError()) << '\n';
}
OS << ")\n";
return false;
}
-DWARFAddressRangesVector DWARFDie::getAddressRanges() const {
+Expected<DWARFAddressRangesVector> DWARFDie::getAddressRanges() const {
if (isNULL())
return DWARFAddressRangesVector();
// Single range specified by low/high PC.
uint64_t LowPC, HighPC, Index;
if (getLowAndHighPC(LowPC, HighPC, Index))
- return {{LowPC, HighPC, Index}};
+ return DWARFAddressRangesVector{{LowPC, HighPC, Index}};
Optional<DWARFFormValue> Value = find(DW_AT_ranges);
if (Value) {
if (isNULL())
return;
if (isSubprogramDIE()) {
- const auto &DIERanges = getAddressRanges();
- Ranges.insert(Ranges.end(), DIERanges.begin(), DIERanges.end());
+ if (auto DIERangesOrError = getAddressRanges())
+ Ranges.insert(Ranges.end(), DIERangesOrError.get().begin(),
+ DIERangesOrError.get().end());
+ else
+ llvm::consumeError(DIERangesOrError.takeError());
}
for (auto Child : children())
}
bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const {
- for (const auto &R : getAddressRanges()) {
+ auto RangesOrError = getAddressRanges();
+ if (!RangesOrError) {
+ llvm::consumeError(RangesOrError.takeError());
+ return false;
+ }
+
+ for (const auto &R : RangesOrError.get())
if (R.LowPC <= Address && Address < R.HighPC)
return true;
- }
return false;
}
return Table;
}
-bool DWARFUnit::extractRangeList(uint32_t RangeListOffset,
- DWARFDebugRangeList &RangeList) const {
+Error DWARFUnit::extractRangeList(uint32_t RangeListOffset,
+ DWARFDebugRangeList &RangeList) const {
// Require that compile unit is extracted.
assert(!DieArray.empty());
DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
}
}
-DWARFAddressRangesVector DWARFUnit::findRnglistFromOffset(uint32_t Offset) {
+Expected<DWARFAddressRangesVector>
+DWARFUnit::findRnglistFromOffset(uint32_t Offset) {
if (getVersion() <= 4) {
DWARFDebugRangeList RangeList;
- if (extractRangeList(Offset, RangeList))
- return RangeList.getAbsoluteRanges(getBaseAddress());
- return DWARFAddressRangesVector();
+ if (Error E = extractRangeList(Offset, RangeList))
+ return std::move(E);
+ return RangeList.getAbsoluteRanges(getBaseAddress());
}
if (RngListTable) {
DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
isLittleEndian, RngListTable->getAddrSize());
- if (auto RangeList = RngListTable->findRangeList(RangesData, Offset))
- return RangeList->getAbsoluteRanges(getBaseAddress());
+ auto RangeListOrError = RngListTable->findRangeList(RangesData, Offset);
+ if (RangeListOrError)
+ return RangeListOrError.get().getAbsoluteRanges(getBaseAddress());
+ return RangeListOrError.takeError();
}
- return DWARFAddressRangesVector();
+
+ return make_error<StringError>("missing or invalid range list table",
+ inconvertibleErrorCode());
}
-DWARFAddressRangesVector DWARFUnit::findRnglistFromIndex(uint32_t Index) {
+Expected<DWARFAddressRangesVector>
+DWARFUnit::findRnglistFromIndex(uint32_t Index) {
if (auto Offset = getRnglistOffset(Index))
return findRnglistFromOffset(*Offset + RangeSectionBase);
- return DWARFAddressRangesVector();
+
+ std::string Buffer;
+ raw_string_ostream Stream(Buffer);
+ if (RngListTable)
+ Stream << format("invalid range list table index %d", Index);
+ else
+ Stream << "missing or invalid range list table";
+ return make_error<StringError>(Stream.str(), inconvertibleErrorCode());
}
void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) {
if (!UnitDie)
return;
// First, check if unit DIE describes address ranges for the whole unit.
- const auto &CUDIERanges = UnitDie.getAddressRanges();
- if (!CUDIERanges.empty()) {
- CURanges.insert(CURanges.end(), CUDIERanges.begin(), CUDIERanges.end());
- return;
- }
+ auto CUDIERangesOrError = UnitDie.getAddressRanges();
+ if (CUDIERangesOrError) {
+ if (!CUDIERangesOrError.get().empty()) {
+ CURanges.insert(CURanges.end(), CUDIERangesOrError.get().begin(),
+ CUDIERangesOrError.get().end());
+ return;
+ }
+ } else
+ WithColor::error() << "decoding address ranges: "
+ << toString(CUDIERangesOrError.takeError()) << '\n';
// This function is usually called if there in no .debug_aranges section
// in order to produce a compile unit level set of address ranges that
void DWARFUnit::updateAddressDieMap(DWARFDie Die) {
if (Die.isSubroutineDIE()) {
- for (const auto &R : Die.getAddressRanges()) {
- // Ignore 0-sized ranges.
- if (R.LowPC == R.HighPC)
- continue;
- auto B = AddrDieMap.upper_bound(R.LowPC);
- if (B != AddrDieMap.begin() && R.LowPC < (--B)->second.first) {
- // The range is a sub-range of existing ranges, we need to split the
- // existing range.
- if (R.HighPC < B->second.first)
- AddrDieMap[R.HighPC] = B->second;
- if (R.LowPC > B->first)
- AddrDieMap[B->first].first = R.LowPC;
+ auto DIERangesOrError = Die.getAddressRanges();
+ if (DIERangesOrError) {
+ for (const auto &R : DIERangesOrError.get()) {
+ // Ignore 0-sized ranges.
+ if (R.LowPC == R.HighPC)
+ continue;
+ auto B = AddrDieMap.upper_bound(R.LowPC);
+ if (B != AddrDieMap.begin() && R.LowPC < (--B)->second.first) {
+ // The range is a sub-range of existing ranges, we need to split the
+ // existing range.
+ if (R.HighPC < B->second.first)
+ AddrDieMap[R.HighPC] = B->second;
+ if (R.LowPC > B->first)
+ AddrDieMap[B->first].first = R.LowPC;
+ }
+ AddrDieMap[R.LowPC] = std::make_pair(R.HighPC, Die);
}
- AddrDieMap[R.LowPC] = std::make_pair(R.HighPC, Die);
- }
+ } else
+ llvm::consumeError(DIERangesOrError.takeError());
}
// Parent DIEs are added to the AddrDieMap prior to the Children DIEs to
// simplify the logic to update AddrDieMap. The child's range will always
if (!Die.isValid())
return NumErrors;
- DWARFAddressRangesVector Ranges = Die.getAddressRanges();
+ auto RangesOrError = Die.getAddressRanges();
+ if (!RangesOrError) {
+ // FIXME: Report the error.
+ ++NumErrors;
+ llvm::consumeError(RangesOrError.takeError());
+ return NumErrors;
+ }
+ DWARFAddressRangesVector Ranges = RangesOrError.get();
// Build RI for this DIE and check that ranges within this DIE do not
// overlap.
DieRangeInfo RI(Die);
# RUN: llvm-mc -triple x86_64-pc-linux -filetype=obj %s -o %t
-# RUN: llvm-dwarfdump -v %t | FileCheck %s
+# RUN: llvm-dwarfdump -v %t 2>%t.err | FileCheck %s
+# RUN: FileCheck %s <%t.err -check-prefix=ERR
# CHECK: .debug_info contents:
# CHECK: 0x0000000b: DW_TAG_compile_unit [1]
.quad .Lfunc_begin0 # DW_AT_low_pc
.long .Ldebug_ranges0 # DW_AT_ranges
+# A CU with an invalid DW_AT_ranges attribute
+.Lcu_begin1:
+.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 0x4000 # DW_AT_ranges
+
+# ERR: error: decoding address ranges: invalid range list offset 0x4000
+
+# A CU where the DW_AT_ranges attribute points to an invalid range list.
+.Lcu_begin2:
+.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_ranges1 # DW_AT_ranges
+
.section .debug_ranges,"",@progbits
.Ldebug_ranges0:
.quad .Lfunc_begin0-.Lfunc_begin0
.quad .Ltmp5-.text.foo1
.quad 0
.quad 0
+.Ldebug_ranges1:
+ .quad 0
+
+# ERR: error: decoding address ranges: invalid range list entry at offset 0x50
# 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
+# RUN: llvm-dwarfdump -lookup 10 %t.o 2> %t2.err
+# RUN: FileCheck %s --input-file %t2.err --check-prefix=ERR
# Test object to verify dwarfdump handles v5 range lists.
# We use very simplified compile unit dies.
.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 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
.long 0 # DW_AT_ranges
.byte 0 # NULL
CU3_5_end:
+# A CU DIE with an incorrect DW_AT_ranges attribute
+ .long CU4_5_end-CU4_5_version # Length of Unit
+CU4_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 4000 # DW_AT_ranges
+ .byte 0 # NULL
+CU4_5_end:
.section .debug_info.dwo,"",@progbits
# CHECK-NEXT: [0x0000002a, 0x00000034))
#ERR: error: parsing a range list table: Did not detect a valid range list table with base = 0x8
+#ERR: error: decoding address ranges: missing or invalid range list table
+#ERR: error: decoding address ranges: invalid range list offset 0xfa0
for (const auto &RangeAttribute : Unit.getRangesAttributes()) {
uint32_t Offset = RangeAttribute.get();
RangeAttribute.set(Streamer->getRangesSectionSize());
- RangeList.extract(RangeExtractor, &Offset);
+ if (Error E = RangeList.extract(RangeExtractor, &Offset)) {
+ llvm::consumeError(std::move(E));
+ reportWarning("invalid range list ignored.", DMO);
+ RangeList.clear();
+ }
const auto &Entries = RangeList.getEntries();
if (!Entries.empty()) {
const DWARFDebugRangeList::RangeListEntry &First = Entries.front();
/// Extract the low pc from a Die.
static uint64_t getLowPC(DWARFDie Die) {
- if (Die.getAddressRanges().size())
- return Die.getAddressRanges()[0].LowPC;
+ auto RangesOrError = Die.getAddressRanges();
+ DWARFAddressRangesVector Ranges;
+ if (RangesOrError)
+ Ranges = RangesOrError.get();
+ else
+ llvm::consumeError(RangesOrError.takeError());
+ if (Ranges.size())
+ return Ranges[0].LowPC;
return dwarf::toAddress(Die.find(dwarf::DW_AT_low_pc), 0);
}
}
// PC Ranges.
- auto Ranges = Die.getAddressRanges();
+ auto RangesOrError = Die.getAddressRanges();
+ if (!RangesOrError) {
+ llvm::consumeError(RangesOrError.takeError());
+ return;
+ }
+
+ auto Ranges = RangesOrError.get();
uint64_t BytesInThisScope = 0;
for (auto Range : Ranges)
BytesInThisScope += Range.HighPC - Range.LowPC;