//===- DwarfStreamer.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/DWARFLinker/Classic/DWARFStreamer.h" #include "llvm/CodeGen/NonRelocatableStringpool.h" #include "llvm/DWARFLinker/Classic/DWARFLinkerCompileUnit.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/MC/MCTargetOptionsCommandFlags.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/LEB128.h" #include "llvm/Target/TargetOptions.h" #include "llvm/TargetParser/Triple.h" using namespace llvm; using namespace dwarf_linker; using namespace dwarf_linker::classic; Expected> DwarfStreamer::createStreamer( const Triple &TheTriple, DWARFLinkerBase::OutputFileType FileType, raw_pwrite_stream &OutFile, DWARFLinkerBase::MessageHandlerTy Warning) { std::unique_ptr Streamer = std::make_unique(FileType, OutFile, Warning); if (Error Err = Streamer->init(TheTriple, "__DWARF")) return std::move(Err); return std::move(Streamer); } Error DwarfStreamer::init(Triple TheTriple, StringRef Swift5ReflectionSegmentName) { std::string ErrorStr; std::string TripleName; // Get the target. const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr); if (!TheTarget) return createStringError(std::errc::invalid_argument, ErrorStr.c_str()); TripleName = TheTriple.getTriple(); // Create all the MC Objects. MRI.reset(TheTarget->createMCRegInfo(TripleName)); if (!MRI) return createStringError(std::errc::invalid_argument, "no register info for target %s", TripleName.c_str()); MCTargetOptions MCOptions = mc::InitMCTargetOptionsFromFlags(); MCOptions.AsmVerbose = true; MCOptions.MCUseDwarfDirectory = MCTargetOptions::EnableDwarfDirectory; MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions)); if (!MAI) return createStringError(std::errc::invalid_argument, "no asm info for target %s", TripleName.c_str()); MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", "")); if (!MSTI) return createStringError(std::errc::invalid_argument, "no subtarget info for target %s", TripleName.c_str()); MC.reset(new MCContext(TheTriple, MAI.get(), MRI.get(), MSTI.get(), nullptr, nullptr, true, Swift5ReflectionSegmentName)); MOFI.reset(TheTarget->createMCObjectFileInfo(*MC, /*PIC=*/false, false)); MC->setObjectFileInfo(MOFI.get()); MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, MCOptions); if (!MAB) return createStringError(std::errc::invalid_argument, "no asm backend for target %s", TripleName.c_str()); MII.reset(TheTarget->createMCInstrInfo()); if (!MII) return createStringError(std::errc::invalid_argument, "no instr info info for target %s", TripleName.c_str()); MCE = TheTarget->createMCCodeEmitter(*MII, *MC); if (!MCE) return createStringError(std::errc::invalid_argument, "no code emitter for target %s", TripleName.c_str()); switch (OutFileType) { case DWARFLinker::OutputFileType::Assembly: { MIP = TheTarget->createMCInstPrinter(TheTriple, MAI->getAssemblerDialect(), *MAI, *MII, *MRI); MS = TheTarget->createAsmStreamer( *MC, std::make_unique(OutFile), MIP, std::unique_ptr(MCE), std::unique_ptr(MAB)); break; } case DWARFLinker::OutputFileType::Object: { MS = TheTarget->createMCObjectStreamer( TheTriple, *MC, std::unique_ptr(MAB), MAB->createObjectWriter(OutFile), std::unique_ptr(MCE), *MSTI); break; } } if (!MS) return createStringError(std::errc::invalid_argument, "no object streamer for target %s", TripleName.c_str()); // Finally create the AsmPrinter we'll use to emit the DIEs. TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(), std::nullopt)); if (!TM) return createStringError(std::errc::invalid_argument, "no target machine for target %s", TripleName.c_str()); Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr(MS))); if (!Asm) return createStringError(std::errc::invalid_argument, "no asm printer for target %s", TripleName.c_str()); Asm->setDwarfUsesRelocationsAcrossSections(false); RangesSectionSize = 0; RngListsSectionSize = 0; LocSectionSize = 0; LocListsSectionSize = 0; LineSectionSize = 0; FrameSectionSize = 0; DebugInfoSectionSize = 0; MacInfoSectionSize = 0; MacroSectionSize = 0; return Error::success(); } void DwarfStreamer::finish() { MS->finish(); } void DwarfStreamer::switchToDebugInfoSection(unsigned DwarfVersion) { MS->switchSection(MOFI->getDwarfInfoSection()); MC->setDwarfVersion(DwarfVersion); } /// Emit the compilation unit header for \p Unit in the debug_info section. /// /// A Dwarf 4 section header is encoded as: /// uint32_t Unit length (omitting this field) /// uint16_t Version /// uint32_t Abbreviation table offset /// uint8_t Address size /// Leading to a total of 11 bytes. /// /// A Dwarf 5 section header is encoded as: /// uint32_t Unit length (omitting this field) /// uint16_t Version /// uint8_t Unit type /// uint8_t Address size /// uint32_t Abbreviation table offset /// Leading to a total of 12 bytes. void DwarfStreamer::emitCompileUnitHeader(CompileUnit &Unit, unsigned DwarfVersion) { switchToDebugInfoSection(DwarfVersion); /// The start of the unit within its section. Unit.setLabelBegin(Asm->createTempSymbol("cu_begin")); Asm->OutStreamer->emitLabel(Unit.getLabelBegin()); // Emit size of content not including length itself. The size has already // been computed in CompileUnit::computeOffsets(). Subtract 4 to that size to // account for the length field. Asm->emitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset() - 4); Asm->emitInt16(DwarfVersion); if (DwarfVersion >= 5) { Asm->emitInt8(dwarf::DW_UT_compile); Asm->emitInt8(Unit.getOrigUnit().getAddressByteSize()); // We share one abbreviations table across all units so it's always at the // start of the section. Asm->emitInt32(0); DebugInfoSectionSize += 12; } else { // We share one abbreviations table across all units so it's always at the // start of the section. Asm->emitInt32(0); Asm->emitInt8(Unit.getOrigUnit().getAddressByteSize()); DebugInfoSectionSize += 11; } // Remember this CU. EmittedUnits.push_back({Unit.getUniqueID(), Unit.getLabelBegin()}); } /// Emit the \p Abbrevs array as the shared abbreviation table /// for the linked Dwarf file. void DwarfStreamer::emitAbbrevs( const std::vector> &Abbrevs, unsigned DwarfVersion) { MS->switchSection(MOFI->getDwarfAbbrevSection()); MC->setDwarfVersion(DwarfVersion); Asm->emitDwarfAbbrevs(Abbrevs); } /// Recursively emit the DIE tree rooted at \p Die. void DwarfStreamer::emitDIE(DIE &Die) { MS->switchSection(MOFI->getDwarfInfoSection()); Asm->emitDwarfDIE(Die); DebugInfoSectionSize += Die.getSize(); } /// Emit contents of section SecName From Obj. void DwarfStreamer::emitSectionContents(StringRef SecData, DebugSectionKind SecKind) { if (SecData.empty()) return; if (MCSection *Section = getMCSection(SecKind)) { MS->switchSection(Section); MS->emitBytes(SecData); } } MCSection *DwarfStreamer::getMCSection(DebugSectionKind SecKind) { switch (SecKind) { case DebugSectionKind::DebugInfo: return MC->getObjectFileInfo()->getDwarfInfoSection(); case DebugSectionKind::DebugLine: return MC->getObjectFileInfo()->getDwarfLineSection(); case DebugSectionKind::DebugFrame: return MC->getObjectFileInfo()->getDwarfFrameSection(); case DebugSectionKind::DebugRange: return MC->getObjectFileInfo()->getDwarfRangesSection(); case DebugSectionKind::DebugRngLists: return MC->getObjectFileInfo()->getDwarfRnglistsSection(); case DebugSectionKind::DebugLoc: return MC->getObjectFileInfo()->getDwarfLocSection(); case DebugSectionKind::DebugLocLists: return MC->getObjectFileInfo()->getDwarfLoclistsSection(); case DebugSectionKind::DebugARanges: return MC->getObjectFileInfo()->getDwarfARangesSection(); case DebugSectionKind::DebugAbbrev: return MC->getObjectFileInfo()->getDwarfAbbrevSection(); case DebugSectionKind::DebugMacinfo: return MC->getObjectFileInfo()->getDwarfMacinfoSection(); case DebugSectionKind::DebugMacro: return MC->getObjectFileInfo()->getDwarfMacroSection(); case DebugSectionKind::DebugAddr: return MC->getObjectFileInfo()->getDwarfAddrSection(); case DebugSectionKind::DebugStr: return MC->getObjectFileInfo()->getDwarfStrSection(); case DebugSectionKind::DebugLineStr: return MC->getObjectFileInfo()->getDwarfLineStrSection(); case DebugSectionKind::DebugStrOffsets: return MC->getObjectFileInfo()->getDwarfStrOffSection(); case DebugSectionKind::DebugPubNames: return MC->getObjectFileInfo()->getDwarfPubNamesSection(); case DebugSectionKind::DebugPubTypes: return MC->getObjectFileInfo()->getDwarfPubTypesSection(); case DebugSectionKind::DebugNames: return MC->getObjectFileInfo()->getDwarfDebugNamesSection(); case DebugSectionKind::AppleNames: return MC->getObjectFileInfo()->getDwarfAccelNamesSection(); case DebugSectionKind::AppleNamespaces: return MC->getObjectFileInfo()->getDwarfAccelNamespaceSection(); case DebugSectionKind::AppleObjC: return MC->getObjectFileInfo()->getDwarfAccelObjCSection(); case DebugSectionKind::AppleTypes: return MC->getObjectFileInfo()->getDwarfAccelTypesSection(); case DebugSectionKind::NumberOfEnumEntries: llvm_unreachable("Unknown DebugSectionKind value"); break; } return nullptr; } /// Emit the debug_str section stored in \p Pool. void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) { Asm->OutStreamer->switchSection(MOFI->getDwarfStrSection()); std::vector Entries = Pool.getEntriesForEmission(); for (auto Entry : Entries) { // Emit the string itself. Asm->OutStreamer->emitBytes(Entry.getString()); // Emit a null terminator. Asm->emitInt8(0); } } /// Emit the debug string offset table described by \p StringOffsets into the /// .debug_str_offsets table. void DwarfStreamer::emitStringOffsets( const SmallVector &StringOffsets, uint16_t TargetDWARFVersion) { if (TargetDWARFVersion < 5 || StringOffsets.empty()) return; Asm->OutStreamer->switchSection(MOFI->getDwarfStrOffSection()); MCSymbol *BeginLabel = Asm->createTempSymbol("Bdebugstroff"); MCSymbol *EndLabel = Asm->createTempSymbol("Edebugstroff"); // Length. Asm->emitLabelDifference(EndLabel, BeginLabel, sizeof(uint32_t)); Asm->OutStreamer->emitLabel(BeginLabel); StrOffsetSectionSize += sizeof(uint32_t); // Version. MS->emitInt16(5); StrOffsetSectionSize += sizeof(uint16_t); // Padding. MS->emitInt16(0); StrOffsetSectionSize += sizeof(uint16_t); for (auto Off : StringOffsets) { Asm->OutStreamer->emitInt32(Off); StrOffsetSectionSize += sizeof(uint32_t); } Asm->OutStreamer->emitLabel(EndLabel); } /// Emit the debug_line_str section stored in \p Pool. void DwarfStreamer::emitLineStrings(const NonRelocatableStringpool &Pool) { Asm->OutStreamer->switchSection(MOFI->getDwarfLineStrSection()); std::vector Entries = Pool.getEntriesForEmission(); for (auto Entry : Entries) { // Emit the string itself. Asm->OutStreamer->emitBytes(Entry.getString()); // Emit a null terminator. Asm->emitInt8(0); } } void DwarfStreamer::emitDebugNames(DWARF5AccelTable &Table) { if (EmittedUnits.empty()) return; // Build up data structures needed to emit this section. std::vector> CompUnits; DenseMap UniqueIdToCuMap; unsigned Id = 0; for (auto &CU : EmittedUnits) { CompUnits.push_back(CU.LabelBegin); // We might be omitting CUs, so we need to remap them. UniqueIdToCuMap[CU.ID] = Id++; } Asm->OutStreamer->switchSection(MOFI->getDwarfDebugNamesSection()); dwarf::Form Form = DIEInteger::BestForm(/*IsSigned*/ false, (uint64_t)UniqueIdToCuMap.size() - 1); /// llvm-dwarfutil doesn't support type units + .debug_names right now. // FIXME: add support for type units + .debug_names. For now the behavior is // unsuported. emitDWARF5AccelTable( Asm.get(), Table, CompUnits, [&](const DWARF5AccelTableData &Entry) -> std::optional { if (UniqueIdToCuMap.size() > 1) return {{UniqueIdToCuMap[Entry.getUnitID()], {dwarf::DW_IDX_compile_unit, Form}}}; return std::nullopt; }); } void DwarfStreamer::emitAppleNamespaces( AccelTable &Table) { Asm->OutStreamer->switchSection(MOFI->getDwarfAccelNamespaceSection()); auto *SectionBegin = Asm->createTempSymbol("namespac_begin"); Asm->OutStreamer->emitLabel(SectionBegin); emitAppleAccelTable(Asm.get(), Table, "namespac", SectionBegin); } void DwarfStreamer::emitAppleNames( AccelTable &Table) { Asm->OutStreamer->switchSection(MOFI->getDwarfAccelNamesSection()); auto *SectionBegin = Asm->createTempSymbol("names_begin"); Asm->OutStreamer->emitLabel(SectionBegin); emitAppleAccelTable(Asm.get(), Table, "names", SectionBegin); } void DwarfStreamer::emitAppleObjc( AccelTable &Table) { Asm->OutStreamer->switchSection(MOFI->getDwarfAccelObjCSection()); auto *SectionBegin = Asm->createTempSymbol("objc_begin"); Asm->OutStreamer->emitLabel(SectionBegin); emitAppleAccelTable(Asm.get(), Table, "objc", SectionBegin); } void DwarfStreamer::emitAppleTypes( AccelTable &Table) { Asm->OutStreamer->switchSection(MOFI->getDwarfAccelTypesSection()); auto *SectionBegin = Asm->createTempSymbol("types_begin"); Asm->OutStreamer->emitLabel(SectionBegin); emitAppleAccelTable(Asm.get(), Table, "types", SectionBegin); } /// Emit the swift_ast section stored in \p Buffers. void DwarfStreamer::emitSwiftAST(StringRef Buffer) { MCSection *SwiftASTSection = MOFI->getDwarfSwiftASTSection(); SwiftASTSection->setAlignment(Align(32)); MS->switchSection(SwiftASTSection); MS->emitBytes(Buffer); } void DwarfStreamer::emitSwiftReflectionSection( llvm::binaryformat::Swift5ReflectionSectionKind ReflSectionKind, StringRef Buffer, uint32_t Alignment, uint32_t Size) { MCSection *ReflectionSection = MOFI->getSwift5ReflectionSection(ReflSectionKind); if (ReflectionSection == nullptr) return; ReflectionSection->setAlignment(Align(Alignment)); MS->switchSection(ReflectionSection); MS->emitBytes(Buffer); } void DwarfStreamer::emitDwarfDebugArangesTable( const CompileUnit &Unit, const AddressRanges &LinkedRanges) { unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); // Make .debug_aranges to be current section. MS->switchSection(MC->getObjectFileInfo()->getDwarfARangesSection()); // Emit Header. MCSymbol *BeginLabel = Asm->createTempSymbol("Barange"); MCSymbol *EndLabel = Asm->createTempSymbol("Earange"); unsigned HeaderSize = sizeof(int32_t) + // Size of contents (w/o this field sizeof(int16_t) + // DWARF ARange version number sizeof(int32_t) + // Offset of CU in the .debug_info section sizeof(int8_t) + // Pointer Size (in bytes) sizeof(int8_t); // Segment Size (in bytes) unsigned TupleSize = AddressSize * 2; unsigned Padding = offsetToAlignment(HeaderSize, Align(TupleSize)); Asm->emitLabelDifference(EndLabel, BeginLabel, 4); // Arange length Asm->OutStreamer->emitLabel(BeginLabel); Asm->emitInt16(dwarf::DW_ARANGES_VERSION); // Version number Asm->emitInt32(Unit.getStartOffset()); // Corresponding unit's offset Asm->emitInt8(AddressSize); // Address size Asm->emitInt8(0); // Segment size Asm->OutStreamer->emitFill(Padding, 0x0); // Emit linked ranges. for (const AddressRange &Range : LinkedRanges) { MS->emitIntValue(Range.start(), AddressSize); MS->emitIntValue(Range.end() - Range.start(), AddressSize); } // Emit terminator. Asm->OutStreamer->emitIntValue(0, AddressSize); Asm->OutStreamer->emitIntValue(0, AddressSize); Asm->OutStreamer->emitLabel(EndLabel); } void DwarfStreamer::emitDwarfDebugRangesTableFragment( const CompileUnit &Unit, const AddressRanges &LinkedRanges, PatchLocation Patch) { Patch.set(RangesSectionSize); // Make .debug_ranges to be current section. MS->switchSection(MC->getObjectFileInfo()->getDwarfRangesSection()); unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); // Emit ranges. uint64_t BaseAddress = 0; if (std::optional LowPC = Unit.getLowPc()) BaseAddress = *LowPC; for (const AddressRange &Range : LinkedRanges) { MS->emitIntValue(Range.start() - BaseAddress, AddressSize); MS->emitIntValue(Range.end() - BaseAddress, AddressSize); RangesSectionSize += AddressSize; RangesSectionSize += AddressSize; } // Add the terminator entry. MS->emitIntValue(0, AddressSize); MS->emitIntValue(0, AddressSize); RangesSectionSize += AddressSize; RangesSectionSize += AddressSize; } MCSymbol * DwarfStreamer::emitDwarfDebugRangeListHeader(const CompileUnit &Unit) { if (Unit.getOrigUnit().getVersion() < 5) return nullptr; // Make .debug_rnglists to be current section. MS->switchSection(MC->getObjectFileInfo()->getDwarfRnglistsSection()); MCSymbol *BeginLabel = Asm->createTempSymbol("Brnglists"); MCSymbol *EndLabel = Asm->createTempSymbol("Ernglists"); unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); // Length Asm->emitLabelDifference(EndLabel, BeginLabel, sizeof(uint32_t)); Asm->OutStreamer->emitLabel(BeginLabel); RngListsSectionSize += sizeof(uint32_t); // Version. MS->emitInt16(5); RngListsSectionSize += sizeof(uint16_t); // Address size. MS->emitInt8(AddressSize); RngListsSectionSize++; // Seg_size MS->emitInt8(0); RngListsSectionSize++; // Offset entry count MS->emitInt32(0); RngListsSectionSize += sizeof(uint32_t); return EndLabel; } void DwarfStreamer::emitDwarfDebugRangeListFragment( const CompileUnit &Unit, const AddressRanges &LinkedRanges, PatchLocation Patch, DebugDieValuePool &AddrPool) { if (Unit.getOrigUnit().getVersion() < 5) { emitDwarfDebugRangesTableFragment(Unit, LinkedRanges, Patch); return; } emitDwarfDebugRngListsTableFragment(Unit, LinkedRanges, Patch, AddrPool); } void DwarfStreamer::emitDwarfDebugRangeListFooter(const CompileUnit &Unit, MCSymbol *EndLabel) { if (Unit.getOrigUnit().getVersion() < 5) return; // Make .debug_rnglists to be current section. MS->switchSection(MC->getObjectFileInfo()->getDwarfRnglistsSection()); if (EndLabel != nullptr) Asm->OutStreamer->emitLabel(EndLabel); } void DwarfStreamer::emitDwarfDebugRngListsTableFragment( const CompileUnit &Unit, const AddressRanges &LinkedRanges, PatchLocation Patch, DebugDieValuePool &AddrPool) { Patch.set(RngListsSectionSize); // Make .debug_rnglists to be current section. MS->switchSection(MC->getObjectFileInfo()->getDwarfRnglistsSection()); std::optional BaseAddress; for (const AddressRange &Range : LinkedRanges) { if (!BaseAddress) { BaseAddress = Range.start(); // Emit base address. MS->emitInt8(dwarf::DW_RLE_base_addressx); RngListsSectionSize += 1; RngListsSectionSize += MS->emitULEB128IntValue(AddrPool.getValueIndex(*BaseAddress)); } // Emit type of entry. MS->emitInt8(dwarf::DW_RLE_offset_pair); RngListsSectionSize += 1; // Emit start offset relative to base address. RngListsSectionSize += MS->emitULEB128IntValue(Range.start() - *BaseAddress); // Emit end offset relative to base address. RngListsSectionSize += MS->emitULEB128IntValue(Range.end() - *BaseAddress); } // Emit the terminator entry. MS->emitInt8(dwarf::DW_RLE_end_of_list); RngListsSectionSize += 1; } /// Emit debug locations(.debug_loc, .debug_loclists) header. MCSymbol *DwarfStreamer::emitDwarfDebugLocListHeader(const CompileUnit &Unit) { if (Unit.getOrigUnit().getVersion() < 5) return nullptr; // Make .debug_loclists the current section. MS->switchSection(MC->getObjectFileInfo()->getDwarfLoclistsSection()); MCSymbol *BeginLabel = Asm->createTempSymbol("Bloclists"); MCSymbol *EndLabel = Asm->createTempSymbol("Eloclists"); unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); // Length Asm->emitLabelDifference(EndLabel, BeginLabel, sizeof(uint32_t)); Asm->OutStreamer->emitLabel(BeginLabel); LocListsSectionSize += sizeof(uint32_t); // Version. MS->emitInt16(5); LocListsSectionSize += sizeof(uint16_t); // Address size. MS->emitInt8(AddressSize); LocListsSectionSize++; // Seg_size MS->emitInt8(0); LocListsSectionSize++; // Offset entry count MS->emitInt32(0); LocListsSectionSize += sizeof(uint32_t); return EndLabel; } /// Emit debug locations(.debug_loc, .debug_loclists) fragment. void DwarfStreamer::emitDwarfDebugLocListFragment( const CompileUnit &Unit, const DWARFLocationExpressionsVector &LinkedLocationExpression, PatchLocation Patch, DebugDieValuePool &AddrPool) { if (Unit.getOrigUnit().getVersion() < 5) { emitDwarfDebugLocTableFragment(Unit, LinkedLocationExpression, Patch); return; } emitDwarfDebugLocListsTableFragment(Unit, LinkedLocationExpression, Patch, AddrPool); } /// Emit debug locations(.debug_loc, .debug_loclists) footer. void DwarfStreamer::emitDwarfDebugLocListFooter(const CompileUnit &Unit, MCSymbol *EndLabel) { if (Unit.getOrigUnit().getVersion() < 5) return; // Make .debug_loclists the current section. MS->switchSection(MC->getObjectFileInfo()->getDwarfLoclistsSection()); if (EndLabel != nullptr) Asm->OutStreamer->emitLabel(EndLabel); } /// Emit piece of .debug_loc for \p LinkedLocationExpression. void DwarfStreamer::emitDwarfDebugLocTableFragment( const CompileUnit &Unit, const DWARFLocationExpressionsVector &LinkedLocationExpression, PatchLocation Patch) { Patch.set(LocSectionSize); // Make .debug_loc to be current section. MS->switchSection(MC->getObjectFileInfo()->getDwarfLocSection()); unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); // Emit ranges. uint64_t BaseAddress = 0; if (std::optional LowPC = Unit.getLowPc()) BaseAddress = *LowPC; for (const DWARFLocationExpression &LocExpression : LinkedLocationExpression) { if (LocExpression.Range) { MS->emitIntValue(LocExpression.Range->LowPC - BaseAddress, AddressSize); MS->emitIntValue(LocExpression.Range->HighPC - BaseAddress, AddressSize); LocSectionSize += AddressSize; LocSectionSize += AddressSize; } Asm->OutStreamer->emitIntValue(LocExpression.Expr.size(), 2); Asm->OutStreamer->emitBytes(StringRef( (const char *)LocExpression.Expr.data(), LocExpression.Expr.size())); LocSectionSize += LocExpression.Expr.size() + 2; } // Add the terminator entry. MS->emitIntValue(0, AddressSize); MS->emitIntValue(0, AddressSize); LocSectionSize += AddressSize; LocSectionSize += AddressSize; } /// Emit .debug_addr header. MCSymbol *DwarfStreamer::emitDwarfDebugAddrsHeader(const CompileUnit &Unit) { // Make .debug_addr the current section. MS->switchSection(MC->getObjectFileInfo()->getDwarfAddrSection()); MCSymbol *BeginLabel = Asm->createTempSymbol("Bdebugaddr"); MCSymbol *EndLabel = Asm->createTempSymbol("Edebugaddr"); unsigned AddrSize = Unit.getOrigUnit().getAddressByteSize(); // Emit length. Asm->emitLabelDifference(EndLabel, BeginLabel, sizeof(uint32_t)); Asm->OutStreamer->emitLabel(BeginLabel); AddrSectionSize += sizeof(uint32_t); // Emit version. Asm->emitInt16(5); AddrSectionSize += 2; // Emit address size. Asm->emitInt8(AddrSize); AddrSectionSize += 1; // Emit segment size. Asm->emitInt8(0); AddrSectionSize += 1; return EndLabel; } /// Emit the .debug_addr addresses stored in \p Addrs. void DwarfStreamer::emitDwarfDebugAddrs(const SmallVector &Addrs, uint8_t AddrSize) { Asm->OutStreamer->switchSection(MOFI->getDwarfAddrSection()); for (auto Addr : Addrs) { Asm->OutStreamer->emitIntValue(Addr, AddrSize); AddrSectionSize += AddrSize; } } /// Emit .debug_addr footer. void DwarfStreamer::emitDwarfDebugAddrsFooter(const CompileUnit &Unit, MCSymbol *EndLabel) { // Make .debug_addr the current section. MS->switchSection(MC->getObjectFileInfo()->getDwarfAddrSection()); if (EndLabel != nullptr) Asm->OutStreamer->emitLabel(EndLabel); } /// Emit piece of .debug_loclists for \p LinkedLocationExpression. void DwarfStreamer::emitDwarfDebugLocListsTableFragment( const CompileUnit &Unit, const DWARFLocationExpressionsVector &LinkedLocationExpression, PatchLocation Patch, DebugDieValuePool &AddrPool) { Patch.set(LocListsSectionSize); // Make .debug_loclists the current section. MS->switchSection(MC->getObjectFileInfo()->getDwarfLoclistsSection()); std::optional BaseAddress; for (const DWARFLocationExpression &LocExpression : LinkedLocationExpression) { if (LocExpression.Range) { if (!BaseAddress) { BaseAddress = LocExpression.Range->LowPC; // Emit base address. MS->emitInt8(dwarf::DW_LLE_base_addressx); LocListsSectionSize += 1; LocListsSectionSize += MS->emitULEB128IntValue(AddrPool.getValueIndex(*BaseAddress)); } // Emit type of entry. MS->emitInt8(dwarf::DW_LLE_offset_pair); LocListsSectionSize += 1; // Emit start offset relative to base address. LocListsSectionSize += MS->emitULEB128IntValue(LocExpression.Range->LowPC - *BaseAddress); // Emit end offset relative to base address. LocListsSectionSize += MS->emitULEB128IntValue(LocExpression.Range->HighPC - *BaseAddress); } else { // Emit type of entry. MS->emitInt8(dwarf::DW_LLE_default_location); LocListsSectionSize += 1; } LocListsSectionSize += MS->emitULEB128IntValue(LocExpression.Expr.size()); Asm->OutStreamer->emitBytes(StringRef( (const char *)LocExpression.Expr.data(), LocExpression.Expr.size())); LocListsSectionSize += LocExpression.Expr.size(); } // Emit the terminator entry. MS->emitInt8(dwarf::DW_LLE_end_of_list); LocListsSectionSize += 1; } void DwarfStreamer::emitLineTableForUnit( const DWARFDebugLine::LineTable &LineTable, const CompileUnit &Unit, OffsetsStringPool &DebugStrPool, OffsetsStringPool &DebugLineStrPool) { // Switch to the section where the table will be emitted into. MS->switchSection(MC->getObjectFileInfo()->getDwarfLineSection()); MCSymbol *LineStartSym = MC->createTempSymbol(); MCSymbol *LineEndSym = MC->createTempSymbol(); // unit_length. if (LineTable.Prologue.FormParams.Format == dwarf::DwarfFormat::DWARF64) { MS->emitInt32(dwarf::DW_LENGTH_DWARF64); LineSectionSize += 4; } emitLabelDifference(LineEndSym, LineStartSym, LineTable.Prologue.FormParams.Format, LineSectionSize); Asm->OutStreamer->emitLabel(LineStartSym); // Emit prologue. emitLineTablePrologue(LineTable.Prologue, DebugStrPool, DebugLineStrPool); // Emit rows. emitLineTableRows(LineTable, LineEndSym, Unit.getOrigUnit().getAddressByteSize()); } void DwarfStreamer::emitLineTablePrologue(const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool, OffsetsStringPool &DebugLineStrPool) { MCSymbol *PrologueStartSym = MC->createTempSymbol(); MCSymbol *PrologueEndSym = MC->createTempSymbol(); // version (uhalf). MS->emitInt16(P.getVersion()); LineSectionSize += 2; if (P.getVersion() == 5) { // address_size (ubyte). MS->emitInt8(P.getAddressSize()); LineSectionSize += 1; // segment_selector_size (ubyte). MS->emitInt8(P.SegSelectorSize); LineSectionSize += 1; } // header_length. emitLabelDifference(PrologueEndSym, PrologueStartSym, P.FormParams.Format, LineSectionSize); Asm->OutStreamer->emitLabel(PrologueStartSym); emitLineTableProloguePayload(P, DebugStrPool, DebugLineStrPool); Asm->OutStreamer->emitLabel(PrologueEndSym); } void DwarfStreamer::emitLineTablePrologueV2IncludeAndFileTable( const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool, OffsetsStringPool &DebugLineStrPool) { // include_directories (sequence of path names). for (const DWARFFormValue &Include : P.IncludeDirectories) emitLineTableString(P, Include, DebugStrPool, DebugLineStrPool); // The last entry is followed by a single null byte. MS->emitInt8(0); LineSectionSize += 1; // file_names (sequence of file entries). for (const DWARFDebugLine::FileNameEntry &File : P.FileNames) { // A null-terminated string containing the full or relative path name of a // source file. emitLineTableString(P, File.Name, DebugStrPool, DebugLineStrPool); // An unsigned LEB128 number representing the directory index of a directory // in the include_directories section. LineSectionSize += MS->emitULEB128IntValue(File.DirIdx); // An unsigned LEB128 number representing the (implementation-defined) time // of last modification for the file, or 0 if not available. LineSectionSize += MS->emitULEB128IntValue(File.ModTime); // An unsigned LEB128 number representing the length in bytes of the file, // or 0 if not available. LineSectionSize += MS->emitULEB128IntValue(File.Length); } // The last entry is followed by a single null byte. MS->emitInt8(0); LineSectionSize += 1; } void DwarfStreamer::emitLineTablePrologueV5IncludeAndFileTable( const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool, OffsetsStringPool &DebugLineStrPool) { if (P.IncludeDirectories.empty()) { // directory_entry_format_count(ubyte). MS->emitInt8(0); LineSectionSize += 1; } else { // directory_entry_format_count(ubyte). MS->emitInt8(1); LineSectionSize += 1; // directory_entry_format (sequence of ULEB128 pairs). LineSectionSize += MS->emitULEB128IntValue(dwarf::DW_LNCT_path); LineSectionSize += MS->emitULEB128IntValue(P.IncludeDirectories[0].getForm()); } // directories_count (ULEB128). LineSectionSize += MS->emitULEB128IntValue(P.IncludeDirectories.size()); // directories (sequence of directory names). for (auto Include : P.IncludeDirectories) emitLineTableString(P, Include, DebugStrPool, DebugLineStrPool); bool HasChecksums = P.ContentTypes.HasMD5; bool HasInlineSources = P.ContentTypes.HasSource; if (P.FileNames.empty()) { // file_name_entry_format_count (ubyte). MS->emitInt8(0); LineSectionSize += 1; } else { // file_name_entry_format_count (ubyte). MS->emitInt8(2 + (HasChecksums ? 1 : 0) + (HasInlineSources ? 1 : 0)); LineSectionSize += 1; // file_name_entry_format (sequence of ULEB128 pairs). auto StrForm = P.FileNames[0].Name.getForm(); LineSectionSize += MS->emitULEB128IntValue(dwarf::DW_LNCT_path); LineSectionSize += MS->emitULEB128IntValue(StrForm); LineSectionSize += MS->emitULEB128IntValue(dwarf::DW_LNCT_directory_index); LineSectionSize += MS->emitULEB128IntValue(dwarf::DW_FORM_data1); if (HasChecksums) { LineSectionSize += MS->emitULEB128IntValue(dwarf::DW_LNCT_MD5); LineSectionSize += MS->emitULEB128IntValue(dwarf::DW_FORM_data16); } if (HasInlineSources) { LineSectionSize += MS->emitULEB128IntValue(dwarf::DW_LNCT_LLVM_source); LineSectionSize += MS->emitULEB128IntValue(StrForm); } } // file_names_count (ULEB128). LineSectionSize += MS->emitULEB128IntValue(P.FileNames.size()); // file_names (sequence of file name entries). for (auto File : P.FileNames) { emitLineTableString(P, File.Name, DebugStrPool, DebugLineStrPool); MS->emitInt8(File.DirIdx); LineSectionSize += 1; if (HasChecksums) { MS->emitBinaryData( StringRef(reinterpret_cast(File.Checksum.data()), File.Checksum.size())); LineSectionSize += File.Checksum.size(); } if (HasInlineSources) emitLineTableString(P, File.Source, DebugStrPool, DebugLineStrPool); } } void DwarfStreamer::emitLineTableString(const DWARFDebugLine::Prologue &P, const DWARFFormValue &String, OffsetsStringPool &DebugStrPool, OffsetsStringPool &DebugLineStrPool) { std::optional StringVal = dwarf::toString(String); if (!StringVal) { warn("Cann't read string from line table."); return; } switch (String.getForm()) { case dwarf::DW_FORM_string: { StringRef Str = *StringVal; Asm->OutStreamer->emitBytes(Str.data()); Asm->emitInt8(0); LineSectionSize += Str.size() + 1; } break; case dwarf::DW_FORM_strp: case dwarf::DW_FORM_line_strp: { DwarfStringPoolEntryRef StringRef = String.getForm() == dwarf::DW_FORM_strp ? DebugStrPool.getEntry(*StringVal) : DebugLineStrPool.getEntry(*StringVal); emitIntOffset(StringRef.getOffset(), P.FormParams.Format, LineSectionSize); } break; default: warn("Unsupported string form inside line table."); break; }; } void DwarfStreamer::emitLineTableProloguePayload( const DWARFDebugLine::Prologue &P, OffsetsStringPool &DebugStrPool, OffsetsStringPool &DebugLineStrPool) { // minimum_instruction_length (ubyte). MS->emitInt8(P.MinInstLength); LineSectionSize += 1; if (P.FormParams.Version >= 4) { // maximum_operations_per_instruction (ubyte). MS->emitInt8(P.MaxOpsPerInst); LineSectionSize += 1; } // default_is_stmt (ubyte). MS->emitInt8(P.DefaultIsStmt); LineSectionSize += 1; // line_base (sbyte). MS->emitInt8(P.LineBase); LineSectionSize += 1; // line_range (ubyte). MS->emitInt8(P.LineRange); LineSectionSize += 1; // opcode_base (ubyte). MS->emitInt8(P.OpcodeBase); LineSectionSize += 1; // standard_opcode_lengths (array of ubyte). for (auto Length : P.StandardOpcodeLengths) { MS->emitInt8(Length); LineSectionSize += 1; } if (P.FormParams.Version < 5) emitLineTablePrologueV2IncludeAndFileTable(P, DebugStrPool, DebugLineStrPool); else emitLineTablePrologueV5IncludeAndFileTable(P, DebugStrPool, DebugLineStrPool); } void DwarfStreamer::emitLineTableRows( const DWARFDebugLine::LineTable &LineTable, MCSymbol *LineEndSym, unsigned AddressByteSize) { MCDwarfLineTableParams Params; Params.DWARF2LineOpcodeBase = LineTable.Prologue.OpcodeBase; Params.DWARF2LineBase = LineTable.Prologue.LineBase; Params.DWARF2LineRange = LineTable.Prologue.LineRange; SmallString<128> EncodingBuffer; if (LineTable.Rows.empty()) { // We only have the dummy entry, dsymutil emits an entry with a 0 // address in that case. MCDwarfLineAddr::encode(*MC, Params, std::numeric_limits::max(), 0, EncodingBuffer); MS->emitBytes(EncodingBuffer); LineSectionSize += EncodingBuffer.size(); MS->emitLabel(LineEndSym); return; } // Line table state machine fields unsigned FileNum = 1; unsigned LastLine = 1; unsigned Column = 0; unsigned Discriminator = 0; unsigned IsStatement = 1; unsigned Isa = 0; uint64_t Address = -1ULL; unsigned RowsSinceLastSequence = 0; for (const DWARFDebugLine::Row &Row : LineTable.Rows) { int64_t AddressDelta; if (Address == -1ULL) { MS->emitIntValue(dwarf::DW_LNS_extended_op, 1); MS->emitULEB128IntValue(AddressByteSize + 1); MS->emitIntValue(dwarf::DW_LNE_set_address, 1); MS->emitIntValue(Row.Address.Address, AddressByteSize); LineSectionSize += 2 + AddressByteSize + getULEB128Size(AddressByteSize + 1); AddressDelta = 0; } else { AddressDelta = (Row.Address.Address - Address) / LineTable.Prologue.MinInstLength; } // FIXME: code copied and transformed from MCDwarf.cpp::EmitDwarfLineTable. // We should find a way to share this code, but the current compatibility // requirement with classic dsymutil makes it hard. Revisit that once this // requirement is dropped. if (FileNum != Row.File) { FileNum = Row.File; MS->emitIntValue(dwarf::DW_LNS_set_file, 1); MS->emitULEB128IntValue(FileNum); LineSectionSize += 1 + getULEB128Size(FileNum); } if (Column != Row.Column) { Column = Row.Column; MS->emitIntValue(dwarf::DW_LNS_set_column, 1); MS->emitULEB128IntValue(Column); LineSectionSize += 1 + getULEB128Size(Column); } if (Discriminator != Row.Discriminator && MS->getContext().getDwarfVersion() >= 4) { Discriminator = Row.Discriminator; unsigned Size = getULEB128Size(Discriminator); MS->emitIntValue(dwarf::DW_LNS_extended_op, 1); MS->emitULEB128IntValue(Size + 1); MS->emitIntValue(dwarf::DW_LNE_set_discriminator, 1); MS->emitULEB128IntValue(Discriminator); LineSectionSize += /* extended op */ 1 + getULEB128Size(Size + 1) + /* discriminator */ 1 + Size; } Discriminator = 0; if (Isa != Row.Isa) { Isa = Row.Isa; MS->emitIntValue(dwarf::DW_LNS_set_isa, 1); MS->emitULEB128IntValue(Isa); LineSectionSize += 1 + getULEB128Size(Isa); } if (IsStatement != Row.IsStmt) { IsStatement = Row.IsStmt; MS->emitIntValue(dwarf::DW_LNS_negate_stmt, 1); LineSectionSize += 1; } if (Row.BasicBlock) { MS->emitIntValue(dwarf::DW_LNS_set_basic_block, 1); LineSectionSize += 1; } if (Row.PrologueEnd) { MS->emitIntValue(dwarf::DW_LNS_set_prologue_end, 1); LineSectionSize += 1; } if (Row.EpilogueBegin) { MS->emitIntValue(dwarf::DW_LNS_set_epilogue_begin, 1); LineSectionSize += 1; } int64_t LineDelta = int64_t(Row.Line) - LastLine; if (!Row.EndSequence) { MCDwarfLineAddr::encode(*MC, Params, LineDelta, AddressDelta, EncodingBuffer); MS->emitBytes(EncodingBuffer); LineSectionSize += EncodingBuffer.size(); EncodingBuffer.resize(0); Address = Row.Address.Address; LastLine = Row.Line; RowsSinceLastSequence++; } else { if (LineDelta) { MS->emitIntValue(dwarf::DW_LNS_advance_line, 1); MS->emitSLEB128IntValue(LineDelta); LineSectionSize += 1 + getSLEB128Size(LineDelta); } if (AddressDelta) { MS->emitIntValue(dwarf::DW_LNS_advance_pc, 1); MS->emitULEB128IntValue(AddressDelta); LineSectionSize += 1 + getULEB128Size(AddressDelta); } MCDwarfLineAddr::encode(*MC, Params, std::numeric_limits::max(), 0, EncodingBuffer); MS->emitBytes(EncodingBuffer); LineSectionSize += EncodingBuffer.size(); EncodingBuffer.resize(0); Address = -1ULL; LastLine = FileNum = IsStatement = 1; RowsSinceLastSequence = Column = Discriminator = Isa = 0; } } if (RowsSinceLastSequence) { MCDwarfLineAddr::encode(*MC, Params, std::numeric_limits::max(), 0, EncodingBuffer); MS->emitBytes(EncodingBuffer); LineSectionSize += EncodingBuffer.size(); EncodingBuffer.resize(0); } MS->emitLabel(LineEndSym); } void DwarfStreamer::emitIntOffset(uint64_t Offset, dwarf::DwarfFormat Format, uint64_t &SectionSize) { uint8_t Size = dwarf::getDwarfOffsetByteSize(Format); MS->emitIntValue(Offset, Size); SectionSize += Size; } void DwarfStreamer::emitLabelDifference(const MCSymbol *Hi, const MCSymbol *Lo, dwarf::DwarfFormat Format, uint64_t &SectionSize) { uint8_t Size = dwarf::getDwarfOffsetByteSize(Format); Asm->emitLabelDifference(Hi, Lo, Size); SectionSize += Size; } /// Emit the pubnames or pubtypes section contribution for \p /// Unit into \p Sec. The data is provided in \p Names. void DwarfStreamer::emitPubSectionForUnit( MCSection *Sec, StringRef SecName, const CompileUnit &Unit, const std::vector &Names) { if (Names.empty()) return; // Start the dwarf pubnames section. Asm->OutStreamer->switchSection(Sec); MCSymbol *BeginLabel = Asm->createTempSymbol("pub" + SecName + "_begin"); MCSymbol *EndLabel = Asm->createTempSymbol("pub" + SecName + "_end"); bool HeaderEmitted = false; // Emit the pubnames for this compilation unit. for (const auto &Name : Names) { if (Name.SkipPubSection) continue; if (!HeaderEmitted) { // Emit the header. Asm->emitLabelDifference(EndLabel, BeginLabel, 4); // Length Asm->OutStreamer->emitLabel(BeginLabel); Asm->emitInt16(dwarf::DW_PUBNAMES_VERSION); // Version Asm->emitInt32(Unit.getStartOffset()); // Unit offset Asm->emitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset()); // Size HeaderEmitted = true; } Asm->emitInt32(Name.Die->getOffset()); // Emit the string itself. Asm->OutStreamer->emitBytes(Name.Name.getString()); // Emit a null terminator. Asm->emitInt8(0); } if (!HeaderEmitted) return; Asm->emitInt32(0); // End marker. Asm->OutStreamer->emitLabel(EndLabel); } /// Emit .debug_pubnames for \p Unit. void DwarfStreamer::emitPubNamesForUnit(const CompileUnit &Unit) { emitPubSectionForUnit(MC->getObjectFileInfo()->getDwarfPubNamesSection(), "names", Unit, Unit.getPubnames()); } /// Emit .debug_pubtypes for \p Unit. void DwarfStreamer::emitPubTypesForUnit(const CompileUnit &Unit) { emitPubSectionForUnit(MC->getObjectFileInfo()->getDwarfPubTypesSection(), "types", Unit, Unit.getPubtypes()); } /// Emit a CIE into the debug_frame section. void DwarfStreamer::emitCIE(StringRef CIEBytes) { MS->switchSection(MC->getObjectFileInfo()->getDwarfFrameSection()); MS->emitBytes(CIEBytes); FrameSectionSize += CIEBytes.size(); } /// Emit a FDE into the debug_frame section. \p FDEBytes /// contains the FDE data without the length, CIE offset and address /// which will be replaced with the parameter values. void DwarfStreamer::emitFDE(uint32_t CIEOffset, uint32_t AddrSize, uint64_t Address, StringRef FDEBytes) { MS->switchSection(MC->getObjectFileInfo()->getDwarfFrameSection()); MS->emitIntValue(FDEBytes.size() + 4 + AddrSize, 4); MS->emitIntValue(CIEOffset, 4); MS->emitIntValue(Address, AddrSize); MS->emitBytes(FDEBytes); FrameSectionSize += FDEBytes.size() + 8 + AddrSize; } void DwarfStreamer::emitMacroTables(DWARFContext *Context, const Offset2UnitMap &UnitMacroMap, OffsetsStringPool &StringPool) { assert(Context != nullptr && "Empty DWARF context"); // Check for .debug_macinfo table. if (const DWARFDebugMacro *Table = Context->getDebugMacinfo()) { MS->switchSection(MC->getObjectFileInfo()->getDwarfMacinfoSection()); emitMacroTableImpl(Table, UnitMacroMap, StringPool, MacInfoSectionSize); } // Check for .debug_macro table. if (const DWARFDebugMacro *Table = Context->getDebugMacro()) { MS->switchSection(MC->getObjectFileInfo()->getDwarfMacroSection()); emitMacroTableImpl(Table, UnitMacroMap, StringPool, MacroSectionSize); } } void DwarfStreamer::emitMacroTableImpl(const DWARFDebugMacro *MacroTable, const Offset2UnitMap &UnitMacroMap, OffsetsStringPool &StringPool, uint64_t &OutOffset) { bool DefAttributeIsReported = false; bool UndefAttributeIsReported = false; bool ImportAttributeIsReported = false; for (const DWARFDebugMacro::MacroList &List : MacroTable->MacroLists) { Offset2UnitMap::const_iterator UnitIt = UnitMacroMap.find(List.Offset); if (UnitIt == UnitMacroMap.end()) { warn(formatv( "couldn`t find compile unit for the macro table with offset = {0:x}", List.Offset)); continue; } // Skip macro table if the unit was not cloned. DIE *OutputUnitDIE = UnitIt->second->getOutputUnitDIE(); if (OutputUnitDIE == nullptr) continue; // Update macro attribute of cloned compile unit with the proper offset to // the macro table. bool hasDWARFv5Header = false; for (auto &V : OutputUnitDIE->values()) { if (V.getAttribute() == dwarf::DW_AT_macro_info) { V = DIEValue(V.getAttribute(), V.getForm(), DIEInteger(OutOffset)); break; } else if (V.getAttribute() == dwarf::DW_AT_macros) { hasDWARFv5Header = true; V = DIEValue(V.getAttribute(), V.getForm(), DIEInteger(OutOffset)); break; } } // Write DWARFv5 header. if (hasDWARFv5Header) { // Write header version. MS->emitIntValue(List.Header.Version, sizeof(List.Header.Version)); OutOffset += sizeof(List.Header.Version); uint8_t Flags = List.Header.Flags; // Check for OPCODE_OPERANDS_TABLE. if (Flags & DWARFDebugMacro::HeaderFlagMask::MACRO_OPCODE_OPERANDS_TABLE) { Flags &= ~DWARFDebugMacro::HeaderFlagMask::MACRO_OPCODE_OPERANDS_TABLE; warn("opcode_operands_table is not supported yet."); } // Check for DEBUG_LINE_OFFSET. std::optional StmtListOffset; if (Flags & DWARFDebugMacro::HeaderFlagMask::MACRO_DEBUG_LINE_OFFSET) { // Get offset to the line table from the cloned compile unit. for (auto &V : OutputUnitDIE->values()) { if (V.getAttribute() == dwarf::DW_AT_stmt_list) { StmtListOffset = V.getDIEInteger().getValue(); break; } } if (!StmtListOffset) { Flags &= ~DWARFDebugMacro::HeaderFlagMask::MACRO_DEBUG_LINE_OFFSET; warn("couldn`t find line table for macro table."); } } // Write flags. MS->emitIntValue(Flags, sizeof(Flags)); OutOffset += sizeof(Flags); // Write offset to line table. if (StmtListOffset) { MS->emitIntValue(*StmtListOffset, List.Header.getOffsetByteSize()); OutOffset += List.Header.getOffsetByteSize(); } } // Write macro entries. for (const DWARFDebugMacro::Entry &MacroEntry : List.Macros) { if (MacroEntry.Type == 0) { OutOffset += MS->emitULEB128IntValue(MacroEntry.Type); continue; } uint8_t MacroType = MacroEntry.Type; switch (MacroType) { default: { bool HasVendorSpecificExtension = (!hasDWARFv5Header && MacroType == dwarf::DW_MACINFO_vendor_ext) || (hasDWARFv5Header && (MacroType >= dwarf::DW_MACRO_lo_user && MacroType <= dwarf::DW_MACRO_hi_user)); if (HasVendorSpecificExtension) { // Write macinfo type. MS->emitIntValue(MacroType, 1); OutOffset++; // Write vendor extension constant. OutOffset += MS->emitULEB128IntValue(MacroEntry.ExtConstant); // Write vendor extension string. StringRef String = MacroEntry.ExtStr; MS->emitBytes(String); MS->emitIntValue(0, 1); OutOffset += String.size() + 1; } else warn("unknown macro type. skip."); } break; // debug_macro and debug_macinfo share some common encodings. // DW_MACRO_define == DW_MACINFO_define // DW_MACRO_undef == DW_MACINFO_undef // DW_MACRO_start_file == DW_MACINFO_start_file // DW_MACRO_end_file == DW_MACINFO_end_file // For readibility/uniformity we are using DW_MACRO_*. case dwarf::DW_MACRO_define: case dwarf::DW_MACRO_undef: { // Write macinfo type. MS->emitIntValue(MacroType, 1); OutOffset++; // Write source line. OutOffset += MS->emitULEB128IntValue(MacroEntry.Line); // Write macro string. StringRef String = MacroEntry.MacroStr; MS->emitBytes(String); MS->emitIntValue(0, 1); OutOffset += String.size() + 1; } break; case dwarf::DW_MACRO_define_strp: case dwarf::DW_MACRO_undef_strp: case dwarf::DW_MACRO_define_strx: case dwarf::DW_MACRO_undef_strx: { assert(UnitIt->second->getOrigUnit().getVersion() >= 5); // DW_MACRO_*_strx forms are not supported currently. // Convert to *_strp. switch (MacroType) { case dwarf::DW_MACRO_define_strx: { MacroType = dwarf::DW_MACRO_define_strp; if (!DefAttributeIsReported) { warn("DW_MACRO_define_strx unsupported yet. Convert to " "DW_MACRO_define_strp."); DefAttributeIsReported = true; } } break; case dwarf::DW_MACRO_undef_strx: { MacroType = dwarf::DW_MACRO_undef_strp; if (!UndefAttributeIsReported) { warn("DW_MACRO_undef_strx unsupported yet. Convert to " "DW_MACRO_undef_strp."); UndefAttributeIsReported = true; } } break; default: // Nothing to do. break; } // Write macinfo type. MS->emitIntValue(MacroType, 1); OutOffset++; // Write source line. OutOffset += MS->emitULEB128IntValue(MacroEntry.Line); // Write macro string. DwarfStringPoolEntryRef EntryRef = StringPool.getEntry(MacroEntry.MacroStr); MS->emitIntValue(EntryRef.getOffset(), List.Header.getOffsetByteSize()); OutOffset += List.Header.getOffsetByteSize(); break; } case dwarf::DW_MACRO_start_file: { // Write macinfo type. MS->emitIntValue(MacroType, 1); OutOffset++; // Write source line. OutOffset += MS->emitULEB128IntValue(MacroEntry.Line); // Write source file id. OutOffset += MS->emitULEB128IntValue(MacroEntry.File); } break; case dwarf::DW_MACRO_end_file: { // Write macinfo type. MS->emitIntValue(MacroType, 1); OutOffset++; } break; case dwarf::DW_MACRO_import: case dwarf::DW_MACRO_import_sup: { if (!ImportAttributeIsReported) { warn("DW_MACRO_import and DW_MACRO_import_sup are unsupported yet. " "remove."); ImportAttributeIsReported = true; } } break; } } } }