diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/DWARFLinker/Classic/DWARFStreamer.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/DWARFLinker/Classic/DWARFStreamer.cpp | 1430 |
1 files changed, 1430 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/DWARFLinker/Classic/DWARFStreamer.cpp b/contrib/llvm-project/llvm/lib/DWARFLinker/Classic/DWARFStreamer.cpp new file mode 100644 index 000000000000..020bbb06449d --- /dev/null +++ b/contrib/llvm-project/llvm/lib/DWARFLinker/Classic/DWARFStreamer.cpp @@ -0,0 +1,1430 @@ +//===- 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; + +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(); + 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<formatted_raw_ostream>(OutFile), true, true, MIP, + std::unique_ptr<MCCodeEmitter>(MCE), std::unique_ptr<MCAsmBackend>(MAB), + true); + break; + } + case DWARFLinker::OutputFileType::Object: { + MS = TheTarget->createMCObjectStreamer( + TheTriple, *MC, std::unique_ptr<MCAsmBackend>(MAB), + MAB->createObjectWriter(OutFile), std::unique_ptr<MCCodeEmitter>(MCE), + *MSTI, MCOptions.MCRelaxAll, MCOptions.MCIncrementalLinkerCompatible, + /*DWARFMustBeAtTheEnd*/ false); + 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<MCStreamer>(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<std::unique_ptr<DIEAbbrev>> &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, StringRef SecName) { + MCSection *Section = + StringSwitch<MCSection *>(SecName) + .Case("debug_line", MC->getObjectFileInfo()->getDwarfLineSection()) + .Case("debug_loc", MC->getObjectFileInfo()->getDwarfLocSection()) + .Case("debug_ranges", + MC->getObjectFileInfo()->getDwarfRangesSection()) + .Case("debug_frame", MC->getObjectFileInfo()->getDwarfFrameSection()) + .Case("debug_aranges", + MC->getObjectFileInfo()->getDwarfARangesSection()) + .Case("debug_addr", MC->getObjectFileInfo()->getDwarfAddrSection()) + .Case("debug_rnglists", + MC->getObjectFileInfo()->getDwarfRnglistsSection()) + .Case("debug_loclists", + MC->getObjectFileInfo()->getDwarfLoclistsSection()) + .Default(nullptr); + + if (Section) { + MS->switchSection(Section); + + MS->emitBytes(SecData); + } +} + +/// Emit the debug_str section stored in \p Pool. +void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) { + Asm->OutStreamer->switchSection(MOFI->getDwarfStrSection()); + std::vector<DwarfStringPoolEntryRef> 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<uint64_t> &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<DwarfStringPoolEntryRef> 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<std::variant<MCSymbol *, uint64_t>> CompUnits; + DenseMap<unsigned, unsigned> 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<DWARF5AccelTable::UnitIndexAndEncoding> { + if (UniqueIdToCuMap.size() > 1) + return {{UniqueIdToCuMap[Entry.getUnitID()], + {dwarf::DW_IDX_compile_unit, Form}}}; + return std::nullopt; + }); +} + +void DwarfStreamer::emitAppleNamespaces( + AccelTable<AppleAccelTableStaticOffsetData> &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<AppleAccelTableStaticOffsetData> &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<AppleAccelTableStaticOffsetData> &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<AppleAccelTableStaticTypeData> &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<uint64_t> 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<uint64_t> 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<uint64_t> 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<uint64_t> &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<uint64_t> 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<const char *>(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<const char *> StringVal = dwarf::toString(String); + if (!StringVal) { + warn("Cann't read string from line table."); + return; + } + + switch (String.getForm()) { + case dwarf::DW_FORM_string: { + StringRef TranslatedString = + (Translator) ? Translator(*StringVal) : *StringVal; + Asm->OutStreamer->emitBytes(TranslatedString.data()); + Asm->emitInt8(0); + LineSectionSize += TranslatedString.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<int64_t>::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 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); + } + + // FIXME: We should handle the discriminator here, but dsymutil doesn't + // consider it, thus ignore it for now. + + 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<int64_t>::max(), + 0, EncodingBuffer); + MS->emitBytes(EncodingBuffer); + LineSectionSize += EncodingBuffer.size(); + EncodingBuffer.resize(0); + Address = -1ULL; + LastLine = FileNum = IsStatement = 1; + RowsSinceLastSequence = Column = Isa = 0; + } + } + + if (RowsSinceLastSequence) { + MCDwarfLineAddr::encode(*MC, Params, std::numeric_limits<int64_t>::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<CompileUnit::AccelInfo> &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<uint64_t> 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; + } + } + } +} |