Index: include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h +++ include/llvm/DebugInfo/DWARF/DWARFDebugRangeList.h @@ -71,7 +71,7 @@ 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 &getEntries() { return Entries; } /// getAbsoluteRanges - Returns absolute address ranges defined by this range Index: include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h +++ include/llvm/DebugInfo/DWARF/DWARFDebugRnglists.h @@ -97,7 +97,7 @@ 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 findRangeList(DWARFDataExtractor Data, + Expected findRangeList(DWARFDataExtractor Data, uint32_t Offset); uint32_t getHeaderOffset() const { return HeaderOffset; } uint8_t getAddrSize() const { return HeaderData.AddrSize; } Index: include/llvm/DebugInfo/DWARF/DWARFDie.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFDie.h +++ include/llvm/DebugInfo/DWARF/DWARFDie.h @@ -207,7 +207,7 @@ /// /// \returns a address range vector that might be empty if no address range /// information is available. - DWARFAddressRangesVector getAddressRanges() const; + Expected getAddressRanges() const; /// Get all address ranges for any DW_TAG_subprogram DIEs in this DIE or any /// of its children. Index: include/llvm/DebugInfo/DWARF/DWARFUnit.h =================================================================== --- include/llvm/DebugInfo/DWARF/DWARFUnit.h +++ include/llvm/DebugInfo/DWARF/DWARFUnit.h @@ -371,11 +371,12 @@ 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 & @@ -450,12 +451,12 @@ /// 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 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 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 Index: lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFContext.cpp +++ lib/DebugInfo/DWARF/DWARFContext.cpp @@ -470,8 +470,13 @@ 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, Index: lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp +++ lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp @@ -16,20 +16,30 @@ using namespace llvm; +// FIXME: There are several versions of this. Consolidate them. +template +static Error createError(char const *Fmt, const Ts &... Vals) { + std::string Buffer; + raw_string_ostream Stream(Buffer); + Stream << format(Fmt, Vals...); + return make_error(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; @@ -43,13 +53,14 @@ // 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 { Index: lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp +++ lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp @@ -208,6 +208,8 @@ 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}; @@ -351,7 +353,7 @@ return HeaderData.Length + sizeof(uint32_t); } -Optional +Expected DWARFDebugRnglistTable::findRangeList(DWARFDataExtractor Data, uint32_t Offset) { auto Entry = Ranges.find(Offset); @@ -362,10 +364,8 @@ 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; } Index: lib/DebugInfo/DWARF/DWARFDie.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFDie.cpp +++ lib/DebugInfo/DWARF/DWARFDie.cpp @@ -270,8 +270,12 @@ 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"; @@ -385,13 +389,13 @@ return false; } -DWARFAddressRangesVector DWARFDie::getAddressRanges() const { +Expected 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 Value = find(DW_AT_ranges); if (Value) { @@ -407,8 +411,11 @@ 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()) @@ -416,10 +423,15 @@ } 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; } Index: lib/DebugInfo/DWARF/DWARFUnit.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFUnit.cpp +++ lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -181,8 +181,8 @@ 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, @@ -397,26 +397,39 @@ } } -DWARFAddressRangesVector DWARFUnit::findRnglistFromOffset(uint32_t Offset) { +Expected +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("Missing or invalid range list table", + inconvertibleErrorCode()); } -DWARFAddressRangesVector DWARFUnit::findRnglistFromIndex(uint32_t Index) { +Expected +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(Stream.str(), inconvertibleErrorCode()); } void DWARFUnit::collectAddressRanges(DWARFAddressRangesVector &CURanges) { @@ -424,11 +437,16 @@ 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 @@ -454,21 +472,25 @@ 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 Index: lib/DebugInfo/DWARF/DWARFVerifier.cpp =================================================================== --- lib/DebugInfo/DWARF/DWARFVerifier.cpp +++ lib/DebugInfo/DWARF/DWARFVerifier.cpp @@ -324,8 +324,15 @@ 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); Index: test/DebugInfo/X86/dwarfdump-ranges-baseaddr.s =================================================================== --- test/DebugInfo/X86/dwarfdump-ranges-baseaddr.s +++ test/DebugInfo/X86/dwarfdump-ranges-baseaddr.s @@ -1,5 +1,6 @@ # 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] @@ -68,6 +69,38 @@ .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 @@ -80,3 +113,7 @@ .quad .Ltmp5-.text.foo1 .quad 0 .quad 0 +.Ldebug_ranges1: + .quad 0 + +# ERR: error: decoding address ranges: invalid range list entry at offset 0x50 Index: test/DebugInfo/X86/dwarfdump-rnglists.s =================================================================== --- test/DebugInfo/X86/dwarfdump-rnglists.s +++ test/DebugInfo/X86/dwarfdump-rnglists.s @@ -1,6 +1,8 @@ # 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. @@ -42,7 +44,6 @@ .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 @@ -57,7 +58,6 @@ .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 @@ -83,6 +83,19 @@ .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 @@ -190,3 +203,5 @@ # 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 Index: tools/dsymutil/DwarfLinker.cpp =================================================================== --- tools/dsymutil/DwarfLinker.cpp +++ tools/dsymutil/DwarfLinker.cpp @@ -3503,7 +3503,11 @@ 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(); Index: tools/llvm-dwarfdump/Statistics.cpp =================================================================== --- tools/llvm-dwarfdump/Statistics.cpp +++ tools/llvm-dwarfdump/Statistics.cpp @@ -34,8 +34,14 @@ /// 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); } @@ -137,7 +143,13 @@ } // 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;