diff options
Diffstat (limited to 'llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp')
-rw-r--r-- | llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 163 |
1 files changed, 126 insertions, 37 deletions
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp index a56402a707ad..7bb019466161 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -175,18 +175,37 @@ DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section, const DWARFSection *AOS, const DWARFSection &LS, bool LE, bool IsDWO, const DWARFUnitVector &UnitVector) : Context(DC), InfoSection(Section), Header(Header), Abbrev(DA), - RangeSection(RS), LocSection(LocSection), LineSection(LS), - StringSection(SS), StringOffsetSection(SOS), AddrOffsetSection(AOS), - isLittleEndian(LE), IsDWO(IsDWO), UnitVector(UnitVector) { + RangeSection(RS), LineSection(LS), StringSection(SS), + StringOffsetSection(SOS), AddrOffsetSection(AOS), isLittleEndian(LE), + IsDWO(IsDWO), UnitVector(UnitVector) { clear(); - // For split DWARF we only need to keep track of the location list section's - // data (no relocations), and if we are reading a package file, we need to - // adjust the location list data based on the index entries. if (IsDWO) { - LocSectionData = LocSection->Data; + // If we are reading a package file, we need to adjust the location list + // data based on the index entries. + StringRef Data = LocSection->Data; if (auto *IndexEntry = Header.getIndexEntry()) if (const auto *C = IndexEntry->getOffset(DW_SECT_LOC)) - LocSectionData = LocSectionData.substr(C->Offset, C->Length); + Data = Data.substr(C->Offset, C->Length); + + DWARFDataExtractor DWARFData = + Header.getVersion() >= 5 + ? DWARFDataExtractor(Context.getDWARFObj(), + Context.getDWARFObj().getLoclistsDWOSection(), + isLittleEndian, getAddressByteSize()) + : DWARFDataExtractor(Data, isLittleEndian, getAddressByteSize()); + LocTable = + std::make_unique<DWARFDebugLoclists>(DWARFData, Header.getVersion()); + + } else if (Header.getVersion() >= 5) { + LocTable = std::make_unique<DWARFDebugLoclists>( + DWARFDataExtractor(Context.getDWARFObj(), + Context.getDWARFObj().getLoclistsSection(), + isLittleEndian, getAddressByteSize()), + Header.getVersion()); + } else { + LocTable = std::make_unique<DWARFDebugLoc>( + DWARFDataExtractor(Context.getDWARFObj(), *LocSection, isLittleEndian, + getAddressByteSize())); } } @@ -209,7 +228,9 @@ DWARFUnit::getAddrOffsetSectionItem(uint32_t Index) const { if (I != R.end() && std::next(I) == R.end()) return (*I)->getAddrOffsetSectionItem(Index); } - uint64_t Offset = AddrOffsetSectionBase + Index * getAddressByteSize(); + if (!AddrOffsetSectionBase) + return None; + uint64_t Offset = *AddrOffsetSectionBase + Index * getAddressByteSize(); if (AddrOffsetSection->Data.size() < Offset + getAddressByteSize()) return None; DWARFDataExtractor DA(Context.getDWARFObj(), *AddrOffsetSection, @@ -238,23 +259,26 @@ bool DWARFUnitHeader::extract(DWARFContext &Context, const DWARFUnitIndex *Index, const DWARFUnitIndex::Entry *Entry) { Offset = *offset_ptr; + Error Err = Error::success(); IndexEntry = Entry; if (!IndexEntry && Index) IndexEntry = Index->getFromOffset(*offset_ptr); - Length = debug_info.getRelocatedValue(4, offset_ptr); + Length = debug_info.getRelocatedValue(4, offset_ptr, nullptr, &Err); FormParams.Format = DWARF32; if (Length == dwarf::DW_LENGTH_DWARF64) { - Length = debug_info.getU64(offset_ptr); + Length = debug_info.getU64(offset_ptr, &Err); FormParams.Format = DWARF64; } - FormParams.Version = debug_info.getU16(offset_ptr); + FormParams.Version = debug_info.getU16(offset_ptr, &Err); if (FormParams.Version >= 5) { - UnitType = debug_info.getU8(offset_ptr); - FormParams.AddrSize = debug_info.getU8(offset_ptr); - AbbrOffset = debug_info.getRelocatedValue(FormParams.getDwarfOffsetByteSize(), offset_ptr); + UnitType = debug_info.getU8(offset_ptr, &Err); + FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err); + AbbrOffset = debug_info.getRelocatedValue( + FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); } else { - AbbrOffset = debug_info.getRelocatedValue(FormParams.getDwarfOffsetByteSize(), offset_ptr); - FormParams.AddrSize = debug_info.getU8(offset_ptr); + AbbrOffset = debug_info.getRelocatedValue( + FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err); + FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err); // Fake a unit type based on the section type. This isn't perfect, // but distinguishing compile and type units is generally enough. if (SectionKind == DW_SECT_TYPES) @@ -274,11 +298,14 @@ bool DWARFUnitHeader::extract(DWARFContext &Context, AbbrOffset = AbbrEntry->Offset; } if (isTypeUnit()) { - TypeHash = debug_info.getU64(offset_ptr); - TypeOffset = - debug_info.getUnsigned(offset_ptr, FormParams.getDwarfOffsetByteSize()); + TypeHash = debug_info.getU64(offset_ptr, &Err); + TypeOffset = debug_info.getUnsigned( + offset_ptr, FormParams.getDwarfOffsetByteSize(), &Err); } else if (UnitType == DW_UT_split_compile || UnitType == DW_UT_skeleton) - DWOId = debug_info.getU64(offset_ptr); + DWOId = debug_info.getU64(offset_ptr, &Err); + + if (errorToBool(std::move(Err))) + return false; // Header fields all parsed, capture the size of this unit header. assert(*offset_ptr - Offset <= 255 && "unexpected header size"); @@ -305,8 +332,9 @@ bool DWARFUnitHeader::extract(DWARFContext &Context, // Parse the rangelist table header, including the optional array of offsets // following it (DWARF v5 and later). -static Expected<DWARFDebugRnglistTable> -parseRngListTableHeader(DWARFDataExtractor &DA, uint64_t Offset, +template<typename ListTableType> +static Expected<ListTableType> +parseListTableHeader(DWARFDataExtractor &DA, uint64_t Offset, DwarfFormat Format) { // We are expected to be called with Offset 0 or pointing just past the table // header. Correct Offset in the latter case so that it points to the start @@ -314,12 +342,12 @@ parseRngListTableHeader(DWARFDataExtractor &DA, uint64_t Offset, if (Offset > 0) { uint64_t HeaderSize = DWARFListTableHeader::getHeaderSize(Format); if (Offset < HeaderSize) - return createStringError(errc::invalid_argument, "Did not detect a valid" - " range list table with base = 0x%" PRIx64 "\n", + return createStringError(errc::invalid_argument, "did not detect a valid" + " list table with base = 0x%" PRIx64 "\n", Offset); Offset -= HeaderSize; } - llvm::DWARFDebugRnglistTable Table; + ListTableType Table; if (Error E = Table.extractHeaderAndOffsets(DA, &Offset)) return std::move(E); return Table; @@ -339,7 +367,8 @@ void DWARFUnit::clear() { Abbrevs = nullptr; BaseAddr.reset(); RangeSectionBase = 0; - AddrOffsetSectionBase = 0; + LocSectionBase = 0; + AddrOffsetSectionBase = None; clearDIEs(false); DWO.reset(); } @@ -427,13 +456,15 @@ Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) { if (Optional<uint64_t> DWOId = toUnsigned(UnitDie.find(DW_AT_GNU_dwo_id))) Header.setDWOId(*DWOId); if (!IsDWO) { - assert(AddrOffsetSectionBase == 0); + assert(AddrOffsetSectionBase == None); assert(RangeSectionBase == 0); - AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_addr_base), 0); + assert(LocSectionBase == 0); + AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_addr_base)); if (!AddrOffsetSectionBase) AddrOffsetSectionBase = - toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base), 0); + toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base)); RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0); + LocSectionBase = toSectionOffset(UnitDie.find(DW_AT_loclists_base), 0); } // In general, in DWARF v5 and beyond we derive the start of the unit's @@ -471,8 +502,8 @@ Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) { // extracted lazily. DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection, isLittleEndian, 0); - auto TableOrError = parseRngListTableHeader(RangesDA, RangeSectionBase, - Header.getFormat()); + auto TableOrError = parseListTableHeader<DWARFDebugRnglistTable>( + RangesDA, RangeSectionBase, Header.getFormat()); if (!TableOrError) return createStringError(errc::invalid_argument, "parsing a range list table: " + @@ -485,6 +516,37 @@ Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) { if (IsDWO && RngListTable) RangeSectionBase = RngListTable->getHeaderSize(); } + + // In a split dwarf unit, there is no DW_AT_loclists_base attribute. + // Setting LocSectionBase to point past the table header. + if (IsDWO) + setLocSection(&Context.getDWARFObj().getLoclistsDWOSection(), + DWARFListTableHeader::getHeaderSize(Header.getFormat())); + else + setLocSection(&Context.getDWARFObj().getLoclistsSection(), + toSectionOffset(UnitDie.find(DW_AT_loclists_base), 0)); + + if (LocSection->Data.size()) { + if (IsDWO) + LoclistTableHeader.emplace(".debug_loclists.dwo", "locations"); + else + LoclistTableHeader.emplace(".debug_loclists", "locations"); + + uint64_t HeaderSize = DWARFListTableHeader::getHeaderSize(Header.getFormat()); + uint64_t Offset = getLocSectionBase(); + DWARFDataExtractor Data(Context.getDWARFObj(), *LocSection, + isLittleEndian, getAddressByteSize()); + if (Offset < HeaderSize) + return createStringError(errc::invalid_argument, + "did not detect a valid" + " list table with base = 0x%" PRIx64 "\n", + Offset); + Offset -= HeaderSize; + if (Error E = LoclistTableHeader->extract(Data, &Offset)) + return createStringError(errc::invalid_argument, + "parsing a loclist table: " + + toString(std::move(E))); + } } // Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for @@ -500,7 +562,9 @@ bool DWARFUnit::parseDWO() { DWARFDie UnitDie = getUnitDIE(); if (!UnitDie) return false; - auto DWOFileName = dwarf::toString(UnitDie.find(DW_AT_GNU_dwo_name)); + auto DWOFileName = getVersion() >= 5 + ? dwarf::toString(UnitDie.find(DW_AT_dwo_name)) + : dwarf::toString(UnitDie.find(DW_AT_GNU_dwo_name)); if (!DWOFileName) return false; auto CompilationDir = dwarf::toString(UnitDie.find(DW_AT_comp_dir)); @@ -522,13 +586,14 @@ bool DWARFUnit::parseDWO() { return false; 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); + if (AddrOffsetSectionBase) + DWO->setAddrOffsetSection(AddrOffsetSection, *AddrOffsetSectionBase); if (getVersion() >= 5) { DWO->setRangesSection(&Context.getDWARFObj().getRnglistsDWOSection(), 0); DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection, isLittleEndian, 0); - if (auto TableOrError = parseRngListTableHeader(RangesDA, RangeSectionBase, - Header.getFormat())) + if (auto TableOrError = parseListTableHeader<DWARFDebugRnglistTable>( + RangesDA, RangeSectionBase, Header.getFormat())) DWO->RngListTable = TableOrError.get(); else WithColor::error() << "parsing a range list table: " @@ -575,7 +640,7 @@ DWARFUnit::findRnglistFromOffset(uint64_t Offset) { Expected<DWARFAddressRangesVector> DWARFUnit::findRnglistFromIndex(uint32_t Index) { if (auto Offset = getRnglistOffset(Index)) - return findRnglistFromOffset(*Offset + RangeSectionBase); + return findRnglistFromOffset(*Offset); if (RngListTable) return createStringError(errc::invalid_argument, @@ -599,6 +664,30 @@ Expected<DWARFAddressRangesVector> DWARFUnit::collectAddressRanges() { return *CUDIERangesOrError; } +Expected<DWARFLocationExpressionsVector> +DWARFUnit::findLoclistFromOffset(uint64_t Offset) { + DWARFLocationExpressionsVector Result; + + Error InterpretationError = Error::success(); + + Error ParseError = getLocationTable().visitAbsoluteLocationList( + Offset, getBaseAddress(), + [this](uint32_t Index) { return getAddrOffsetSectionItem(Index); }, + [&](Expected<DWARFLocationExpression> L) { + if (L) + Result.push_back(std::move(*L)); + else + InterpretationError = + joinErrors(L.takeError(), std::move(InterpretationError)); + return !InterpretationError; + }); + + if (ParseError || InterpretationError) + return joinErrors(std::move(ParseError), std::move(InterpretationError)); + + return Result; +} + void DWARFUnit::updateAddressDieMap(DWARFDie Die) { if (Die.isSubroutineDIE()) { auto DIERangesOrError = Die.getAddressRanges(); |