diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp --- a/bolt/lib/Rewrite/DWARFRewriter.cpp +++ b/bolt/lib/Rewrite/DWARFRewriter.cpp @@ -1244,8 +1244,12 @@ NeedConverted = true; uint64_t CurRangeBase = 0; - if (std::optional DWOId = Unit.getDWOId()) { - CurRangeBase = getDwoRangesBase(*DWOId); + if (Unit.isDWOUnit()) { + if (std::optional DWOId = Unit.getDWOId()) + CurRangeBase = getDwoRangesBase(*DWOId); + else + errs() << "BOLT-WARNING: [internal-dwarf-error]: DWOId is not found " + "for DWO Unit."; } if (NeedConverted || RangesAttrInfo.getForm() == dwarf::DW_FORM_rnglistx) DIEBldr.replaceValue(&Die, dwarf::DW_AT_ranges, dwarf::DW_FORM_rnglistx, @@ -1296,914 +1300,930 @@ } } -void DWARFRewriter::updateLineTableOffsets(const MCAsmLayout &Layout) { - ErrorOr DbgInfoSection = - BC.getUniqueSectionByName(".debug_info"); - ErrorOr TypeInfoSection = - BC.getUniqueSectionByName(".debug_types"); - assert(((BC.DwCtx->getNumTypeUnits() > 0 && TypeInfoSection) || - BC.DwCtx->getNumTypeUnits() == 0) && - "Was not able to retrieve Debug Types section."); - - // There is no direct connection between CU and TU, but same offsets, - // encoded in DW_AT_stmt_list, into .debug_line get modified. - // We take advantage of that to map original CU line table offsets to new - // ones. - std::unordered_map DebugLineOffsetMap; - - auto GetStatementListValue = [](DWARFUnit *Unit) { - std::optional StmtList = - Unit->getUnitDIE().find(dwarf::DW_AT_stmt_list); - std::optional Offset = dwarf::toSectionOffset(StmtList); - assert(Offset && "Was not able to retreive value of DW_AT_stmt_list."); - return *Offset; - }; - - for (const std::unique_ptr &CU : BC.DwCtx->compile_units()) { - const unsigned CUID = CU->getOffset(); - MCSymbol *Label = BC.getDwarfLineTable(CUID).getLabel(); - if (!Label) - continue; - - std::optional AttrVal = - findAttributeInfo(CU.get()->getUnitDIE(), dwarf::DW_AT_stmt_list); - if (!AttrVal) - continue; - - const uint64_t LineTableOffset = Layout.getSymbolOffset(*Label); - DebugLineOffsetMap[GetStatementListValue(CU.get())] = LineTableOffset; - assert(DbgInfoSection && ".debug_info section must exist"); - LineTablePatchMap[CU.get()] = LineTableOffset; - } - - for (const std::unique_ptr &TU : BC.DwCtx->types_section_units()) { - DWARFUnit *Unit = TU.get(); - std::optional AttrVal = - findAttributeInfo(TU.get()->getUnitDIE(), dwarf::DW_AT_stmt_list); - if (!AttrVal) - continue; - auto Iter = DebugLineOffsetMap.find(GetStatementListValue(Unit)); - assert(Iter != DebugLineOffsetMap.end() && - "Type Unit Updated Line Number Entry does not exist."); - TypeUnitRelocMap[Unit] = Iter->second; - } - - // Set .debug_info as finalized so it won't be skipped over when - // we process sections while writing out the new binary. This ensures - // that the pending relocations will be processed and not ignored. - if (DbgInfoSection) - DbgInfoSection->setIsFinalized(); - - if (TypeInfoSection) - TypeInfoSection->setIsFinalized(); -} - -CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder &DIEBlder, - DIEStreamer &Streamer) { - // update TypeUnit DW_AT_stmt_list with new .debug_line information. - for (const std::unique_ptr &TU : BC.DwCtx->types_section_units()) { - DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*TU.get()); - DIEValue StmtAttrInfo = UnitDIE->findAttribute(dwarf::DW_AT_stmt_list); - if (!StmtAttrInfo || !TypeUnitRelocMap.count(TU.get())) - continue; - DIEBlder.replaceValue(UnitDIE, dwarf::DW_AT_stmt_list, - StmtAttrInfo.getForm(), - DIEInteger(TypeUnitRelocMap[TU.get()])); - } - - // generate and populate abbrevs here - DIEBlder.generateAbbrevs(); - DIEBlder.finish(); - SmallVector OutBuffer; - std::shared_ptr ObjOS = - std::make_shared(OutBuffer); - const object::ObjectFile *File = BC.DwCtx->getDWARFObj().getFile(); - auto TheTriple = std::make_unique(File->makeTriple()); - std::unique_ptr TypeStreamer = - createDIEStreamer(*TheTriple, *ObjOS, "TypeStreamer", DIEBlder, *this); - - // generate debug_info and CUMap - CUOffsetMap CUMap; - for (std::unique_ptr &CU : BC.DwCtx->info_section_units()) { - if (!CU->isTypeUnit()) - continue; - emitUnit(DIEBlder, Streamer, *CU.get()); - uint32_t StartOffset = CUOffset; - DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU.get()); - CUOffset += CU.get()->getHeaderSize(); - CUOffset += UnitDIE->getSize(); - CUMap[CU.get()->getOffset()] = {StartOffset, CUOffset - StartOffset - 4}; - } + void DWARFRewriter::updateLineTableOffsets(const MCAsmLayout &Layout) { + ErrorOr DbgInfoSection = + BC.getUniqueSectionByName(".debug_info"); + ErrorOr TypeInfoSection = + BC.getUniqueSectionByName(".debug_types"); + assert(((BC.DwCtx->getNumTypeUnits() > 0 && TypeInfoSection) || + BC.DwCtx->getNumTypeUnits() == 0) && + "Was not able to retrieve Debug Types section."); + + // There is no direct connection between CU and TU, but same offsets, + // encoded in DW_AT_stmt_list, into .debug_line get modified. + // We take advantage of that to map original CU line table offsets to new + // ones. + std::unordered_map DebugLineOffsetMap; + + auto GetStatementListValue = [](DWARFUnit *Unit) { + std::optional StmtList = + Unit->getUnitDIE().find(dwarf::DW_AT_stmt_list); + std::optional Offset = dwarf::toSectionOffset(StmtList); + assert(Offset && "Was not able to retreive value of DW_AT_stmt_list."); + return *Offset; + }; + + for (const std::unique_ptr &CU : BC.DwCtx->compile_units()) { + const unsigned CUID = CU->getOffset(); + MCSymbol *Label = BC.getDwarfLineTable(CUID).getLabel(); + if (!Label) + continue; - // Emit Type Unit of DWARF 4 to .debug_type section - for (DWARFUnit *TU : DIEBlder.getDWARF4TUVector()) - emitUnit(DIEBlder, *TypeStreamer, *TU); + std::optional AttrVal = + findAttributeInfo(CU.get()->getUnitDIE(), dwarf::DW_AT_stmt_list); + if (!AttrVal) + continue; - TypeStreamer->finish(); + const uint64_t LineTableOffset = Layout.getSymbolOffset(*Label); + DebugLineOffsetMap[GetStatementListValue(CU.get())] = LineTableOffset; + assert(DbgInfoSection && ".debug_info section must exist"); + LineTablePatchMap[CU.get()] = LineTableOffset; + } - std::unique_ptr ObjectMemBuffer = - MemoryBuffer::getMemBuffer(ObjOS->str(), "in-memory object file", false); - std::unique_ptr Obj = cantFail( - object::ObjectFile::createObjectFile(ObjectMemBuffer->getMemBufferRef()), - "error creating in-memory object"); + for (const std::unique_ptr &TU : + BC.DwCtx->types_section_units()) { + DWARFUnit *Unit = TU.get(); + std::optional AttrVal = + findAttributeInfo(TU.get()->getUnitDIE(), dwarf::DW_AT_stmt_list); + if (!AttrVal) + continue; + auto Iter = DebugLineOffsetMap.find(GetStatementListValue(Unit)); + assert(Iter != DebugLineOffsetMap.end() && + "Type Unit Updated Line Number Entry does not exist."); + TypeUnitRelocMap[Unit] = Iter->second; + } - for (const SectionRef &Section : Obj->sections()) { - StringRef Contents = cantFail(Section.getContents()); - StringRef Name = cantFail(Section.getName()); - if (Name.equals(".debug_types")) - BC.registerOrUpdateNoteSection(".debug_types", copyByteArray(Contents), - Contents.size()); - } - return CUMap; -} + // Set .debug_info as finalized so it won't be skipped over when + // we process sections while writing out the new binary. This ensures + // that the pending relocations will be processed and not ignored. + if (DbgInfoSection) + DbgInfoSection->setIsFinalized(); -void DWARFRewriter::finalizeDebugSections(DIEBuilder &DIEBlder, - DIEStreamer &Streamer, - raw_svector_ostream &ObjOS, - CUOffsetMap &CUMap) { - if (StrWriter->isInitialized()) { - RewriteInstance::addToDebugSectionsToOverwrite(".debug_str"); - std::unique_ptr DebugStrSectionContents = - StrWriter->releaseBuffer(); - BC.registerOrUpdateNoteSection(".debug_str", - copyByteArray(*DebugStrSectionContents), - DebugStrSectionContents->size()); + if (TypeInfoSection) + TypeInfoSection->setIsFinalized(); } - if (StrOffstsWriter->isFinalized()) { - RewriteInstance::addToDebugSectionsToOverwrite(".debug_str_offsets"); - std::unique_ptr - DebugStrOffsetsSectionContents = StrOffstsWriter->releaseBuffer(); - BC.registerOrUpdateNoteSection( - ".debug_str_offsets", copyByteArray(*DebugStrOffsetsSectionContents), - DebugStrOffsetsSectionContents->size()); - } + CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder & DIEBlder, + DIEStreamer & Streamer) { + // update TypeUnit DW_AT_stmt_list with new .debug_line information. + for (const std::unique_ptr &TU : + BC.DwCtx->types_section_units()) { + DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*TU.get()); + DIEValue StmtAttrInfo = UnitDIE->findAttribute(dwarf::DW_AT_stmt_list); + if (!StmtAttrInfo || !TypeUnitRelocMap.count(TU.get())) + continue; + DIEBlder.replaceValue(UnitDIE, dwarf::DW_AT_stmt_list, + StmtAttrInfo.getForm(), + DIEInteger(TypeUnitRelocMap[TU.get()])); + } - if (BC.isDWARFLegacyUsed()) { - std::unique_ptr RangesSectionContents = - LegacyRangesSectionWriter->releaseBuffer(); - BC.registerOrUpdateNoteSection(".debug_ranges", - copyByteArray(*RangesSectionContents), - RangesSectionContents->size()); - } + // generate and populate abbrevs here + DIEBlder.generateAbbrevs(); + DIEBlder.finish(); + SmallVector OutBuffer; + std::shared_ptr ObjOS = + std::make_shared(OutBuffer); + const object::ObjectFile *File = BC.DwCtx->getDWARFObj().getFile(); + auto TheTriple = std::make_unique(File->makeTriple()); + std::unique_ptr TypeStreamer = + createDIEStreamer(*TheTriple, *ObjOS, "TypeStreamer", DIEBlder, *this); + + // generate debug_info and CUMap + CUOffsetMap CUMap; + for (std::unique_ptr &CU : + BC.DwCtx->info_section_units()) { + if (!CU->isTypeUnit()) + continue; + emitUnit(DIEBlder, Streamer, *CU.get()); + uint32_t StartOffset = CUOffset; + DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU.get()); + CUOffset += CU.get()->getHeaderSize(); + CUOffset += UnitDIE->getSize(); + CUMap[CU.get()->getOffset()] = {StartOffset, CUOffset - StartOffset - 4}; + } - if (BC.isDWARF5Used()) { - std::unique_ptr RangesSectionContents = - RangeListsSectionWriter->releaseBuffer(); - BC.registerOrUpdateNoteSection(".debug_rnglists", - copyByteArray(*RangesSectionContents), - RangesSectionContents->size()); - } + // Emit Type Unit of DWARF 4 to .debug_type section + for (DWARFUnit *TU : DIEBlder.getDWARF4TUVector()) + emitUnit(DIEBlder, *TypeStreamer, *TU); + + TypeStreamer->finish(); + + std::unique_ptr ObjectMemBuffer = MemoryBuffer::getMemBuffer( + ObjOS->str(), "in-memory object file", false); + std::unique_ptr Obj = + cantFail(object::ObjectFile::createObjectFile( + ObjectMemBuffer->getMemBufferRef()), + "error creating in-memory object"); + + for (const SectionRef &Section : Obj->sections()) { + StringRef Contents = cantFail(Section.getContents()); + StringRef Name = cantFail(Section.getName()); + if (Name.equals(".debug_types")) + BC.registerOrUpdateNoteSection(".debug_types", copyByteArray(Contents), + Contents.size()); + } + return CUMap; + } + + void DWARFRewriter::finalizeDebugSections( + DIEBuilder & DIEBlder, DIEStreamer & Streamer, + raw_svector_ostream & ObjOS, CUOffsetMap & CUMap) { + if (StrWriter->isInitialized()) { + RewriteInstance::addToDebugSectionsToOverwrite(".debug_str"); + std::unique_ptr DebugStrSectionContents = + StrWriter->releaseBuffer(); + BC.registerOrUpdateNoteSection(".debug_str", + copyByteArray(*DebugStrSectionContents), + DebugStrSectionContents->size()); + } - if (BC.isDWARF5Used()) { - std::unique_ptr LocationListSectionContents = - makeFinalLocListsSection(DWARFVersion::DWARF5); - if (!LocationListSectionContents->empty()) + if (StrOffstsWriter->isFinalized()) { + RewriteInstance::addToDebugSectionsToOverwrite(".debug_str_offsets"); + std::unique_ptr + DebugStrOffsetsSectionContents = StrOffstsWriter->releaseBuffer(); BC.registerOrUpdateNoteSection( - ".debug_loclists", copyByteArray(*LocationListSectionContents), - LocationListSectionContents->size()); - } + ".debug_str_offsets", copyByteArray(*DebugStrOffsetsSectionContents), + DebugStrOffsetsSectionContents->size()); + } - if (BC.isDWARFLegacyUsed()) { - std::unique_ptr LocationListSectionContents = - makeFinalLocListsSection(DWARFVersion::DWARFLegacy); - if (!LocationListSectionContents->empty()) - BC.registerOrUpdateNoteSection( - ".debug_loc", copyByteArray(*LocationListSectionContents), - LocationListSectionContents->size()); - } + if (BC.isDWARFLegacyUsed()) { + std::unique_ptr RangesSectionContents = + LegacyRangesSectionWriter->releaseBuffer(); + BC.registerOrUpdateNoteSection(".debug_ranges", + copyByteArray(*RangesSectionContents), + RangesSectionContents->size()); + } - // AddrWriter should be finalized after debug_loc since more addresses can be - // added there. - if (AddrWriter->isInitialized()) { - AddressSectionBuffer AddressSectionContents = AddrWriter->finalize(); - BC.registerOrUpdateNoteSection(".debug_addr", - copyByteArray(AddressSectionContents), - AddressSectionContents.size()); - } + if (BC.isDWARF5Used()) { + std::unique_ptr RangesSectionContents = + RangeListsSectionWriter->releaseBuffer(); + BC.registerOrUpdateNoteSection(".debug_rnglists", + copyByteArray(*RangesSectionContents), + RangesSectionContents->size()); + } - Streamer.emitAbbrevs(DIEBlder.getAbbrevs(), BC.DwCtx->getMaxVersion()); - Streamer.finish(); + if (BC.isDWARF5Used()) { + std::unique_ptr LocationListSectionContents = + makeFinalLocListsSection(DWARFVersion::DWARF5); + if (!LocationListSectionContents->empty()) + BC.registerOrUpdateNoteSection( + ".debug_loclists", copyByteArray(*LocationListSectionContents), + LocationListSectionContents->size()); + } - std::unique_ptr ObjectMemBuffer = - MemoryBuffer::getMemBuffer(ObjOS.str(), "in-memory object file", false); - std::unique_ptr Obj = cantFail( - object::ObjectFile::createObjectFile(ObjectMemBuffer->getMemBufferRef()), - "error creating in-memory object"); + if (BC.isDWARFLegacyUsed()) { + std::unique_ptr LocationListSectionContents = + makeFinalLocListsSection(DWARFVersion::DWARFLegacy); + if (!LocationListSectionContents->empty()) + BC.registerOrUpdateNoteSection( + ".debug_loc", copyByteArray(*LocationListSectionContents), + LocationListSectionContents->size()); + } - for (const SectionRef &Secs : Obj->sections()) { - StringRef Contents = cantFail(Secs.getContents()); - StringRef Name = cantFail(Secs.getName()); - if (Name.equals(".debug_abbrev")) { - BC.registerOrUpdateNoteSection(".debug_abbrev", copyByteArray(Contents), - Contents.size()); - } else if (Name.equals(".debug_info")) { - BC.registerOrUpdateNoteSection(".debug_info", copyByteArray(Contents), - Contents.size()); + // AddrWriter should be finalized after debug_loc since more addresses can + // be added there. + if (AddrWriter->isInitialized()) { + AddressSectionBuffer AddressSectionContents = AddrWriter->finalize(); + BC.registerOrUpdateNoteSection(".debug_addr", + copyByteArray(AddressSectionContents), + AddressSectionContents.size()); } - } - // Skip .debug_aranges if we are re-generating .gdb_index. - if (opts::KeepARanges || !BC.getGdbIndexSection()) { - SmallVector ARangesBuffer; - raw_svector_ostream OS(ARangesBuffer); + Streamer.emitAbbrevs(DIEBlder.getAbbrevs(), BC.DwCtx->getMaxVersion()); + Streamer.finish(); + + std::unique_ptr ObjectMemBuffer = + MemoryBuffer::getMemBuffer(ObjOS.str(), "in-memory object file", false); + std::unique_ptr Obj = + cantFail(object::ObjectFile::createObjectFile( + ObjectMemBuffer->getMemBufferRef()), + "error creating in-memory object"); + + for (const SectionRef &Secs : Obj->sections()) { + StringRef Contents = cantFail(Secs.getContents()); + StringRef Name = cantFail(Secs.getName()); + if (Name.equals(".debug_abbrev")) { + BC.registerOrUpdateNoteSection(".debug_abbrev", copyByteArray(Contents), + Contents.size()); + } else if (Name.equals(".debug_info")) { + BC.registerOrUpdateNoteSection(".debug_info", copyByteArray(Contents), + Contents.size()); + } + } - auto MAB = std::unique_ptr( - BC.TheTarget->createMCAsmBackend(*BC.STI, *BC.MRI, MCTargetOptions())); + // Skip .debug_aranges if we are re-generating .gdb_index. + if (opts::KeepARanges || !BC.getGdbIndexSection()) { + SmallVector ARangesBuffer; + raw_svector_ostream OS(ARangesBuffer); - ARangesSectionWriter->writeARangesSection(OS, CUMap); - const StringRef &ARangesContents = OS.str(); + auto MAB = std::unique_ptr(BC.TheTarget->createMCAsmBackend( + *BC.STI, *BC.MRI, MCTargetOptions())); - BC.registerOrUpdateNoteSection(".debug_aranges", - copyByteArray(ARangesContents), - ARangesContents.size()); - } -} + ARangesSectionWriter->writeARangesSection(OS, CUMap); + const StringRef &ARangesContents = OS.str(); -void DWARFRewriter::finalizeCompileUnits(DIEBuilder &DIEBlder, - DIEStreamer &Streamer, - CUOffsetMap &CUMap, - const std::list &CUs) { - DIEBlder.generateAbbrevs(); - DIEBlder.finish(); - // generate debug_info and CUMap - for (DWARFUnit *CU : CUs) { - emitUnit(DIEBlder, Streamer, *CU); - const uint32_t StartOffset = CUOffset; - DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU); - CUOffset += CU->getHeaderSize(); - CUOffset += UnitDIE->getSize(); - CUMap[CU->getOffset()] = {StartOffset, CUOffset - StartOffset - 4}; + BC.registerOrUpdateNoteSection(".debug_aranges", + copyByteArray(ARangesContents), + ARangesContents.size()); + } } -} - -// Creates all the data structures necessary for creating MCStreamer. -// They are passed by reference because they need to be kept around. -// Also creates known debug sections. These are sections handled by -// handleDebugDataPatching. -namespace { - -std::unique_ptr -createDwarfOnlyBC(const object::ObjectFile &File) { - return cantFail(BinaryContext::createBinaryContext( - &File, false, - DWARFContext::create(File, DWARFContext::ProcessDebugRelocations::Ignore, - nullptr, "", WithColor::defaultErrorHandler, - WithColor::defaultWarningHandler))); -} - -StringMap -createKnownSectionsMap(const MCObjectFileInfo &MCOFI) { - StringMap KnownSectionsTemp = { - {"debug_info.dwo", {MCOFI.getDwarfInfoDWOSection(), DW_SECT_INFO}}, - {"debug_types.dwo", {MCOFI.getDwarfTypesDWOSection(), DW_SECT_EXT_TYPES}}, - {"debug_str_offsets.dwo", - {MCOFI.getDwarfStrOffDWOSection(), DW_SECT_STR_OFFSETS}}, - {"debug_str.dwo", {MCOFI.getDwarfStrDWOSection(), DW_SECT_EXT_unknown}}, - {"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_EXT_LOC}}, - {"debug_abbrev.dwo", {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}}, - {"debug_line.dwo", {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}}, - {"debug_loclists.dwo", - {MCOFI.getDwarfLoclistsDWOSection(), DW_SECT_LOCLISTS}}, - {"debug_rnglists.dwo", - {MCOFI.getDwarfRnglistsDWOSection(), DW_SECT_RNGLISTS}}}; - return KnownSectionsTemp; -} - -StringRef getSectionName(const SectionRef &Section) { - Expected SectionName = Section.getName(); - assert(SectionName && "Invalid section name."); - StringRef Name = *SectionName; - Name = Name.substr(Name.find_first_not_of("._")); - return Name; -} - -// Exctracts an appropriate slice if input is DWP. -// Applies patches or overwrites the section. -std::optional updateDebugData( - DWARFContext &DWCtx, StringRef SectionName, StringRef SectionContents, - const StringMap &KnownSections, - MCStreamer &Streamer, DWARFRewriter &Writer, - const DWARFUnitIndex::Entry *CUDWOEntry, uint64_t DWOId, - std::unique_ptr &OutputBuffer, - DebugRangeListsSectionWriter *RangeListsWriter, DebugLocWriter &LocWriter, - const llvm::bolt::DWARFRewriter::OverriddenSectionsMap &OverridenSections) { - - using DWOSectionContribution = - const DWARFUnitIndex::Entry::SectionContribution; - auto getSliceData = [&](const DWARFUnitIndex::Entry *DWOEntry, - StringRef OutData, DWARFSectionKind Sec, - uint64_t &DWPOffset) -> StringRef { - if (DWOEntry) { - DWOSectionContribution *DWOContrubution = DWOEntry->getContribution(Sec); - DWPOffset = DWOContrubution->getOffset(); - OutData = OutData.substr(DWPOffset, DWOContrubution->getLength()); - } - return OutData; - }; - - auto SectionIter = KnownSections.find(SectionName); - if (SectionIter == KnownSections.end()) - return std::nullopt; - Streamer.switchSection(SectionIter->second.first); - uint64_t DWPOffset = 0; - auto getOverridenSection = - [&](DWARFSectionKind Kind) -> std::optional { - auto Iter = OverridenSections.find(Kind); - if (Iter == OverridenSections.end()) { - errs() - << "BOLT-WARNING: [internal-dwarf-error]: Could not find overriden " - "section for: " - << Twine::utohexstr(DWOId) << ".\n"; - return std::nullopt; + void DWARFRewriter::finalizeCompileUnits( + DIEBuilder & DIEBlder, DIEStreamer & Streamer, CUOffsetMap & CUMap, + const std::list &CUs) { + DIEBlder.generateAbbrevs(); + DIEBlder.finish(); + // generate debug_info and CUMap + for (DWARFUnit *CU : CUs) { + emitUnit(DIEBlder, Streamer, *CU); + const uint32_t StartOffset = CUOffset; + DIE *UnitDIE = DIEBlder.getUnitDIEbyUnit(*CU); + CUOffset += CU->getHeaderSize(); + CUOffset += UnitDIE->getSize(); + CUMap[CU->getOffset()] = {StartOffset, CUOffset - StartOffset - 4}; } - return Iter->second; - }; - switch (SectionIter->second.second) { - default: { - if (!SectionName.equals("debug_str.dwo")) - errs() << "BOLT-WARNING: unsupported debug section: " << SectionName - << "\n"; - return SectionContents; - } - case DWARFSectionKind::DW_SECT_INFO: { - return getOverridenSection(DWARFSectionKind::DW_SECT_INFO); - } - case DWARFSectionKind::DW_SECT_EXT_TYPES: { - return getOverridenSection(DWARFSectionKind::DW_SECT_EXT_TYPES); } - case DWARFSectionKind::DW_SECT_STR_OFFSETS: { - return getSliceData(CUDWOEntry, SectionContents, - DWARFSectionKind::DW_SECT_STR_OFFSETS, DWPOffset); - } - case DWARFSectionKind::DW_SECT_ABBREV: { - return getOverridenSection(DWARFSectionKind::DW_SECT_ABBREV); - } - case DWARFSectionKind::DW_SECT_EXT_LOC: - case DWARFSectionKind::DW_SECT_LOCLISTS: { - OutputBuffer = LocWriter.getBuffer(); - // Creating explicit StringRef here, otherwise - // with impicit conversion it will take null byte as end of - // string. - return StringRef(reinterpret_cast(OutputBuffer->data()), - OutputBuffer->size()); - } - case DWARFSectionKind::DW_SECT_LINE: { - return getSliceData(CUDWOEntry, SectionContents, - DWARFSectionKind::DW_SECT_LINE, DWPOffset); - } - case DWARFSectionKind::DW_SECT_RNGLISTS: { - assert(RangeListsWriter && "RangeListsWriter was not created."); - OutputBuffer = RangeListsWriter->releaseBuffer(); - return StringRef(reinterpret_cast(OutputBuffer->data()), - OutputBuffer->size()); - } - } -} -} // namespace + // Creates all the data structures necessary for creating MCStreamer. + // They are passed by reference because they need to be kept around. + // Also creates known debug sections. These are sections handled by + // handleDebugDataPatching. + namespace { + + std::unique_ptr + createDwarfOnlyBC(const object::ObjectFile &File) { + return cantFail(BinaryContext::createBinaryContext( + &File, false, + DWARFContext::create( + File, DWARFContext::ProcessDebugRelocations::Ignore, nullptr, "", + WithColor::defaultErrorHandler, WithColor::defaultWarningHandler))); + } + + StringMap + createKnownSectionsMap(const MCObjectFileInfo &MCOFI) { + StringMap KnownSectionsTemp = { + {"debug_info.dwo", {MCOFI.getDwarfInfoDWOSection(), DW_SECT_INFO}}, + {"debug_types.dwo", + {MCOFI.getDwarfTypesDWOSection(), DW_SECT_EXT_TYPES}}, + {"debug_str_offsets.dwo", + {MCOFI.getDwarfStrOffDWOSection(), DW_SECT_STR_OFFSETS}}, + {"debug_str.dwo", {MCOFI.getDwarfStrDWOSection(), DW_SECT_EXT_unknown}}, + {"debug_loc.dwo", {MCOFI.getDwarfLocDWOSection(), DW_SECT_EXT_LOC}}, + {"debug_abbrev.dwo", + {MCOFI.getDwarfAbbrevDWOSection(), DW_SECT_ABBREV}}, + {"debug_line.dwo", {MCOFI.getDwarfLineDWOSection(), DW_SECT_LINE}}, + {"debug_loclists.dwo", + {MCOFI.getDwarfLoclistsDWOSection(), DW_SECT_LOCLISTS}}, + {"debug_rnglists.dwo", + {MCOFI.getDwarfRnglistsDWOSection(), DW_SECT_RNGLISTS}}}; + return KnownSectionsTemp; + } + + StringRef getSectionName(const SectionRef &Section) { + Expected SectionName = Section.getName(); + assert(SectionName && "Invalid section name."); + StringRef Name = *SectionName; + Name = Name.substr(Name.find_first_not_of("._")); + return Name; + } + + // Exctracts an appropriate slice if input is DWP. + // Applies patches or overwrites the section. + std::optional updateDebugData( + DWARFContext &DWCtx, StringRef SectionName, StringRef SectionContents, + const StringMap &KnownSections, + MCStreamer &Streamer, DWARFRewriter &Writer, + const DWARFUnitIndex::Entry *CUDWOEntry, uint64_t DWOId, + std::unique_ptr &OutputBuffer, + DebugRangeListsSectionWriter *RangeListsWriter, DebugLocWriter &LocWriter, + const llvm::bolt::DWARFRewriter::OverriddenSectionsMap + &OverridenSections) { + + using DWOSectionContribution = + const DWARFUnitIndex::Entry::SectionContribution; + auto getSliceData = [&](const DWARFUnitIndex::Entry *DWOEntry, + StringRef OutData, DWARFSectionKind Sec, + uint64_t &DWPOffset) -> StringRef { + if (DWOEntry) { + DWOSectionContribution *DWOContrubution = + DWOEntry->getContribution(Sec); + DWPOffset = DWOContrubution->getOffset(); + OutData = OutData.substr(DWPOffset, DWOContrubution->getLength()); + } + return OutData; + }; -void DWARFRewriter::initDWPState(DWPState &State) { - SmallString<0> OutputNameStr; - StringRef OutputName; - if (opts::DwarfOutputPath.empty()) { - OutputName = - Twine(opts::OutputFilename).concat(".dwp").toStringRef(OutputNameStr); - } else { - StringRef ExeFileName = llvm::sys::path::filename(opts::OutputFilename); - OutputName = Twine(opts::DwarfOutputPath) - .concat("/") - .concat(ExeFileName) - .concat(".dwp") - .toStringRef(OutputNameStr); - errs() << "BOLT-WARNING: dwarf-output-path is in effect and .dwp file will " - "possibly be written to another location that is not the same as " - "the executable\n"; + auto SectionIter = KnownSections.find(SectionName); + if (SectionIter == KnownSections.end()) + return std::nullopt; + Streamer.switchSection(SectionIter->second.first); + uint64_t DWPOffset = 0; + + auto getOverridenSection = + [&](DWARFSectionKind Kind) -> std::optional { + auto Iter = OverridenSections.find(Kind); + if (Iter == OverridenSections.end()) { + errs() + << "BOLT-WARNING: [internal-dwarf-error]: Could not find overriden " + "section for: " + << Twine::utohexstr(DWOId) << ".\n"; + return std::nullopt; + } + return Iter->second; + }; + switch (SectionIter->second.second) { + default: { + if (!SectionName.equals("debug_str.dwo")) + errs() << "BOLT-WARNING: unsupported debug section: " << SectionName + << "\n"; + return SectionContents; + } + case DWARFSectionKind::DW_SECT_INFO: { + return getOverridenSection(DWARFSectionKind::DW_SECT_INFO); + } + case DWARFSectionKind::DW_SECT_EXT_TYPES: { + return getOverridenSection(DWARFSectionKind::DW_SECT_EXT_TYPES); + } + case DWARFSectionKind::DW_SECT_STR_OFFSETS: { + return getSliceData(CUDWOEntry, SectionContents, + DWARFSectionKind::DW_SECT_STR_OFFSETS, DWPOffset); + } + case DWARFSectionKind::DW_SECT_ABBREV: { + return getOverridenSection(DWARFSectionKind::DW_SECT_ABBREV); + } + case DWARFSectionKind::DW_SECT_EXT_LOC: + case DWARFSectionKind::DW_SECT_LOCLISTS: { + OutputBuffer = LocWriter.getBuffer(); + // Creating explicit StringRef here, otherwise + // with impicit conversion it will take null byte as end of + // string. + return StringRef(reinterpret_cast(OutputBuffer->data()), + OutputBuffer->size()); + } + case DWARFSectionKind::DW_SECT_LINE: { + return getSliceData(CUDWOEntry, SectionContents, + DWARFSectionKind::DW_SECT_LINE, DWPOffset); + } + case DWARFSectionKind::DW_SECT_RNGLISTS: { + assert(RangeListsWriter && "RangeListsWriter was not created."); + OutputBuffer = RangeListsWriter->releaseBuffer(); + return StringRef(reinterpret_cast(OutputBuffer->data()), + OutputBuffer->size()); + } + } } - std::error_code EC; - State.Out = - std::make_unique(OutputName, EC, sys::fs::OF_None); - const object::ObjectFile *File = BC.DwCtx->getDWARFObj().getFile(); - State.TmpBC = createDwarfOnlyBC(*File); - State.Streamer = State.TmpBC->createStreamer(State.Out->os()); - State.MCOFI = State.Streamer->getContext().getObjectFileInfo(); - State.KnownSections = createKnownSectionsMap(*State.MCOFI); - MCSection *const StrSection = State.MCOFI->getDwarfStrDWOSection(); - - // Data Structures for DWP book keeping - // Size of array corresponds to the number of sections supported by DWO format - // in DWARF4/5. - - State.Strings = std::make_unique(*State.Streamer, StrSection); - // Setup DWP code once. - DWARFContext *DWOCtx = BC.getDWOContext(); - - if (DWOCtx) { - State.CUIndex = &DWOCtx->getCUIndex(); - State.IsDWP = !State.CUIndex->getRows().empty(); - } -} + } // namespace -void DWARFRewriter::finalizeDWP(DWPState &State) { - if (State.Version < 5) { - // Lie about there being no info contributions so the TU index only includes - // the type unit contribution for DWARF < 5. In DWARFv5 the TU index has a - // contribution to the info section, so we do not want to lie about it. - State.ContributionOffsets[0] = 0; - } - writeIndex(*State.Streamer.get(), State.MCOFI->getDwarfTUIndexSection(), - State.ContributionOffsets, State.TypeIndexEntries, - State.IndexVersion); - - if (State.Version < 5) { - // Lie about the type contribution for DWARF < 5. In DWARFv5 the type - // section does not exist, so no need to do anything about this. - State.ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES, 2)] = 0; - // Unlie about the info contribution - State.ContributionOffsets[0] = 1; + void DWARFRewriter::initDWPState(DWPState & State) { + SmallString<0> OutputNameStr; + StringRef OutputName; + if (opts::DwarfOutputPath.empty()) { + OutputName = + Twine(opts::OutputFilename).concat(".dwp").toStringRef(OutputNameStr); + } else { + StringRef ExeFileName = llvm::sys::path::filename(opts::OutputFilename); + OutputName = Twine(opts::DwarfOutputPath) + .concat("/") + .concat(ExeFileName) + .concat(".dwp") + .toStringRef(OutputNameStr); + errs() + << "BOLT-WARNING: dwarf-output-path is in effect and .dwp file will " + "possibly be written to another location that is not the same as " + "the executable\n"; + } + std::error_code EC; + State.Out = + std::make_unique(OutputName, EC, sys::fs::OF_None); + const object::ObjectFile *File = BC.DwCtx->getDWARFObj().getFile(); + State.TmpBC = createDwarfOnlyBC(*File); + State.Streamer = State.TmpBC->createStreamer(State.Out->os()); + State.MCOFI = State.Streamer->getContext().getObjectFileInfo(); + State.KnownSections = createKnownSectionsMap(*State.MCOFI); + MCSection *const StrSection = State.MCOFI->getDwarfStrDWOSection(); + + // Data Structures for DWP book keeping + // Size of array corresponds to the number of sections supported by DWO + // format in DWARF4/5. + + State.Strings = + std::make_unique(*State.Streamer, StrSection); + + // Setup DWP code once. + DWARFContext *DWOCtx = BC.getDWOContext(); + + if (DWOCtx) { + State.CUIndex = &DWOCtx->getCUIndex(); + State.IsDWP = !State.CUIndex->getRows().empty(); + } } - writeIndex(*State.Streamer.get(), State.MCOFI->getDwarfCUIndexSection(), - State.ContributionOffsets, State.IndexEntries, State.IndexVersion); - - State.Streamer->finish(); - State.Out->keep(); -} -void DWARFRewriter::updateDWP(DWARFUnit &CU, - const OverriddenSectionsMap &OverridenSections, - const DWARFRewriter::UnitMeta &CUMI, - DWARFRewriter::UnitMetaVectorType &TUMetaVector, - DWPState &State, DebugLocWriter &LocWriter) { - const uint64_t DWOId = *CU.getDWOId(); - MCSection *const StrOffsetSection = State.MCOFI->getDwarfStrOffDWOSection(); - assert(StrOffsetSection && "StrOffsetSection does not exist."); - // Skipping CUs that we failed to load. - std::optional DWOCU = BC.getDWOCU(DWOId); - if (!DWOCU) - return; - - if (State.Version == 0) { - State.Version = CU.getVersion(); - State.IndexVersion = State.Version < 5 ? 2 : 5; - } else if (State.Version != CU.getVersion()) { - errs() << "BOLT-ERROR: incompatible DWARF compile unit versions\n"; - exit(1); - } + void DWARFRewriter::finalizeDWP(DWPState & State) { + if (State.Version < 5) { + // Lie about there being no info contributions so the TU index only + // includes the type unit contribution for DWARF < 5. In DWARFv5 the TU + // index has a contribution to the info section, so we do not want to lie + // about it. + State.ContributionOffsets[0] = 0; + } + writeIndex(*State.Streamer.get(), State.MCOFI->getDwarfTUIndexSection(), + State.ContributionOffsets, State.TypeIndexEntries, + State.IndexVersion); + + if (State.Version < 5) { + // Lie about the type contribution for DWARF < 5. In DWARFv5 the type + // section does not exist, so no need to do anything about this. + State.ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES, 2)] = 0; + // Unlie about the info contribution + State.ContributionOffsets[0] = 1; + } + writeIndex(*State.Streamer.get(), State.MCOFI->getDwarfCUIndexSection(), + State.ContributionOffsets, State.IndexEntries, + State.IndexVersion); + + State.Streamer->finish(); + State.Out->keep(); + } + + void DWARFRewriter::updateDWP(DWARFUnit & CU, + const OverriddenSectionsMap &OverridenSections, + const DWARFRewriter::UnitMeta &CUMI, + DWARFRewriter::UnitMetaVectorType &TUMetaVector, + DWPState &State, DebugLocWriter &LocWriter) { + const uint64_t DWOId = *CU.getDWOId(); + MCSection *const StrOffsetSection = State.MCOFI->getDwarfStrOffDWOSection(); + assert(StrOffsetSection && "StrOffsetSection does not exist."); + // Skipping CUs that we failed to load. + std::optional DWOCU = BC.getDWOCU(DWOId); + if (!DWOCU) + return; - UnitIndexEntry CurEntry = {}; - CurEntry.DWOName = dwarf::toString( - CU.getUnitDIE().find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), - ""); - const char *Name = CU.getUnitDIE().getShortName(); - if (Name) - CurEntry.Name = Name; - StringRef CurStrSection; - StringRef CurStrOffsetSection; - - // This maps each section contained in this file to its length. - // This information is later on used to calculate the contributions, - // i.e. offset and length, of each compile/type unit to a section. - std::vector> SectionLength; - - const DWARFUnitIndex::Entry *CUDWOEntry = nullptr; - if (State.IsDWP) - CUDWOEntry = State.CUIndex->getFromHash(DWOId); - - bool StrSectionWrittenOut = false; - const object::ObjectFile *DWOFile = - (*DWOCU)->getContext().getDWARFObj().getFile(); - - DebugRangeListsSectionWriter *RangeListssWriter = nullptr; - if (CU.getVersion() == 5) { - assert(RangeListsWritersByCU.count(DWOId) != 0 && - "No RangeListsWriter for DWO ID."); - RangeListssWriter = RangeListsWritersByCU[DWOId].get(); - } - auto AddType = [&](unsigned int Index, uint32_t IndexVersion, uint64_t Offset, - uint64_t Length, uint64_t Hash) -> void { - UnitIndexEntry TUEntry = CurEntry; - if (IndexVersion < 5) - TUEntry.Contributions[0] = {}; - TUEntry.Contributions[Index].setOffset(Offset); - TUEntry.Contributions[Index].setLength(Length); - State.ContributionOffsets[Index] += - TUEntry.Contributions[Index].getLength32(); - State.TypeIndexEntries.insert(std::make_pair(Hash, TUEntry)); - }; - for (const SectionRef &Section : DWOFile->sections()) { - std::unique_ptr OutputData; - StringRef SectionName = getSectionName(Section); - Expected ContentsExp = Section.getContents(); - assert(ContentsExp && "Invalid contents."); - std::optional TOutData = updateDebugData( - (*DWOCU)->getContext(), SectionName, *ContentsExp, State.KnownSections, - *State.Streamer, *this, CUDWOEntry, DWOId, OutputData, - RangeListssWriter, LocWriter, OverridenSections); - if (!TOutData) - continue; + if (State.Version == 0) { + State.Version = CU.getVersion(); + State.IndexVersion = State.Version < 5 ? 2 : 5; + } else if (State.Version != CU.getVersion()) { + errs() << "BOLT-ERROR: incompatible DWARF compile unit versions\n"; + exit(1); + } - StringRef OutData = *TOutData; - if (SectionName == "debug_types.dwo") { - State.Streamer->emitBytes(OutData); - continue; + UnitIndexEntry CurEntry = {}; + CurEntry.DWOName = + dwarf::toString(CU.getUnitDIE().find( + {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), + ""); + const char *Name = CU.getUnitDIE().getShortName(); + if (Name) + CurEntry.Name = Name; + StringRef CurStrSection; + StringRef CurStrOffsetSection; + + // This maps each section contained in this file to its length. + // This information is later on used to calculate the contributions, + // i.e. offset and length, of each compile/type unit to a section. + std::vector> SectionLength; + + const DWARFUnitIndex::Entry *CUDWOEntry = nullptr; + if (State.IsDWP) + CUDWOEntry = State.CUIndex->getFromHash(DWOId); + + bool StrSectionWrittenOut = false; + const object::ObjectFile *DWOFile = + (*DWOCU)->getContext().getDWARFObj().getFile(); + + DebugRangeListsSectionWriter *RangeListssWriter = nullptr; + if (CU.getVersion() == 5) { + assert(RangeListsWritersByCU.count(DWOId) != 0 && + "No RangeListsWriter for DWO ID."); + RangeListssWriter = RangeListsWritersByCU[DWOId].get(); } + auto AddType = [&](unsigned int Index, uint32_t IndexVersion, + uint64_t Offset, uint64_t Length, + uint64_t Hash) -> void { + UnitIndexEntry TUEntry = CurEntry; + if (IndexVersion < 5) + TUEntry.Contributions[0] = {}; + TUEntry.Contributions[Index].setOffset(Offset); + TUEntry.Contributions[Index].setLength(Length); + State.ContributionOffsets[Index] += + TUEntry.Contributions[Index].getLength32(); + State.TypeIndexEntries.insert(std::make_pair(Hash, TUEntry)); + }; + for (const SectionRef &Section : DWOFile->sections()) { + std::unique_ptr OutputData; + StringRef SectionName = getSectionName(Section); + Expected ContentsExp = Section.getContents(); + assert(ContentsExp && "Invalid contents."); + std::optional TOutData = updateDebugData( + (*DWOCU)->getContext(), SectionName, *ContentsExp, + State.KnownSections, *State.Streamer, *this, CUDWOEntry, DWOId, + OutputData, RangeListssWriter, LocWriter, OverridenSections); + if (!TOutData) + continue; - if (SectionName.equals("debug_str.dwo")) { - CurStrSection = OutData; - } else { - // Since handleDebugDataPatching returned true, we already know this is - // a known section. - auto SectionIter = State.KnownSections.find(SectionName); - if (SectionIter->second.second == DWARFSectionKind::DW_SECT_STR_OFFSETS) - CurStrOffsetSection = OutData; - else + StringRef OutData = *TOutData; + if (SectionName == "debug_types.dwo") { State.Streamer->emitBytes(OutData); - unsigned int Index = - getContributionIndex(SectionIter->second.second, State.IndexVersion); - uint64_t Offset = State.ContributionOffsets[Index]; - uint64_t Length = OutData.size(); - if (CU.getVersion() >= 5 && - SectionIter->second.second == DWARFSectionKind::DW_SECT_INFO) { - for (UnitMeta &MI : TUMetaVector) - MI.Offset += State.DebugInfoSize; - - Offset = State.DebugInfoSize + CUMI.Offset; - Length = CUMI.Length; - State.DebugInfoSize += OutData.size(); + continue; } - CurEntry.Contributions[Index].setOffset(Offset); - CurEntry.Contributions[Index].setLength(Length); - State.ContributionOffsets[Index] += - CurEntry.Contributions[Index].getLength32(); - } - // Strings are combined in to a new string section, and de-duplicated - // based on hash. - if (!StrSectionWrittenOut && !CurStrOffsetSection.empty() && - !CurStrSection.empty()) { - writeStringsAndOffsets(*State.Streamer.get(), *State.Strings.get(), - StrOffsetSection, CurStrSection, - CurStrOffsetSection, CU.getVersion()); - StrSectionWrittenOut = true; + if (SectionName.equals("debug_str.dwo")) { + CurStrSection = OutData; + } else { + // Since handleDebugDataPatching returned true, we already know this is + // a known section. + auto SectionIter = State.KnownSections.find(SectionName); + if (SectionIter->second.second == DWARFSectionKind::DW_SECT_STR_OFFSETS) + CurStrOffsetSection = OutData; + else + State.Streamer->emitBytes(OutData); + unsigned int Index = getContributionIndex(SectionIter->second.second, + State.IndexVersion); + uint64_t Offset = State.ContributionOffsets[Index]; + uint64_t Length = OutData.size(); + if (CU.getVersion() >= 5 && + SectionIter->second.second == DWARFSectionKind::DW_SECT_INFO) { + for (UnitMeta &MI : TUMetaVector) + MI.Offset += State.DebugInfoSize; + + Offset = State.DebugInfoSize + CUMI.Offset; + Length = CUMI.Length; + State.DebugInfoSize += OutData.size(); + } + CurEntry.Contributions[Index].setOffset(Offset); + CurEntry.Contributions[Index].setLength(Length); + State.ContributionOffsets[Index] += + CurEntry.Contributions[Index].getLength32(); + } + + // Strings are combined in to a new string section, and de-duplicated + // based on hash. + if (!StrSectionWrittenOut && !CurStrOffsetSection.empty() && + !CurStrSection.empty()) { + writeStringsAndOffsets(*State.Streamer.get(), *State.Strings.get(), + StrOffsetSection, CurStrSection, + CurStrOffsetSection, CU.getVersion()); + StrSectionWrittenOut = true; + } + } + CompileUnitIdentifiers CUI{DWOId, CurEntry.Name.c_str(), + CurEntry.DWOName.c_str()}; + auto P = State.IndexEntries.insert(std::make_pair(CUI.Signature, CurEntry)); + if (!P.second) { + Error Err = buildDuplicateError(*P.first, CUI, ""); + errs() << "BOLT-ERROR: " << toString(std::move(Err)) << "\n"; + return; } - } - CompileUnitIdentifiers CUI{DWOId, CurEntry.Name.c_str(), - CurEntry.DWOName.c_str()}; - auto P = State.IndexEntries.insert(std::make_pair(CUI.Signature, CurEntry)); - if (!P.second) { - Error Err = buildDuplicateError(*P.first, CUI, ""); - errs() << "BOLT-ERROR: " << toString(std::move(Err)) << "\n"; - return; - } - // Handling TU - const unsigned Index = getContributionIndex( - State.IndexVersion < 5 ? DW_SECT_EXT_TYPES : DW_SECT_INFO, - State.IndexVersion); - for (UnitMeta &MI : TUMetaVector) - AddType(Index, State.IndexVersion, MI.Offset, MI.Length, MI.TUHash); -} + // Handling TU + const unsigned Index = getContributionIndex( + State.IndexVersion < 5 ? DW_SECT_EXT_TYPES : DW_SECT_INFO, + State.IndexVersion); + for (UnitMeta &MI : TUMetaVector) + AddType(Index, State.IndexVersion, MI.Offset, MI.Length, MI.TUHash); + } + + void DWARFRewriter::writeDWOFiles( + DWARFUnit & CU, const OverriddenSectionsMap &OverridenSections, + const std::string &DWOName, DebugLocWriter &LocWriter) { + // Setup DWP code once. + DWARFContext *DWOCtx = BC.getDWOContext(); + const uint64_t DWOId = *CU.getDWOId(); + const DWARFUnitIndex *CUIndex = nullptr; + bool IsDWP = false; + if (DWOCtx) { + CUIndex = &DWOCtx->getCUIndex(); + IsDWP = !CUIndex->getRows().empty(); + } -void DWARFRewriter::writeDWOFiles( - DWARFUnit &CU, const OverriddenSectionsMap &OverridenSections, - const std::string &DWOName, DebugLocWriter &LocWriter) { - // Setup DWP code once. - DWARFContext *DWOCtx = BC.getDWOContext(); - const uint64_t DWOId = *CU.getDWOId(); - const DWARFUnitIndex *CUIndex = nullptr; - bool IsDWP = false; - if (DWOCtx) { - CUIndex = &DWOCtx->getCUIndex(); - IsDWP = !CUIndex->getRows().empty(); - } + // Skipping CUs that we failed to load. + std::optional DWOCU = BC.getDWOCU(DWOId); + if (!DWOCU) { + errs() << "BOLT-WARNING: [internal-dwarf-error]: CU for DWO_ID " + << Twine::utohexstr(DWOId) << " is not found.\n"; + return; + } - // Skipping CUs that we failed to load. - std::optional DWOCU = BC.getDWOCU(DWOId); - if (!DWOCU) { - errs() << "BOLT-WARNING: [internal-dwarf-error]: CU for DWO_ID " - << Twine::utohexstr(DWOId) << " is not found.\n"; - return; - } + std::string CompDir = opts::DwarfOutputPath.empty() + ? CU.getCompilationDir() + : opts::DwarfOutputPath.c_str(); + auto FullPath = CompDir.append("/").append(DWOName); + + std::error_code EC; + std::unique_ptr TempOut = + std::make_unique(FullPath, EC, sys::fs::OF_None); + + const DWARFUnitIndex::Entry *CUDWOEntry = nullptr; + if (IsDWP) + CUDWOEntry = CUIndex->getFromHash(DWOId); + + const object::ObjectFile *File = + (*DWOCU)->getContext().getDWARFObj().getFile(); + std::unique_ptr TmpBC = createDwarfOnlyBC(*File); + std::unique_ptr Streamer = TmpBC->createStreamer(TempOut->os()); + const MCObjectFileInfo &MCOFI = *Streamer->getContext().getObjectFileInfo(); + StringMap KnownSections = createKnownSectionsMap(MCOFI); + + DebugRangeListsSectionWriter *RangeListssWriter = nullptr; + if (CU.getVersion() == 5) { + assert(RangeListsWritersByCU.count(DWOId) != 0 && + "No RangeListsWriter for DWO ID."); + RangeListssWriter = RangeListsWritersByCU[DWOId].get(); + + // Handling .debug_rnglists.dwo seperatly. The original .o/.dwo might not + // have .debug_rnglists so won't be part of the loop below. + if (!RangeListssWriter->empty()) { + std::unique_ptr OutputData; + if (std::optional OutData = updateDebugData( + (*DWOCU)->getContext(), "debug_rnglists.dwo", "", KnownSections, + *Streamer, *this, CUDWOEntry, DWOId, OutputData, + RangeListssWriter, LocWriter, OverridenSections)) + Streamer->emitBytes(*OutData); + } + } - std::string CompDir = opts::DwarfOutputPath.empty() - ? CU.getCompilationDir() - : opts::DwarfOutputPath.c_str(); - auto FullPath = CompDir.append("/").append(DWOName); - - std::error_code EC; - std::unique_ptr TempOut = - std::make_unique(FullPath, EC, sys::fs::OF_None); - - const DWARFUnitIndex::Entry *CUDWOEntry = nullptr; - if (IsDWP) - CUDWOEntry = CUIndex->getFromHash(DWOId); - - const object::ObjectFile *File = - (*DWOCU)->getContext().getDWARFObj().getFile(); - std::unique_ptr TmpBC = createDwarfOnlyBC(*File); - std::unique_ptr Streamer = TmpBC->createStreamer(TempOut->os()); - const MCObjectFileInfo &MCOFI = *Streamer->getContext().getObjectFileInfo(); - StringMap KnownSections = createKnownSectionsMap(MCOFI); - - DebugRangeListsSectionWriter *RangeListssWriter = nullptr; - if (CU.getVersion() == 5) { - assert(RangeListsWritersByCU.count(DWOId) != 0 && - "No RangeListsWriter for DWO ID."); - RangeListssWriter = RangeListsWritersByCU[DWOId].get(); - - // Handling .debug_rnglists.dwo seperatly. The original .o/.dwo might not - // have .debug_rnglists so won't be part of the loop below. - if (!RangeListssWriter->empty()) { + for (const SectionRef &Section : File->sections()) { std::unique_ptr OutputData; + StringRef SectionName = getSectionName(Section); + if (SectionName == "debug_rnglists.dwo") + continue; + Expected ContentsExp = Section.getContents(); + assert(ContentsExp && "Invalid contents."); if (std::optional OutData = updateDebugData( - (*DWOCU)->getContext(), "debug_rnglists.dwo", "", KnownSections, + (*DWOCU)->getContext(), SectionName, *ContentsExp, KnownSections, *Streamer, *this, CUDWOEntry, DWOId, OutputData, RangeListssWriter, LocWriter, OverridenSections)) Streamer->emitBytes(*OutData); } + Streamer->finish(); + TempOut->keep(); } - for (const SectionRef &Section : File->sections()) { - std::unique_ptr OutputData; - StringRef SectionName = getSectionName(Section); - if (SectionName == "debug_rnglists.dwo") - continue; - Expected ContentsExp = Section.getContents(); - assert(ContentsExp && "Invalid contents."); - if (std::optional OutData = updateDebugData( - (*DWOCU)->getContext(), SectionName, *ContentsExp, KnownSections, - *Streamer, *this, CUDWOEntry, DWOId, OutputData, RangeListssWriter, - LocWriter, OverridenSections)) - Streamer->emitBytes(*OutData); + void DWARFRewriter::addGDBTypeUnitEntry(const GDBIndexTUEntry &&Entry) { + std::lock_guard Lock(DWARFRewriterMutex); + if (!BC.getGdbIndexSection()) + return; + GDBIndexTUEntryVector.emplace_back(Entry); } - Streamer->finish(); - TempOut->keep(); -} - -void DWARFRewriter::addGDBTypeUnitEntry(const GDBIndexTUEntry &&Entry) { - std::lock_guard Lock(DWARFRewriterMutex); - if (!BC.getGdbIndexSection()) - return; - GDBIndexTUEntryVector.emplace_back(Entry); -} -void DWARFRewriter::updateGdbIndexSection(CUOffsetMap &CUMap, uint32_t NumCUs) { - if (!BC.getGdbIndexSection()) - return; + void DWARFRewriter::updateGdbIndexSection(CUOffsetMap & CUMap, + uint32_t NumCUs) { + if (!BC.getGdbIndexSection()) + return; - // See https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html - // for .gdb_index section format. + // See https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html + // for .gdb_index section format. - StringRef GdbIndexContents = BC.getGdbIndexSection()->getContents(); + StringRef GdbIndexContents = BC.getGdbIndexSection()->getContents(); - const char *Data = GdbIndexContents.data(); + const char *Data = GdbIndexContents.data(); - // Parse the header. - const uint32_t Version = read32le(Data); - if (Version != 7 && Version != 8) { - errs() << "BOLT-ERROR: can only process .gdb_index versions 7 and 8\n"; - exit(1); - } + // Parse the header. + const uint32_t Version = read32le(Data); + if (Version != 7 && Version != 8) { + errs() << "BOLT-ERROR: can only process .gdb_index versions 7 and 8\n"; + exit(1); + } - // Some .gdb_index generators use file offsets while others use section - // offsets. Hence we can only rely on offsets relative to each other, - // and ignore their absolute values. - const uint32_t CUListOffset = read32le(Data + 4); - const uint32_t CUTypesOffset = read32le(Data + 8); - const uint32_t AddressTableOffset = read32le(Data + 12); - const uint32_t SymbolTableOffset = read32le(Data + 16); - const uint32_t ConstantPoolOffset = read32le(Data + 20); - Data += 24; - - // Map CUs offsets to indices and verify existing index table. - std::map OffsetToIndexMap; - const uint32_t CUListSize = CUTypesOffset - CUListOffset; - const uint32_t TUListSize = AddressTableOffset - CUTypesOffset; - const unsigned NUmCUsEncoded = CUListSize / 16; - unsigned MaxDWARFVersion = BC.DwCtx->getMaxVersion(); - unsigned NumDWARF5TUs = - getGDBIndexTUEntryVector().size() - BC.DwCtx->getNumTypeUnits(); - bool SkipTypeUnits = false; - // For DWARF5 Types are in .debug_info. - // LLD doesn't generate Types CU List, and in CU list offset - // only includes CUs. - // GDB 11+ includes only CUs in CU list and generates Types - // list. - // GDB 9 includes CUs and TUs in CU list and generates TYpes - // list. The NumCUs is CUs + TUs, so need to modify the check. - // For split-dwarf - // GDB-11, DWARF5: TU units from dwo are not included. - // GDB-11, DWARF4: TU units from dwo are included. - if (MaxDWARFVersion >= 5) - SkipTypeUnits = !TUListSize ? true - : ((NUmCUsEncoded + NumDWARF5TUs) == - BC.DwCtx->getNumCompileUnits()); - - if (!((CUListSize == NumCUs * 16) || - (CUListSize == (NumCUs + NumDWARF5TUs) * 16))) { - errs() << "BOLT-ERROR: .gdb_index: CU count mismatch\n"; - exit(1); - } - DenseSet OriginalOffsets; - for (unsigned Index = 0, Units = BC.DwCtx->getNumCompileUnits(); - Index < Units; ++Index) { - const DWARFUnit *CU = BC.DwCtx->getUnitAtIndex(Index); - if (SkipTypeUnits && CU->isTypeUnit()) - continue; - const uint64_t Offset = read64le(Data); - Data += 16; - if (CU->getOffset() != Offset) { - errs() << "BOLT-ERROR: .gdb_index CU offset mismatch\n"; + // Some .gdb_index generators use file offsets while others use section + // offsets. Hence we can only rely on offsets relative to each other, + // and ignore their absolute values. + const uint32_t CUListOffset = read32le(Data + 4); + const uint32_t CUTypesOffset = read32le(Data + 8); + const uint32_t AddressTableOffset = read32le(Data + 12); + const uint32_t SymbolTableOffset = read32le(Data + 16); + const uint32_t ConstantPoolOffset = read32le(Data + 20); + Data += 24; + + // Map CUs offsets to indices and verify existing index table. + std::map OffsetToIndexMap; + const uint32_t CUListSize = CUTypesOffset - CUListOffset; + const uint32_t TUListSize = AddressTableOffset - CUTypesOffset; + const unsigned NUmCUsEncoded = CUListSize / 16; + unsigned MaxDWARFVersion = BC.DwCtx->getMaxVersion(); + unsigned NumDWARF5TUs = + getGDBIndexTUEntryVector().size() - BC.DwCtx->getNumTypeUnits(); + bool SkipTypeUnits = false; + // For DWARF5 Types are in .debug_info. + // LLD doesn't generate Types CU List, and in CU list offset + // only includes CUs. + // GDB 11+ includes only CUs in CU list and generates Types + // list. + // GDB 9 includes CUs and TUs in CU list and generates TYpes + // list. The NumCUs is CUs + TUs, so need to modify the check. + // For split-dwarf + // GDB-11, DWARF5: TU units from dwo are not included. + // GDB-11, DWARF4: TU units from dwo are included. + if (MaxDWARFVersion >= 5) + SkipTypeUnits = !TUListSize ? true + : ((NUmCUsEncoded + NumDWARF5TUs) == + BC.DwCtx->getNumCompileUnits()); + + if (!((CUListSize == NumCUs * 16) || + (CUListSize == (NumCUs + NumDWARF5TUs) * 16))) { + errs() << "BOLT-ERROR: .gdb_index: CU count mismatch\n"; exit(1); } + DenseSet OriginalOffsets; + for (unsigned Index = 0, Units = BC.DwCtx->getNumCompileUnits(); + Index < Units; ++Index) { + const DWARFUnit *CU = BC.DwCtx->getUnitAtIndex(Index); + if (SkipTypeUnits && CU->isTypeUnit()) + continue; + const uint64_t Offset = read64le(Data); + Data += 16; + if (CU->getOffset() != Offset) { + errs() << "BOLT-ERROR: .gdb_index CU offset mismatch\n"; + exit(1); + } - OriginalOffsets.insert(Offset); - OffsetToIndexMap[Offset] = Index; - } + OriginalOffsets.insert(Offset); + OffsetToIndexMap[Offset] = Index; + } - // Ignore old address table. - const uint32_t OldAddressTableSize = SymbolTableOffset - AddressTableOffset; - // Move Data to the beginning of symbol table. - Data += SymbolTableOffset - CUTypesOffset; + // Ignore old address table. + const uint32_t OldAddressTableSize = SymbolTableOffset - AddressTableOffset; + // Move Data to the beginning of symbol table. + Data += SymbolTableOffset - CUTypesOffset; + + // Calculate the size of the new address table. + uint32_t NewAddressTableSize = 0; + for (const auto &CURangesPair : + ARangesSectionWriter->getCUAddressRanges()) { + const SmallVector &Ranges = CURangesPair.second; + NewAddressTableSize += Ranges.size() * 20; + } - // Calculate the size of the new address table. - uint32_t NewAddressTableSize = 0; - for (const auto &CURangesPair : ARangesSectionWriter->getCUAddressRanges()) { - const SmallVector &Ranges = CURangesPair.second; - NewAddressTableSize += Ranges.size() * 20; - } + // Difference between old and new table (and section) sizes. + // Could be negative. + int32_t Delta = NewAddressTableSize - OldAddressTableSize; + + size_t NewGdbIndexSize = GdbIndexContents.size() + Delta; + + // Free'd by ExecutableFileMemoryManager. + auto *NewGdbIndexContents = new uint8_t[NewGdbIndexSize]; + uint8_t *Buffer = NewGdbIndexContents; + + write32le(Buffer, Version); + write32le(Buffer + 4, CUListOffset); + write32le(Buffer + 8, CUTypesOffset); + write32le(Buffer + 12, AddressTableOffset); + write32le(Buffer + 16, SymbolTableOffset + Delta); + write32le(Buffer + 20, ConstantPoolOffset + Delta); + Buffer += 24; + + using MapEntry = std::pair; + std::vector CUVector(CUMap.begin(), CUMap.end()); + // Need to sort since we write out all of TUs in .debug_info before CUs. + std::sort(CUVector.begin(), CUVector.end(), + [](const MapEntry &E1, const MapEntry &E2) -> bool { + return E1.second.Offset < E2.second.Offset; + }); + // Writing out CU List + for (auto &CUInfo : CUVector) { + // Skipping TU for DWARF5 when they are not included in CU list. + if (!OriginalOffsets.count(CUInfo.first)) + continue; + write64le(Buffer, CUInfo.second.Offset); + // Length encoded in CU doesn't contain first 4 bytes that encode length. + write64le(Buffer + 8, CUInfo.second.Length + 4); + Buffer += 16; + } - // Difference between old and new table (and section) sizes. - // Could be negative. - int32_t Delta = NewAddressTableSize - OldAddressTableSize; - - size_t NewGdbIndexSize = GdbIndexContents.size() + Delta; - - // Free'd by ExecutableFileMemoryManager. - auto *NewGdbIndexContents = new uint8_t[NewGdbIndexSize]; - uint8_t *Buffer = NewGdbIndexContents; - - write32le(Buffer, Version); - write32le(Buffer + 4, CUListOffset); - write32le(Buffer + 8, CUTypesOffset); - write32le(Buffer + 12, AddressTableOffset); - write32le(Buffer + 16, SymbolTableOffset + Delta); - write32le(Buffer + 20, ConstantPoolOffset + Delta); - Buffer += 24; - - using MapEntry = std::pair; - std::vector CUVector(CUMap.begin(), CUMap.end()); - // Need to sort since we write out all of TUs in .debug_info before CUs. - std::sort(CUVector.begin(), CUVector.end(), - [](const MapEntry &E1, const MapEntry &E2) -> bool { - return E1.second.Offset < E2.second.Offset; - }); - // Writing out CU List - for (auto &CUInfo : CUVector) { - // Skipping TU for DWARF5 when they are not included in CU list. - if (!OriginalOffsets.count(CUInfo.first)) - continue; - write64le(Buffer, CUInfo.second.Offset); - // Length encoded in CU doesn't contain first 4 bytes that encode length. - write64le(Buffer + 8, CUInfo.second.Length + 4); - Buffer += 16; - } + // Rewrite TU CU List, since abbrevs can be different. + // Entry example: + // 0: offset = 0x00000000, type_offset = 0x0000001e, type_signature = + // 0x418503b8111e9a7b Spec says " triplet, the first value is the CU offset, + // the second value is the type offset in the CU, and the third value is the + // type signature" Looking at what is being generated by gdb-add-index. The + // first entry is TU offset, second entry is offset from it, and third entry + // is the type signature. + if (TUListSize) + for (const GDBIndexTUEntry &Entry : getGDBIndexTUEntryVector()) { + write64le(Buffer, Entry.UnitOffset); + write64le(Buffer + 8, Entry.TypeDIERelativeOffset); + write64le(Buffer + 16, Entry.TypeHash); + Buffer += sizeof(GDBIndexTUEntry); + } - // Rewrite TU CU List, since abbrevs can be different. - // Entry example: - // 0: offset = 0x00000000, type_offset = 0x0000001e, type_signature = - // 0x418503b8111e9a7b Spec says " triplet, the first value is the CU offset, - // the second value is the type offset in the CU, and the third value is the - // type signature" Looking at what is being generated by gdb-add-index. The - // first entry is TU offset, second entry is offset from it, and third entry - // is the type signature. - if (TUListSize) - for (const GDBIndexTUEntry &Entry : getGDBIndexTUEntryVector()) { - write64le(Buffer, Entry.UnitOffset); - write64le(Buffer + 8, Entry.TypeDIERelativeOffset); - write64le(Buffer + 16, Entry.TypeHash); - Buffer += sizeof(GDBIndexTUEntry); - } - - // Generate new address table. - for (const std::pair &CURangesPair : - ARangesSectionWriter->getCUAddressRanges()) { - const uint32_t CUIndex = OffsetToIndexMap[CURangesPair.first]; - const DebugAddressRangesVector &Ranges = CURangesPair.second; - for (const DebugAddressRange &Range : Ranges) { - write64le(Buffer, Range.LowPC); - write64le(Buffer + 8, Range.HighPC); - write32le(Buffer + 16, CUIndex); - Buffer += 20; + // Generate new address table. + for (const std::pair + &CURangesPair : ARangesSectionWriter->getCUAddressRanges()) { + const uint32_t CUIndex = OffsetToIndexMap[CURangesPair.first]; + const DebugAddressRangesVector &Ranges = CURangesPair.second; + for (const DebugAddressRange &Range : Ranges) { + write64le(Buffer, Range.LowPC); + write64le(Buffer + 8, Range.HighPC); + write32le(Buffer + 16, CUIndex); + Buffer += 20; + } } + + const size_t TrailingSize = + GdbIndexContents.data() + GdbIndexContents.size() - Data; + assert(Buffer + TrailingSize == NewGdbIndexContents + NewGdbIndexSize && + "size calculation error"); + + // Copy over the rest of the original data. + memcpy(Buffer, Data, TrailingSize); + + // Register the new section. + BC.registerOrUpdateNoteSection(".gdb_index", NewGdbIndexContents, + NewGdbIndexSize); } - const size_t TrailingSize = - GdbIndexContents.data() + GdbIndexContents.size() - Data; - assert(Buffer + TrailingSize == NewGdbIndexContents + NewGdbIndexSize && - "size calculation error"); + std::unique_ptr DWARFRewriter::makeFinalLocListsSection( + DWARFVersion Version) { + auto LocBuffer = std::make_unique(); + auto LocStream = std::make_unique(*LocBuffer); + auto Writer = + std::unique_ptr(BC.createObjectWriter(*LocStream)); - // Copy over the rest of the original data. - memcpy(Buffer, Data, TrailingSize); + for (std::pair> &Loc : + LocListWritersByCU) { + DebugLocWriter *LocWriter = Loc.second.get(); + auto *LocListWriter = llvm::dyn_cast(LocWriter); - // Register the new section. - BC.registerOrUpdateNoteSection(".gdb_index", NewGdbIndexContents, - NewGdbIndexSize); -} + // Filter out DWARF4, writing out DWARF5 + if (Version == DWARFVersion::DWARF5 && + (!LocListWriter || LocListWriter->getDwarfVersion() <= 4)) + continue; -std::unique_ptr -DWARFRewriter::makeFinalLocListsSection(DWARFVersion Version) { - auto LocBuffer = std::make_unique(); - auto LocStream = std::make_unique(*LocBuffer); - auto Writer = - std::unique_ptr(BC.createObjectWriter(*LocStream)); - - for (std::pair> &Loc : - LocListWritersByCU) { - DebugLocWriter *LocWriter = Loc.second.get(); - auto *LocListWriter = llvm::dyn_cast(LocWriter); - - // Filter out DWARF4, writing out DWARF5 - if (Version == DWARFVersion::DWARF5 && - (!LocListWriter || LocListWriter->getDwarfVersion() <= 4)) - continue; + // Filter out DWARF5, writing out DWARF4 + if (Version == DWARFVersion::DWARFLegacy && + (LocListWriter && LocListWriter->getDwarfVersion() >= 5)) + continue; - // Filter out DWARF5, writing out DWARF4 - if (Version == DWARFVersion::DWARFLegacy && - (LocListWriter && LocListWriter->getDwarfVersion() >= 5)) - continue; + // Skipping DWARF4/5 split dwarf. + if (LocListWriter && LocListWriter->getDwarfVersion() <= 4) + continue; + std::unique_ptr CurrCULocationLists = + LocWriter->getBuffer(); + *LocStream << *CurrCULocationLists; + } - // Skipping DWARF4/5 split dwarf. - if (LocListWriter && LocListWriter->getDwarfVersion() <= 4) - continue; - std::unique_ptr CurrCULocationLists = - LocWriter->getBuffer(); - *LocStream << *CurrCULocationLists; + return LocBuffer; } - return LocBuffer; -} + void DWARFRewriter::convertToRangesPatchDebugInfo( + DWARFUnit & Unit, DIEBuilder & DIEBldr, DIE & Die, + uint64_t RangesSectionOffset, DIEValue & LowPCAttrInfo, + DIEValue & HighPCAttrInfo, std::optional RangesBase) { + uint32_t BaseOffset = 0; + dwarf::Form LowForm = LowPCAttrInfo.getForm(); + dwarf::Attribute RangeBaseAttribute = dwarf::DW_AT_GNU_ranges_base; + dwarf::Form RangesForm = dwarf::DW_FORM_sec_offset; -void DWARFRewriter::convertToRangesPatchDebugInfo( - DWARFUnit &Unit, DIEBuilder &DIEBldr, DIE &Die, - uint64_t RangesSectionOffset, DIEValue &LowPCAttrInfo, - DIEValue &HighPCAttrInfo, std::optional RangesBase) { - uint32_t BaseOffset = 0; - dwarf::Form LowForm = LowPCAttrInfo.getForm(); - dwarf::Attribute RangeBaseAttribute = dwarf::DW_AT_GNU_ranges_base; - dwarf::Form RangesForm = dwarf::DW_FORM_sec_offset; - - if (Unit.getVersion() >= 5) { - RangeBaseAttribute = dwarf::DW_AT_rnglists_base; - RangesForm = dwarf::DW_FORM_rnglistx; - } else if (Unit.getVersion() < 4) { - RangesForm = dwarf::DW_FORM_data4; - } - bool IsUnitDie = Die.getTag() == dwarf::DW_TAG_compile_unit || - Die.getTag() == dwarf::DW_TAG_skeleton_unit; - if (!IsUnitDie) - DIEBldr.deleteValue(&Die, LowPCAttrInfo.getAttribute()); - // In DWARF4 for DW_AT_low_pc in binary DW_FORM_addr is used. In the DWO - // section DW_FORM_GNU_addr_index is used. So for if we are converting - // DW_AT_low_pc/DW_AT_high_pc and see DW_FORM_GNU_addr_index. We are - // converting in DWO section, and DW_AT_ranges [DW_FORM_sec_offset] is - // relative to DW_AT_GNU_ranges_base. - if (LowForm == dwarf::DW_FORM_GNU_addr_index) { - // Ranges are relative to DW_AT_GNU_ranges_base. - uint64_t CurRangeBase = 0; - if (std::optional DWOId = Unit.getDWOId()) { - CurRangeBase = getDwoRangesBase(*DWOId); + if (Unit.getVersion() >= 5) { + RangeBaseAttribute = dwarf::DW_AT_rnglists_base; + RangesForm = dwarf::DW_FORM_rnglistx; + } else if (Unit.getVersion() < 4) { + RangesForm = dwarf::DW_FORM_data4; } - BaseOffset = CurRangeBase; - } else { - // In DWARF 5 we can have DW_AT_low_pc either as DW_FORM_addr, or - // DW_FORM_addrx. Former is when DW_AT_rnglists_base is present. Latter is - // when it's absent. - if (IsUnitDie) { - if (LowForm == dwarf::DW_FORM_addrx) { - const uint32_t Index = AddrWriter->getIndexFromAddress(0, Unit); - DIEBldr.replaceValue(&Die, LowPCAttrInfo.getAttribute(), - LowPCAttrInfo.getForm(), DIEInteger(Index)); - } else { - DIEBldr.replaceValue(&Die, LowPCAttrInfo.getAttribute(), - LowPCAttrInfo.getForm(), DIEInteger(0)); + bool IsUnitDie = Die.getTag() == dwarf::DW_TAG_compile_unit || + Die.getTag() == dwarf::DW_TAG_skeleton_unit; + if (!IsUnitDie) + DIEBldr.deleteValue(&Die, LowPCAttrInfo.getAttribute()); + // In DWARF4 for DW_AT_low_pc in binary DW_FORM_addr is used. In the DWO + // section DW_FORM_GNU_addr_index is used. So for if we are converting + // DW_AT_low_pc/DW_AT_high_pc and see DW_FORM_GNU_addr_index. We are + // converting in DWO section, and DW_AT_ranges [DW_FORM_sec_offset] is + // relative to DW_AT_GNU_ranges_base. + if (LowForm == dwarf::DW_FORM_GNU_addr_index) { + // Ranges are relative to DW_AT_GNU_ranges_base. + uint64_t CurRangeBase = 0; + if (std::optional DWOId = Unit.getDWOId()) { + CurRangeBase = getDwoRangesBase(*DWOId); } + BaseOffset = CurRangeBase; + } else { + // In DWARF 5 we can have DW_AT_low_pc either as DW_FORM_addr, or + // DW_FORM_addrx. Former is when DW_AT_rnglists_base is present. Latter is + // when it's absent. + if (IsUnitDie) { + if (LowForm == dwarf::DW_FORM_addrx) { + const uint32_t Index = AddrWriter->getIndexFromAddress(0, Unit); + DIEBldr.replaceValue(&Die, LowPCAttrInfo.getAttribute(), + LowPCAttrInfo.getForm(), DIEInteger(Index)); + } else { + DIEBldr.replaceValue(&Die, LowPCAttrInfo.getAttribute(), + LowPCAttrInfo.getForm(), DIEInteger(0)); + } + } + // Original CU didn't have DW_AT_*_base. We converted it's children (or + // dwo), so need to insert it into CU. + if (RangesBase) + DIEBldr.addValue(&Die, RangeBaseAttribute, dwarf::DW_FORM_sec_offset, + DIEInteger(*RangesBase)); } - // Original CU didn't have DW_AT_*_base. We converted it's children (or - // dwo), so need to insert it into CU. - if (RangesBase) - DIEBldr.addValue(&Die, RangeBaseAttribute, dwarf::DW_FORM_sec_offset, - DIEInteger(*RangesBase)); - } - uint64_t RangeAttrVal = RangesSectionOffset - BaseOffset; - if (Unit.getVersion() >= 5) - RangeAttrVal = RangesSectionOffset; - // HighPC was conveted into DW_AT_ranges. - // For DWARF5 we only access ranges throught index. + uint64_t RangeAttrVal = RangesSectionOffset - BaseOffset; + if (Unit.getVersion() >= 5) + RangeAttrVal = RangesSectionOffset; + // HighPC was conveted into DW_AT_ranges. + // For DWARF5 we only access ranges throught index. - DIEBldr.replaceValue(&Die, HighPCAttrInfo.getAttribute(), dwarf::DW_AT_ranges, - RangesForm, DIEInteger(RangeAttrVal)); -} + DIEBldr.replaceValue(&Die, HighPCAttrInfo.getAttribute(), + dwarf::DW_AT_ranges, RangesForm, + DIEInteger(RangeAttrVal)); + } diff --git a/bolt/test/X86/Inputs/dwarf4-df-input-lowpc-ranges-main.s b/bolt/test/X86/Inputs/dwarf4-df-input-lowpc-ranges-main.s new file mode 100644 --- /dev/null +++ b/bolt/test/X86/Inputs/dwarf4-df-input-lowpc-ranges-main.s @@ -0,0 +1,705 @@ +# clang++ -fbasic-block-sections=all -ffunction-sections -g2 -gdwarf-4 -gsplit-dwarf +# __attribute__((always_inline)) +# int doStuff(int val) { +# if (val) +# ++val; +# return val; +# } +# __attribute__((always_inline)) +# int doStuff2(int val) { +# int foo = 3; +# return val + foo; +# } +# +# +# int main(int argc, const char** argv) { +# return doStuff(argc) + doStuff2(argc);; +# } + + .text + .file "main.cpp" + .section .text._Z7doStuffi,"ax",@progbits + .globl _Z7doStuffi # -- Begin function _Z7doStuffi + .p2align 4, 0x90 + .type _Z7doStuffi,@function +_Z7doStuffi: # @_Z7doStuffi +.Lfunc_begin0: + .file 1 "." "main.cpp" + .loc 1 2 0 # main.cpp:2:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -4(%rbp) +.Ltmp0: + .loc 1 3 7 prologue_end # main.cpp:3:7 + cmpl $0, -4(%rbp) +.Ltmp1: + .loc 1 3 7 is_stmt 0 # main.cpp:3:7 + je _Z7doStuffi.__part.2 + jmp _Z7doStuffi.__part.1 +.LBB_END0_0: + .cfi_endproc + .section .text._Z7doStuffi,"ax",@progbits,unique,1 +_Z7doStuffi.__part.1: # %if.then + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 1 4 5 is_stmt 1 # main.cpp:4:5 + movl -4(%rbp), %eax + addl $1, %eax + movl %eax, -4(%rbp) + jmp _Z7doStuffi.__part.2 +.LBB_END0_1: + .size _Z7doStuffi.__part.1, .LBB_END0_1-_Z7doStuffi.__part.1 + .cfi_endproc + .section .text._Z7doStuffi,"ax",@progbits,unique,2 +_Z7doStuffi.__part.2: # %if.end + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 1 5 10 # main.cpp:5:10 + movl -4(%rbp), %eax + .loc 1 5 3 epilogue_begin is_stmt 0 # main.cpp:5:3 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END0_2: + .size _Z7doStuffi.__part.2, .LBB_END0_2-_Z7doStuffi.__part.2 + .cfi_endproc + .section .text._Z7doStuffi,"ax",@progbits +.Lfunc_end0: + .size _Z7doStuffi, .Lfunc_end0-_Z7doStuffi + # -- End function + .section .text._Z8doStuff2i,"ax",@progbits + .globl _Z8doStuff2i # -- Begin function _Z8doStuff2i + .p2align 4, 0x90 + .type _Z8doStuff2i,@function +_Z8doStuff2i: # @_Z8doStuff2i +.Lfunc_begin1: + .loc 1 8 0 is_stmt 1 # main.cpp:8:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -4(%rbp) +.Ltmp2: + .loc 1 9 7 prologue_end # main.cpp:9:7 + movl $3, -8(%rbp) + .loc 1 10 10 # main.cpp:10:10 + movl -4(%rbp), %eax + .loc 1 10 14 is_stmt 0 # main.cpp:10:14 + addl -8(%rbp), %eax + .loc 1 10 3 epilogue_begin # main.cpp:10:3 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END1_0: + .cfi_endproc +.Lfunc_end1: + .size _Z8doStuff2i, .Lfunc_end1-_Z8doStuff2i + # -- End function + .section .text.main,"ax",@progbits + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main +.Lfunc_begin2: + .loc 1 14 0 is_stmt 1 # main.cpp:14:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl $0, -16(%rbp) + movl %edi, -20(%rbp) + movq %rsi, -32(%rbp) +.Ltmp3: + .loc 1 15 21 prologue_end # main.cpp:15:21 + movl -20(%rbp), %eax + movl %eax, -12(%rbp) +.Ltmp4: + .loc 1 3 7 # main.cpp:3:7 + cmpl $0, -12(%rbp) +.Ltmp5: + .loc 1 3 7 is_stmt 0 # main.cpp:3:7 + je main.__part.2 + jmp main.__part.1 +.LBB_END2_0: + .cfi_endproc + .section .text.main,"ax",@progbits,unique,3 +main.__part.1: # %if.then.i + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 1 4 5 is_stmt 1 # main.cpp:4:5 + movl -12(%rbp), %eax + addl $1, %eax + movl %eax, -12(%rbp) + jmp main.__part.2 +.LBB_END2_1: + .size main.__part.1, .LBB_END2_1-main.__part.1 + .cfi_endproc + .section .text.main,"ax",@progbits,unique,4 +main.__part.2: # %_Z7doStuffi.exit + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 1 5 10 # main.cpp:5:10 + movl -12(%rbp), %eax +.Ltmp6: + .loc 1 15 38 # main.cpp:15:38 + movl -20(%rbp), %ecx + movl %ecx, -4(%rbp) +.Ltmp7: + .loc 1 9 7 # main.cpp:9:7 + movl $3, -8(%rbp) + .loc 1 10 10 # main.cpp:10:10 + movl -4(%rbp), %ecx + .loc 1 10 14 is_stmt 0 # main.cpp:10:14 + addl -8(%rbp), %ecx +.Ltmp8: + .loc 1 15 27 is_stmt 1 # main.cpp:15:27 + addl %ecx, %eax + .loc 1 15 5 epilogue_begin is_stmt 0 # main.cpp:15:5 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END2_2: + .size main.__part.2, .LBB_END2_2-main.__part.2 + .cfi_endproc + .section .text.main,"ax",@progbits +.Lfunc_end2: + .size main, .Lfunc_end2-main + # -- End function + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .ascii "\264B" # DW_AT_GNU_pubnames + .byte 25 # DW_FORM_flag_present + .ascii "\260B" # DW_AT_GNU_dwo_name + .byte 14 # DW_FORM_strp + .ascii "\261B" # DW_AT_GNU_dwo_id + .byte 7 # DW_FORM_data8 + .ascii "\262B" # DW_AT_GNU_ranges_base + .byte 23 # DW_FORM_sec_offset + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .ascii "\263B" # DW_AT_GNU_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x29 DW_TAG_compile_unit + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Lskel_string0 # DW_AT_comp_dir + # DW_AT_GNU_pubnames + .long .Lskel_string1 # DW_AT_GNU_dwo_name + .quad 1354107878901449185 # DW_AT_GNU_dwo_id + .long .debug_ranges # DW_AT_GNU_ranges_base + .quad 0 # DW_AT_low_pc + .long .Ldebug_ranges3 # DW_AT_ranges + .long .Laddr_table_base0 # DW_AT_GNU_addr_base +.Ldebug_info_end0: + .section .debug_ranges,"",@progbits +.Ldebug_ranges0: + .quad _Z7doStuffi.__part.1 + .quad .LBB_END0_1 + .quad _Z7doStuffi.__part.2 + .quad .LBB_END0_2 + .quad .Lfunc_begin0 + .quad .Lfunc_end0 + .quad 0 + .quad 0 +.Ldebug_ranges1: + .quad main.__part.1 + .quad .LBB_END2_1 + .quad main.__part.2 + .quad .LBB_END2_2 + .quad .Lfunc_begin2 + .quad .Lfunc_end2 + .quad 0 + .quad 0 +.Ldebug_ranges2: + .quad .Ltmp4 + .quad .Lfunc_end2 + .quad main.__part.1 + .quad .LBB_END2_1 + .quad main.__part.2 + .quad .Ltmp6 + .quad 0 + .quad 0 +.Ldebug_ranges3: + .quad _Z7doStuffi.__part.1 + .quad .LBB_END0_1 + .quad _Z7doStuffi.__part.2 + .quad .LBB_END0_2 + .quad .Lfunc_begin0 + .quad .Lfunc_end0 + .quad .Lfunc_begin1 + .quad .Lfunc_end1 + .quad main.__part.1 + .quad .LBB_END2_1 + .quad main.__part.2 + .quad .LBB_END2_2 + .quad .Lfunc_begin2 + .quad .Lfunc_end2 + .quad 0 + .quad 0 + .section .debug_str,"MS",@progbits,1 +.Lskel_string0: + .asciz "." # string offset=0 +.Lskel_string1: + .asciz "main.dwo" # string offset=38 + .section .debug_str.dwo,"eMS",@progbits,1 +.Linfo_string0: + .asciz "_Z7doStuffi" # string offset=0 +.Linfo_string1: + .asciz "doStuff" # string offset=12 +.Linfo_string2: + .asciz "int" # string offset=20 +.Linfo_string3: + .asciz "val" # string offset=24 +.Linfo_string4: + .asciz "_Z8doStuff2i" # string offset=28 +.Linfo_string5: + .asciz "doStuff2" # string offset=41 +.Linfo_string6: + .asciz "foo" # string offset=50 +.Linfo_string7: + .asciz "main" # string offset=54 +.Linfo_string8: + .asciz "argc" # string offset=59 +.Linfo_string9: + .asciz "argv" # string offset=64 +.Linfo_string10: + .asciz "char" # string offset=69 +.Linfo_string11: + .asciz "clang version 18.0.0 (git@github.com:llvm/llvm-project.git 3a8db0f4bfb57348f49d9603119fa157114bbf8e)" # string offset=74 +.Linfo_string12: + .asciz "main.cpp" # string offset=175 +.Linfo_string13: + .asciz "main.dwo" # string offset=184 + .section .debug_str_offsets.dwo,"e",@progbits + .long 0 + .long 12 + .long 20 + .long 24 + .long 28 + .long 41 + .long 50 + .long 54 + .long 59 + .long 64 + .long 69 + .long 74 + .long 175 + .long 184 + .section .debug_info.dwo,"e",@progbits + .long .Ldebug_info_dwo_end0-.Ldebug_info_dwo_start0 # Length of Unit +.Ldebug_info_dwo_start0: + .short 4 # DWARF version number + .long 0 # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0xdd DW_TAG_compile_unit + .byte 11 # DW_AT_producer + .short 33 # DW_AT_language + .byte 12 # DW_AT_name + .byte 13 # DW_AT_GNU_dwo_name + .quad 1354107878901449185 # DW_AT_GNU_dwo_id + .byte 2 # Abbrev [2] 0x19:0x14 DW_TAG_subprogram + .long .Ldebug_ranges0-.debug_ranges # DW_AT_ranges + .byte 1 # DW_AT_frame_base + .byte 86 + .long 74 # DW_AT_abstract_origin + .byte 3 # Abbrev [3] 0x24:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 84 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 4 # Abbrev [4] 0x2d:0x1d DW_TAG_subprogram + .byte 3 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .long 97 # DW_AT_abstract_origin + .byte 3 # Abbrev [3] 0x39:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 107 # DW_AT_abstract_origin + .byte 5 # Abbrev [5] 0x41:0x8 DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .long 115 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 6 # Abbrev [6] 0x4a:0x13 DW_TAG_subprogram + .byte 0 # DW_AT_linkage_name + .byte 1 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long 93 # DW_AT_type + # DW_AT_external + .byte 1 # DW_AT_inline + .byte 7 # Abbrev [7] 0x54:0x8 DW_TAG_formal_parameter + .byte 3 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long 93 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 8 # Abbrev [8] 0x5d:0x4 DW_TAG_base_type + .byte 2 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 6 # Abbrev [6] 0x61:0x1b DW_TAG_subprogram + .byte 4 # DW_AT_linkage_name + .byte 5 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + .long 93 # DW_AT_type + # DW_AT_external + .byte 1 # DW_AT_inline + .byte 7 # Abbrev [7] 0x6b:0x8 DW_TAG_formal_parameter + .byte 3 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + .long 93 # DW_AT_type + .byte 9 # Abbrev [9] 0x73:0x8 DW_TAG_variable + .byte 6 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 9 # DW_AT_decl_line + .long 93 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 10 # Abbrev [10] 0x7c:0x58 DW_TAG_subprogram + .long .Ldebug_ranges1-.debug_ranges # DW_AT_ranges + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 7 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 93 # DW_AT_type + # DW_AT_external + .byte 11 # Abbrev [11] 0x8a:0xb DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 108 + .byte 8 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 93 # DW_AT_type + .byte 11 # Abbrev [11] 0x95:0xb DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 96 + .byte 9 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 212 # DW_AT_type + .byte 12 # Abbrev [12] 0xa0:0x15 DW_TAG_inlined_subroutine + .long 74 # DW_AT_abstract_origin + .long .Ldebug_ranges2-.debug_ranges # DW_AT_ranges + .byte 1 # DW_AT_call_file + .byte 15 # DW_AT_call_line + .byte 13 # DW_AT_call_column + .byte 3 # Abbrev [3] 0xac:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 116 + .long 84 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 13 # Abbrev [13] 0xb5:0x1e DW_TAG_inlined_subroutine + .long 97 # DW_AT_abstract_origin + .byte 7 # DW_AT_low_pc + .long .Ltmp8-.Ltmp7 # DW_AT_high_pc + .byte 1 # DW_AT_call_file + .byte 15 # DW_AT_call_line + .byte 29 # DW_AT_call_column + .byte 3 # Abbrev [3] 0xc2:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 107 # DW_AT_abstract_origin + .byte 5 # Abbrev [5] 0xca:0x8 DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .long 115 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 14 # Abbrev [14] 0xd4:0x5 DW_TAG_pointer_type + .long 217 # DW_AT_type + .byte 14 # Abbrev [14] 0xd9:0x5 DW_TAG_pointer_type + .long 222 # DW_AT_type + .byte 15 # Abbrev [15] 0xde:0x5 DW_TAG_const_type + .long 227 # DW_AT_type + .byte 8 # Abbrev [8] 0xe3:0x4 DW_TAG_base_type + .byte 10 # DW_AT_name + .byte 6 # DW_AT_encoding + .byte 1 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_dwo_end0: + .section .debug_abbrev.dwo,"e",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .ascii "\260B" # DW_AT_GNU_dwo_name + .ascii "\202>" # DW_FORM_GNU_str_index + .ascii "\261B" # DW_AT_GNU_dwo_id + .byte 7 # DW_FORM_data8 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .ascii "\201>" # DW_FORM_GNU_addr_index + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 110 # DW_AT_linkage_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 32 # DW_AT_inline + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 8 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 9 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 10 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 11 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .ascii "\202>" # DW_FORM_GNU_str_index + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 12 # Abbreviation Code + .byte 29 # DW_TAG_inlined_subroutine + .byte 1 # DW_CHILDREN_yes + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 85 # DW_AT_ranges + .byte 23 # DW_FORM_sec_offset + .byte 88 # DW_AT_call_file + .byte 11 # DW_FORM_data1 + .byte 89 # DW_AT_call_line + .byte 11 # DW_FORM_data1 + .byte 87 # DW_AT_call_column + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 13 # Abbreviation Code + .byte 29 # DW_TAG_inlined_subroutine + .byte 1 # DW_CHILDREN_yes + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 17 # DW_AT_low_pc + .ascii "\201>" # DW_FORM_GNU_addr_index + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 88 # DW_AT_call_file + .byte 11 # DW_FORM_data1 + .byte 89 # DW_AT_call_line + .byte 11 # DW_FORM_data1 + .byte 87 # DW_AT_call_column + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 14 # Abbreviation Code + .byte 15 # DW_TAG_pointer_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 15 # Abbreviation Code + .byte 38 # DW_TAG_const_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_addr,"",@progbits +.Laddr_table_base0: + .quad _Z7doStuffi.__part.1 + .quad _Z7doStuffi.__part.2 + .quad .Lfunc_begin0 + .quad .Lfunc_begin1 + .quad main.__part.1 + .quad main.__part.2 + .quad .Lfunc_begin2 + .quad .Ltmp7 + .section .debug_gnu_pubnames,"",@progbits + .long .LpubNames_end0-.LpubNames_start0 # Length of Public Names Info +.LpubNames_start0: + .short 2 # DWARF Version + .long .Lcu_begin0 # Offset of Compilation Unit Info + .long 52 # Compilation Unit Length + .long 74 # DIE offset + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "doStuff" # External Name + .long 97 # DIE offset + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "doStuff2" # External Name + .long 124 # DIE offset + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "main" # External Name + .long 0 # End Mark +.LpubNames_end0: + .section .debug_gnu_pubtypes,"",@progbits + .long .LpubTypes_end0-.LpubTypes_start0 # Length of Public Types Info +.LpubTypes_start0: + .short 2 # DWARF Version + .long .Lcu_begin0 # Offset of Compilation Unit Info + .long 52 # Compilation Unit Length + .long 93 # DIE offset + .byte 144 # Attributes: TYPE, STATIC + .asciz "int" # External Name + .long 227 # DIE offset + .byte 144 # Attributes: TYPE, STATIC + .asciz "char" # External Name + .long 0 # End Mark +.LpubTypes_end0: + .ident "clang version 18.0.0 (git@github.com:llvm/llvm-project.git 3a8db0f4bfb57348f49d9603119fa157114bbf8e)" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/Inputs/dwarf5-df-input-lowpc-ranges-main.s b/bolt/test/X86/Inputs/dwarf5-df-input-lowpc-ranges-main.s new file mode 100644 --- /dev/null +++ b/bolt/test/X86/Inputs/dwarf5-df-input-lowpc-ranges-main.s @@ -0,0 +1,748 @@ +# clang++ -fbasic-block-sections=all -ffunction-sections -g2 -gdwarf-5 -gsplit-dwarf +# __attribute__((always_inline)) +# int doStuff(int val) { +# if (val) +# ++val; +# return val; +# } +# __attribute__((always_inline)) +# int doStuff2(int val) { +# int foo = 3; +# return val + foo; +# } +# +# +# int main(int argc, const char** argv) { +# return doStuff(argc) + doStuff2(argc);; +# } + .text + .file "main.cpp" + .section .text._Z7doStuffi,"ax",@progbits + .globl _Z7doStuffi # -- Begin function _Z7doStuffi + .p2align 4, 0x90 + .type _Z7doStuffi,@function +_Z7doStuffi: # @_Z7doStuffi +.Lfunc_begin0: + .file 0 "." "main.cpp" md5 0x69a746524dda095f8ea37f5a26dd1e9b + .loc 0 2 0 # main.cpp:2:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -4(%rbp) +.Ltmp0: + .loc 0 3 7 prologue_end # main.cpp:3:7 + cmpl $0, -4(%rbp) +.Ltmp1: + .loc 0 3 7 is_stmt 0 # main.cpp:3:7 + je _Z7doStuffi.__part.2 + jmp _Z7doStuffi.__part.1 +.LBB_END0_0: + .cfi_endproc + .section .text._Z7doStuffi,"ax",@progbits,unique,1 +_Z7doStuffi.__part.1: # %if.then + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 0 4 5 is_stmt 1 # main.cpp:4:5 + movl -4(%rbp), %eax + addl $1, %eax + movl %eax, -4(%rbp) + jmp _Z7doStuffi.__part.2 +.LBB_END0_1: + .size _Z7doStuffi.__part.1, .LBB_END0_1-_Z7doStuffi.__part.1 + .cfi_endproc + .section .text._Z7doStuffi,"ax",@progbits,unique,2 +_Z7doStuffi.__part.2: # %if.end + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 0 5 10 # main.cpp:5:10 + movl -4(%rbp), %eax + .loc 0 5 3 epilogue_begin is_stmt 0 # main.cpp:5:3 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END0_2: + .size _Z7doStuffi.__part.2, .LBB_END0_2-_Z7doStuffi.__part.2 + .cfi_endproc + .section .text._Z7doStuffi,"ax",@progbits +.Lfunc_end0: + .size _Z7doStuffi, .Lfunc_end0-_Z7doStuffi + # -- End function + .section .text._Z8doStuff2i,"ax",@progbits + .globl _Z8doStuff2i # -- Begin function _Z8doStuff2i + .p2align 4, 0x90 + .type _Z8doStuff2i,@function +_Z8doStuff2i: # @_Z8doStuff2i +.Lfunc_begin1: + .loc 0 8 0 is_stmt 1 # main.cpp:8:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -4(%rbp) +.Ltmp2: + .loc 0 9 7 prologue_end # main.cpp:9:7 + movl $3, -8(%rbp) + .loc 0 10 10 # main.cpp:10:10 + movl -4(%rbp), %eax + .loc 0 10 14 is_stmt 0 # main.cpp:10:14 + addl -8(%rbp), %eax + .loc 0 10 3 epilogue_begin # main.cpp:10:3 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END1_0: + .cfi_endproc +.Lfunc_end1: + .size _Z8doStuff2i, .Lfunc_end1-_Z8doStuff2i + # -- End function + .section .text.main,"ax",@progbits + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main +.Lfunc_begin2: + .loc 0 14 0 is_stmt 1 # main.cpp:14:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl $0, -16(%rbp) + movl %edi, -20(%rbp) + movq %rsi, -32(%rbp) +.Ltmp3: + .loc 0 15 21 prologue_end # main.cpp:15:21 + movl -20(%rbp), %eax + movl %eax, -12(%rbp) +.Ltmp4: + .loc 0 3 7 # main.cpp:3:7 + cmpl $0, -12(%rbp) +.Ltmp5: + .loc 0 3 7 is_stmt 0 # main.cpp:3:7 + je main.__part.2 + jmp main.__part.1 +.LBB_END2_0: + .cfi_endproc + .section .text.main,"ax",@progbits,unique,3 +main.__part.1: # %if.then.i + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 0 4 5 is_stmt 1 # main.cpp:4:5 + movl -12(%rbp), %eax + addl $1, %eax + movl %eax, -12(%rbp) + jmp main.__part.2 +.LBB_END2_1: + .size main.__part.1, .LBB_END2_1-main.__part.1 + .cfi_endproc + .section .text.main,"ax",@progbits,unique,4 +main.__part.2: # %_Z7doStuffi.exit + .cfi_startproc + .cfi_def_cfa %rbp, 16 + .cfi_offset %rbp, -16 + .loc 0 5 10 # main.cpp:5:10 + movl -12(%rbp), %eax +.Ltmp6: + .loc 0 15 38 # main.cpp:15:38 + movl -20(%rbp), %ecx + movl %ecx, -4(%rbp) +.Ltmp7: + .loc 0 9 7 # main.cpp:9:7 + movl $3, -8(%rbp) + .loc 0 10 10 # main.cpp:10:10 + movl -4(%rbp), %ecx + .loc 0 10 14 is_stmt 0 # main.cpp:10:14 + addl -8(%rbp), %ecx +.Ltmp8: + .loc 0 15 27 is_stmt 1 # main.cpp:15:27 + addl %ecx, %eax + .loc 0 15 5 epilogue_begin is_stmt 0 # main.cpp:15:5 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.LBB_END2_2: + .size main.__part.2, .LBB_END2_2-main.__part.2 + .cfi_endproc + .section .text.main,"ax",@progbits +.Lfunc_end2: + .size main, .Lfunc_end2-main + # -- End function + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 74 # DW_TAG_skeleton_unit + .byte 0 # DW_CHILDREN_no + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 37 # DW_FORM_strx1 + .ascii "\264B" # DW_AT_GNU_pubnames + .byte 25 # DW_FORM_flag_present + .byte 118 # DW_AT_dwo_name + .byte 37 # DW_FORM_strx1 + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 85 # DW_AT_ranges + .byte 35 # DW_FORM_rnglistx + .byte 115 # DW_AT_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 116 # DW_AT_rnglists_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 4 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .quad 1354107878901449185 + .byte 1 # Abbrev [1] 0x14:0x1c DW_TAG_skeleton_unit + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .byte 0 # DW_AT_comp_dir + # DW_AT_GNU_pubnames + .byte 1 # DW_AT_dwo_name + .quad 0 # DW_AT_low_pc + .byte 0 # DW_AT_ranges + .long .Laddr_table_base0 # DW_AT_addr_base + .long .Lrnglists_table_base0 # DW_AT_rnglists_base +.Ldebug_info_end0: + .section .debug_rnglists,"",@progbits + .long .Ldebug_list_header_end0-.Ldebug_list_header_start0 # Length +.Ldebug_list_header_start0: + .short 5 # Version + .byte 8 # Address size + .byte 0 # Segment selector size + .long 1 # Offset entry count +.Lrnglists_table_base0: + .long .Ldebug_ranges4-.Lrnglists_table_base0 +.Ldebug_ranges4: + .byte 3 # DW_RLE_startx_length + .byte 0 # start index + .uleb128 .LBB_END0_1-_Z7doStuffi.__part.1 # length + .byte 3 # DW_RLE_startx_length + .byte 1 # start index + .uleb128 .LBB_END0_2-_Z7doStuffi.__part.2 # length + .byte 3 # DW_RLE_startx_length + .byte 2 # start index + .uleb128 .Lfunc_end0-.Lfunc_begin0 # length + .byte 3 # DW_RLE_startx_length + .byte 3 # start index + .uleb128 .Lfunc_end1-.Lfunc_begin1 # length + .byte 3 # DW_RLE_startx_length + .byte 4 # start index + .uleb128 .LBB_END2_1-main.__part.1 # length + .byte 3 # DW_RLE_startx_length + .byte 5 # start index + .uleb128 .LBB_END2_2-main.__part.2 # length + .byte 3 # DW_RLE_startx_length + .byte 6 # start index + .uleb128 .Lfunc_end2-.Lfunc_begin2 # length + .byte 0 # DW_RLE_end_of_list +.Ldebug_list_header_end0: + .section .debug_str_offsets,"",@progbits + .long 12 # Length of String Offsets Set + .short 5 + .short 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",@progbits,1 +.Lskel_string0: + .asciz "." # string offset=0 +.Lskel_string1: + .asciz "main.dwo" # string offset=38 + .section .debug_str_offsets,"",@progbits + .long .Lskel_string0 + .long .Lskel_string1 + .section .debug_str_offsets.dwo,"e",@progbits + .long 60 # Length of String Offsets Set + .short 5 + .short 0 + .section .debug_str.dwo,"eMS",@progbits,1 +.Linfo_string0: + .asciz "_Z7doStuffi" # string offset=0 +.Linfo_string1: + .asciz "doStuff" # string offset=12 +.Linfo_string2: + .asciz "int" # string offset=20 +.Linfo_string3: + .asciz "val" # string offset=24 +.Linfo_string4: + .asciz "_Z8doStuff2i" # string offset=28 +.Linfo_string5: + .asciz "doStuff2" # string offset=41 +.Linfo_string6: + .asciz "foo" # string offset=50 +.Linfo_string7: + .asciz "main" # string offset=54 +.Linfo_string8: + .asciz "argc" # string offset=59 +.Linfo_string9: + .asciz "argv" # string offset=64 +.Linfo_string10: + .asciz "char" # string offset=69 +.Linfo_string11: + .asciz "clang version 18.0.0 (git@github.com:llvm/llvm-project.git 3a8db0f4bfb57348f49d9603119fa157114bbf8e)" # string offset=74 +.Linfo_string12: + .asciz "main.cpp" # string offset=175 +.Linfo_string13: + .asciz "main.dwo" # string offset=184 + .section .debug_str_offsets.dwo,"e",@progbits + .long 0 + .long 12 + .long 20 + .long 24 + .long 28 + .long 41 + .long 50 + .long 54 + .long 59 + .long 64 + .long 69 + .long 74 + .long 175 + .long 184 + .section .debug_info.dwo,"e",@progbits + .long .Ldebug_info_dwo_end0-.Ldebug_info_dwo_start0 # Length of Unit +.Ldebug_info_dwo_start0: + .short 5 # DWARF version number + .byte 5 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long 0 # Offset Into Abbrev. Section + .quad 1354107878901449185 + .byte 1 # Abbrev [1] 0x14:0xc6 DW_TAG_compile_unit + .byte 11 # DW_AT_producer + .short 33 # DW_AT_language + .byte 12 # DW_AT_name + .byte 13 # DW_AT_dwo_name + .byte 2 # Abbrev [2] 0x1a:0x11 DW_TAG_subprogram + .byte 0 # DW_AT_ranges + .byte 1 # DW_AT_frame_base + .byte 86 + .long 72 # DW_AT_abstract_origin + .byte 3 # Abbrev [3] 0x22:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 81 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 4 # Abbrev [4] 0x2b:0x1d DW_TAG_subprogram + .byte 3 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .long 94 # DW_AT_abstract_origin + .byte 3 # Abbrev [3] 0x37:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 103 # DW_AT_abstract_origin + .byte 5 # Abbrev [5] 0x3f:0x8 DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .long 111 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 6 # Abbrev [6] 0x48:0x12 DW_TAG_subprogram + .byte 0 # DW_AT_linkage_name + .byte 1 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long 90 # DW_AT_type + # DW_AT_external + # DW_AT_inline + .byte 7 # Abbrev [7] 0x51:0x8 DW_TAG_formal_parameter + .byte 3 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long 90 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 8 # Abbrev [8] 0x5a:0x4 DW_TAG_base_type + .byte 2 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 6 # Abbrev [6] 0x5e:0x1a DW_TAG_subprogram + .byte 4 # DW_AT_linkage_name + .byte 5 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + .long 90 # DW_AT_type + # DW_AT_external + # DW_AT_inline + .byte 7 # Abbrev [7] 0x67:0x8 DW_TAG_formal_parameter + .byte 3 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + .long 90 # DW_AT_type + .byte 9 # Abbrev [9] 0x6f:0x8 DW_TAG_variable + .byte 6 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 9 # DW_AT_decl_line + .long 90 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 10 # Abbrev [10] 0x78:0x4e DW_TAG_subprogram + .byte 1 # DW_AT_ranges + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 7 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 90 # DW_AT_type + # DW_AT_external + .byte 11 # Abbrev [11] 0x83:0xb DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 108 + .byte 8 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 90 # DW_AT_type + .byte 11 # Abbrev [11] 0x8e:0xb DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 96 + .byte 9 # DW_AT_name + .byte 0 # DW_AT_decl_file + .byte 14 # DW_AT_decl_line + .long 198 # DW_AT_type + .byte 12 # Abbrev [12] 0x99:0x12 DW_TAG_inlined_subroutine + .long 72 # DW_AT_abstract_origin + .byte 2 # DW_AT_ranges + .byte 0 # DW_AT_call_file + .byte 15 # DW_AT_call_line + .byte 13 # DW_AT_call_column + .byte 3 # Abbrev [3] 0xa2:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 116 + .long 81 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 12 # Abbrev [12] 0xab:0x1a DW_TAG_inlined_subroutine + .long 94 # DW_AT_abstract_origin + .byte 3 # DW_AT_ranges + .byte 0 # DW_AT_call_file + .byte 15 # DW_AT_call_line + .byte 29 # DW_AT_call_column + .byte 3 # Abbrev [3] 0xb4:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 103 # DW_AT_abstract_origin + .byte 5 # Abbrev [5] 0xbc:0x8 DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .long 111 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 13 # Abbrev [13] 0xc6:0x5 DW_TAG_pointer_type + .long 203 # DW_AT_type + .byte 13 # Abbrev [13] 0xcb:0x5 DW_TAG_pointer_type + .long 208 # DW_AT_type + .byte 14 # Abbrev [14] 0xd0:0x5 DW_TAG_const_type + .long 213 # DW_AT_type + .byte 8 # Abbrev [8] 0xd5:0x4 DW_TAG_base_type + .byte 10 # DW_AT_name + .byte 6 # DW_AT_encoding + .byte 1 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_dwo_end0: + .section .debug_abbrev.dwo,"e",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 37 # DW_FORM_strx1 + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 118 # DW_AT_dwo_name + .byte 37 # DW_FORM_strx1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 85 # DW_AT_ranges + .byte 35 # DW_FORM_rnglistx + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 110 # DW_AT_linkage_name + .byte 37 # DW_FORM_strx1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 32 # DW_AT_inline + .byte 33 # DW_FORM_implicit_const + .byte 1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 8 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 9 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 10 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 85 # DW_AT_ranges + .byte 35 # DW_FORM_rnglistx + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 11 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 12 # Abbreviation Code + .byte 29 # DW_TAG_inlined_subroutine + .byte 1 # DW_CHILDREN_yes + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 85 # DW_AT_ranges + .byte 35 # DW_FORM_rnglistx + .byte 88 # DW_AT_call_file + .byte 11 # DW_FORM_data1 + .byte 89 # DW_AT_call_line + .byte 11 # DW_FORM_data1 + .byte 87 # DW_AT_call_column + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 13 # Abbreviation Code + .byte 15 # DW_TAG_pointer_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 14 # Abbreviation Code + .byte 38 # DW_TAG_const_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_rnglists.dwo,"e",@progbits + .long .Ldebug_list_header_end1-.Ldebug_list_header_start1 # Length +.Ldebug_list_header_start1: + .short 5 # Version + .byte 8 # Address size + .byte 0 # Segment selector size + .long 4 # Offset entry count +.Lrnglists_dwo_table_base0: + .long .Ldebug_ranges0-.Lrnglists_dwo_table_base0 + .long .Ldebug_ranges1-.Lrnglists_dwo_table_base0 + .long .Ldebug_ranges2-.Lrnglists_dwo_table_base0 + .long .Ldebug_ranges3-.Lrnglists_dwo_table_base0 +.Ldebug_ranges0: + .byte 3 # DW_RLE_startx_length + .byte 0 # start index + .uleb128 .LBB_END0_1-_Z7doStuffi.__part.1 # length + .byte 3 # DW_RLE_startx_length + .byte 1 # start index + .uleb128 .LBB_END0_2-_Z7doStuffi.__part.2 # length + .byte 3 # DW_RLE_startx_length + .byte 2 # start index + .uleb128 .Lfunc_end0-.Lfunc_begin0 # length + .byte 0 # DW_RLE_end_of_list +.Ldebug_ranges1: + .byte 3 # DW_RLE_startx_length + .byte 4 # start index + .uleb128 .LBB_END2_1-main.__part.1 # length + .byte 3 # DW_RLE_startx_length + .byte 5 # start index + .uleb128 .LBB_END2_2-main.__part.2 # length + .byte 3 # DW_RLE_startx_length + .byte 6 # start index + .uleb128 .Lfunc_end2-.Lfunc_begin2 # length + .byte 0 # DW_RLE_end_of_list +.Ldebug_ranges2: + .byte 1 # DW_RLE_base_addressx + .byte 6 # base address index + .byte 4 # DW_RLE_offset_pair + .uleb128 .Ltmp4-.Lfunc_begin2 # starting offset + .uleb128 .Lfunc_end2-.Lfunc_begin2 # ending offset + .byte 3 # DW_RLE_startx_length + .byte 4 # start index + .uleb128 .LBB_END2_1-main.__part.1 # length + .byte 3 # DW_RLE_startx_length + .byte 5 # start index + .uleb128 .Ltmp6-main.__part.2 # length + .byte 0 # DW_RLE_end_of_list +.Ldebug_ranges3: + .byte 1 # DW_RLE_base_addressx + .byte 5 # base address index + .byte 4 # DW_RLE_offset_pair + .uleb128 .Ltmp7-main.__part.2 # starting offset + .uleb128 .Ltmp8-main.__part.2 # ending offset + .byte 0 # DW_RLE_end_of_list +.Ldebug_list_header_end1: + .section .debug_addr,"",@progbits + .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution +.Ldebug_addr_start0: + .short 5 # DWARF version number + .byte 8 # Address size + .byte 0 # Segment selector size +.Laddr_table_base0: + .quad _Z7doStuffi.__part.1 + .quad _Z7doStuffi.__part.2 + .quad .Lfunc_begin0 + .quad .Lfunc_begin1 + .quad main.__part.1 + .quad main.__part.2 + .quad .Lfunc_begin2 +.Ldebug_addr_end0: + .section .debug_gnu_pubnames,"",@progbits + .long .LpubNames_end0-.LpubNames_start0 # Length of Public Names Info +.LpubNames_start0: + .short 2 # DWARF Version + .long .Lcu_begin0 # Offset of Compilation Unit Info + .long 48 # Compilation Unit Length + .long 72 # DIE offset + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "doStuff" # External Name + .long 94 # DIE offset + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "doStuff2" # External Name + .long 120 # DIE offset + .byte 48 # Attributes: FUNCTION, EXTERNAL + .asciz "main" # External Name + .long 0 # End Mark +.LpubNames_end0: + .section .debug_gnu_pubtypes,"",@progbits + .long .LpubTypes_end0-.LpubTypes_start0 # Length of Public Types Info +.LpubTypes_start0: + .short 2 # DWARF Version + .long .Lcu_begin0 # Offset of Compilation Unit Info + .long 48 # Compilation Unit Length + .long 90 # DIE offset + .byte 144 # Attributes: TYPE, STATIC + .asciz "int" # External Name + .long 213 # DIE offset + .byte 144 # Attributes: TYPE, STATIC + .asciz "char" # External Name + .long 0 # End Mark +.LpubTypes_end0: + .ident "clang version 18.0.0 (git@github.com:llvm/llvm-project.git 3a8db0f4bfb57348f49d9603119fa157114bbf8e)" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/dwarf4-df-input-lowpc-ranges.test b/bolt/test/X86/dwarf4-df-input-lowpc-ranges.test new file mode 100644 --- /dev/null +++ b/bolt/test/X86/dwarf4-df-input-lowpc-ranges.test @@ -0,0 +1,56 @@ +; RUN: rm -rf %t +; RUN: mkdir %t +; RUN: cd %t +;; RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-df-input-lowpc-ranges-main.s \ +; RUN: -split-dwarf-file=main.dwo -o main.o +; RUN: %clang %cflags -gdwarf-4 -gsplit-dwarf=split main.o -o main.exe +; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections +; RUN: llvm-dwarfdump --show-form --verbose --debug-ranges main.exe.bolt &> %t/foo.txt +; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt >> %t/foo.txt +; RUN: cat %t/foo.txt | FileCheck -check-prefix=BOLT %s +; RUN: not llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo &> %t/mainddwodwo.txt +; RUN: cat %t/mainddwodwo.txt | FileCheck -check-prefix=BOLT-DWO-MAIN %s + +; Tests BOLT handles correctly Skeleton CU which has DW_AT_low_pc/DW_AT_ranges as input. + +; BOLT: .debug_ranges +; BOLT-NEXT: 00000000 +; BOLT-NEXT: 00000010 +; BOLT-NEXT: 00000010 +; BOLT-NEXT: 00000010 +; BOLT-NEXT: 00000010 +; BOLT-NEXT: 00000050 +; BOLT-NEXT: 00000050 +; BOLT-NEXT: 00000050 +; BOLT-NEXT: 00000050 +; BOLT-NEXT: 00000090 [[#%.16x,ADDR1:]] [[#%.16x,ADDRB1:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR2:]] [[#%.16x,ADDRB2:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR3:]] [[#%.16x,ADDRB3:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR4:]] [[#%.16x,ADDRB4:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR5:]] [[#%.16x,ADDRB5:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR6:]] [[#%.16x,ADDRB6:]] +; BOLT-NEXT: 00000090 [[#%.16x,ADDR7:]] [[#%.16x,ADDRB7:]] +; BOLT-NEXT: 00000090 + +; BOLT: DW_TAG_compile_unit +; BOLT: DW_AT_GNU_dwo_name [DW_FORM_strp] ( .debug_str[0x{{[0-9a-fA-F]+}}] = "main.dwo.dwo") +; BOLT-NEXT: DW_AT_GNU_dwo_id +; BOLT-NEXT: DW_AT_GNU_ranges_base [DW_FORM_sec_offset] (0x00000010) +; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) +; BOLT-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000090 +; BOLT-NEXT: [0x[[#ADDR1]], 0x[[#ADDRB1]]) +; BOLT-NEXT: [0x[[#ADDR2]], 0x[[#ADDRB2]]) +; BOLT-NEXT: [0x[[#ADDR3]], 0x[[#ADDRB3]]) +; BOLT-NEXT: [0x[[#ADDR4]], 0x[[#ADDRB4]]) +; BOLT-NEXT: [0x[[#ADDR5]], 0x[[#ADDRB5]]) +; BOLT-NEXT: [0x[[#ADDR6]], 0x[[#ADDRB6]]) +; BOLT-NEXT: [0x[[#ADDR7]], 0x[[#ADDRB7]]) +; BOLT-NEXT: DW_AT_GNU_addr_base [DW_FORM_sec_offset] (0x00000000) + +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000 +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000040 diff --git a/bolt/test/X86/dwarf5-df-input-lowpc-ranges.test b/bolt/test/X86/dwarf5-df-input-lowpc-ranges.test new file mode 100644 --- /dev/null +++ b/bolt/test/X86/dwarf5-df-input-lowpc-ranges.test @@ -0,0 +1,51 @@ +; RUN: rm -rf %t +; RUN: mkdir %t +; RUN: cd %t +;; RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-df-input-lowpc-ranges-main.s \ +; RUN: -split-dwarf-file=main.dwo -o main.o +; RUN: %clang %cflags -gdwarf-4 -gsplit-dwarf=split main.o -o main.exe +; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections +; RUN: llvm-dwarfdump --show-form --verbose --debug-rnglists main.exe.bolt &> %t/foo.txt +; RUN: llvm-dwarfdump --show-form --verbose --debug-addr main.exe.bolt >> %t/foo.txt +; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt >> %t/foo.txt +; RUN: cat %t/foo.txt | FileCheck -check-prefix=BOLT %s +; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo.dwo &> %t/mainddwodwo.txt +; RUN: cat %t/mainddwodwo.txt | FileCheck -check-prefix=BOLT-DWO-MAIN %s + +; Tests BOLT handles correctly Skeleton CU which has DW_AT_low_pc/DW_AT_ranges as input. + +; BOLT: Addrs: [ +; BOLT-NEXT: 0x[[#%.16x,ADDR1:]] +; BOLT-NEXT: 0x[[#%.16x,ADDR2:]] +; BOLT-NEXT: 0x[[#%.16x,ADDR3:]] +; BOLT-NEXT: 0x[[#%.16x,ADDR4:]] +; BOLT-NEXT: 0x[[#%.16x,ADDR5:]] + + +; BOLT: DW_TAG_skeleton_unit +; BOLT: DW_AT_dwo_name [DW_FORM_strx1] (indexed (00000001) string = "main.dwo.dwo") +; BOLT-NEXT: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) +; BOLT-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = 0x00000010 +; BOLT-NEXT: [0x[[#ADDR1]], 0x[[#ADDR1 + 0x16]]) +; BOLT-NEXT: [0x[[#ADDR1 + 0x16]], 0x[[#ADDR1 + 0x24]]) +; BOLT-NEXT: [0x[[#ADDR1 + 0x24]], 0x[[#ADDR1 + 0x29]]) +; BOLT-NEXT: [0x[[#ADDR1 + 0x30]], 0x[[#ADDR1 + 0x46]]) +; BOLT-NEXT: [0x[[#ADDR1 + 0x50]], 0x[[#ADDR1 + 0x77]]) +; BOLT-NEXT: [0x[[#ADDR1 + 0x77]], 0x[[#ADDR1 + 0x85]]) +; BOLT-NEXT: [0x[[#ADDR1 + 0x85]], 0x[[#ADDR1 + 0x9f]]) +; BOLT-NEXT: DW_AT_addr_base [DW_FORM_sec_offset] (0x00000008) +; BOLT-NEXT: DW_AT_rnglists_base [DW_FORM_sec_offset] (0x0000000c) + +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x0) rangelist = 0x00000014 +; BOLT-DWO-MAIN-NEXT: [0x0000000000000000, 0x0000000000000016) +; BOLT-DWO-MAIN-NEXT: [0x0000000000000016, 0x0000000000000024) +; BOLT-DWO-MAIN-NEXT: [0x0000000000000024, 0x0000000000000029)) +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN: DW_TAG_subprogram +; BOLT-DWO-MAIN-NEXT: DW_AT_ranges [DW_FORM_rnglistx] (indexed (0x1) rangelist = 0x00000020 +; BOLT-DWO-MAIN-NEXT: [0x0000000000000002, 0x0000000000000029) +; BOLT-DWO-MAIN-NEXT: [0x0000000000000029, 0x0000000000000037) +; BOLT-DWO-MAIN-NEXT: [0x0000000000000037, 0x0000000000000051))