diff --git a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFFormValue.cpp @@ -420,39 +420,27 @@ case DW_FORM_addrx2: case DW_FORM_addrx3: case DW_FORM_addrx4: - case DW_FORM_GNU_addr_index: { + case DW_FORM_GNU_addr_index: + case DW_FORM_LLVM_addrx_offset: { if (U == nullptr) { OS << ""; break; } - std::optional A = - U->getAddrOffsetSectionItem(UValue); - if (!A || DumpOpts.Verbose) - AddrOS << format("indexed (%8.8x) address = ", (uint32_t)UValue); + std::optional A = getAsSectionedAddress(); + if (!A || DumpOpts.Verbose) { + if (Form == DW_FORM_LLVM_addrx_offset) { + uint32_t Index = UValue >> 32; + uint32_t Offset = UValue & 0xffffffff; + AddrOS << format("indexed (%8.8x) + 0x%x address = ", Index, Offset); + } else + AddrOS << format("indexed (%8.8x) address = ", (uint32_t)UValue); + } if (A) dumpSectionedAddress(AddrOS, DumpOpts, *A); else OS << ""; break; } - case DW_FORM_LLVM_addrx_offset: { - if (U == nullptr) { - OS << ""; - break; - } - uint32_t Index = UValue >> 32; - uint32_t Offset = UValue & 0xffffffff; - std::optional A = - U->getAddrOffsetSectionItem(Index); - if (!A || DumpOpts.Verbose) - AddrOS << format("indexed (%8.8x) + 0x%x address = ", Index, Offset); - if (A) { - A->Address += Offset; - dumpSectionedAddress(AddrOS, DumpOpts, *A); - } else - OS << ""; - break; - } case DW_FORM_flag_present: OS << "true"; break; @@ -677,7 +665,9 @@ if (!isFormClass(FC_Address)) return std::nullopt; bool AddrOffset = Form == dwarf::DW_FORM_LLVM_addrx_offset; - if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx || AddrOffset) { + if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx || + Form == DW_FORM_addrx1 || Form == DW_FORM_addrx2 || + Form == DW_FORM_addrx3 || Form == DW_FORM_addrx4 || AddrOffset) { uint32_t Index = AddrOffset ? (Value.uval >> 32) : Value.uval; if (!U) diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp --- a/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -48,6 +48,11 @@ // Test that we can decode all DW_FORM values correctly. const AddrType AddrValue = (AddrType)0x0123456789abcdefULL; + const AddrType AddrxValue = (AddrType)0x4231abcd4231abcdULL; + const AddrType Addrx1Value = (AddrType)0x0000aaaabbbbccccULL; + const AddrType Addrx2Value = (AddrType)0xf00123f00456f000ULL; + const AddrType Addrx4Value = (AddrType)0xa1b2c3d4e5f6e5d4ULL; + const uint8_t BlockData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; const uint32_t BlockSize = sizeof(BlockData); const RefAddrType RefAddr = 0x12345678; @@ -79,8 +84,10 @@ dwarfgen::CompileUnit &CU = DG->addCompileUnit(); dwarfgen::DIE CUDie = CU.getUnitDIE(); - if (Version >= 5) + if (Version >= 5) { CUDie.addStrOffsetsBaseAttribute(); + CUDie.addAddrBaseAttribute(); + } uint16_t Attr = DW_AT_lo_user; @@ -90,6 +97,20 @@ const auto Attr_DW_FORM_addr = static_cast(Attr++); CUDie.addAttribute(Attr_DW_FORM_addr, DW_FORM_addr, AddrValue); + const auto Attr_DW_FORM_addrx = static_cast(Attr++); + const auto Attr_DW_FORM_addrx1 = static_cast(Attr++); + const auto Attr_DW_FORM_addrx2 = static_cast(Attr++); + // TODO: Add Attr_DW_FORM_addrx3 test (this form type is currently + // unsupported) + const auto Attr_DW_FORM_addrx4 = static_cast(Attr++); + + if (Version >= 5) { + CUDie.addAttribute(Attr_DW_FORM_addrx, DW_FORM_addrx, AddrxValue); + CUDie.addAttribute(Attr_DW_FORM_addrx1, DW_FORM_addrx1, Addrx1Value); + CUDie.addAttribute(Attr_DW_FORM_addrx2, DW_FORM_addrx2, Addrx2Value); + CUDie.addAttribute(Attr_DW_FORM_addrx4, DW_FORM_addrx4, Addrx4Value); + } + //---------------------------------------------------------------------- // Test block forms //---------------------------------------------------------------------- @@ -241,6 +262,24 @@ //---------------------------------------------------------------------- EXPECT_EQ(AddrValue, toAddress(DieDG.find(Attr_DW_FORM_addr), 0)); + if (Version >= 5) { + auto ExtractedAddrxValue = toAddress(DieDG.find(Attr_DW_FORM_addrx)); + EXPECT_TRUE(ExtractedAddrxValue.has_value()); + EXPECT_EQ(AddrxValue, *ExtractedAddrxValue); + + auto ExtractedAddrx1Value = toAddress(DieDG.find(Attr_DW_FORM_addrx1)); + EXPECT_TRUE(ExtractedAddrx1Value.has_value()); + EXPECT_EQ(Addrx1Value, *ExtractedAddrx1Value); + + auto ExtractedAddrx2Value = toAddress(DieDG.find(Attr_DW_FORM_addrx2)); + EXPECT_TRUE(ExtractedAddrx2Value.has_value()); + EXPECT_EQ(Addrx2Value, *ExtractedAddrx2Value); + + auto ExtractedAddrx4Value = toAddress(DieDG.find(Attr_DW_FORM_addrx4)); + EXPECT_TRUE(ExtractedAddrx1Value.has_value()); + EXPECT_EQ(Addrx4Value, *ExtractedAddrx4Value); + } + //---------------------------------------------------------------------- // Test block forms //---------------------------------------------------------------------- diff --git a/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.h b/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.h --- a/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.h +++ b/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.h @@ -133,6 +133,9 @@ /// Add a DW_AT_str_offsets_base attribute to this DIE. void addStrOffsetsBaseAttribute(); + /// Add a DW_AT_addr_base attribute to this DIE. + void addAddrBaseAttribute(); + /// Add a new child to this DIE object. /// /// \param Tag the dwarf::Tag to assing to the llvm::DIE object. @@ -258,7 +261,17 @@ std::vector> LineTables; DIEAbbrevSet Abbreviations; + // Mimics llvm::AddressPool, but allows for constant addresses for testing. + struct DummyAddressPool { + unsigned getIndex(uint64_t Address); + + void emit(AsmPrinter &Asm, MCSection *AddrSection, MCSymbol *StartSym); + + std::vector AddressValues; + } AddressPool; + MCSymbol *StringOffsetsStartSym; + MCSymbol *AddrTableStartSym; SmallString<4096> FileBytes; /// The stream we use to generate the DWARF into as an ELF file. @@ -312,6 +325,8 @@ DIEAbbrevSet &getAbbrevSet() { return Abbreviations; } DwarfStringPool &getStringPool() { return *StringPool; } MCSymbol *getStringOffsetsStartSym() const { return StringOffsetsStartSym; } + DummyAddressPool &getAddressPool() { return AddressPool; } + MCSymbol *getAddrTableStartSym() const { return AddrTableStartSym; } /// Save the generated DWARF file to disk. /// diff --git a/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.cpp b/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.cpp --- a/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.cpp +++ b/llvm/unittests/DebugInfo/DWARF/DwarfGenerator.cpp @@ -53,6 +53,16 @@ void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, uint64_t U) { auto &DG = CU->getGenerator(); + switch (Form) { + case DW_FORM_addrx: + case DW_FORM_addrx1: + case DW_FORM_addrx2: + case DW_FORM_addrx3: + case DW_FORM_addrx4: + U = DG.getAddressPool().getIndex(U); + default: + break; + } Die->addValue(DG.getAllocator(), static_cast(A), Form, DIEInteger(U)); } @@ -142,6 +152,24 @@ addAttribute(dwarf::DW_AT_str_offsets_base, DW_FORM_sec_offset, *Expr); } +// This is currently fixed to be the first address entry after the header. +void dwarfgen::DIE::addAddrBaseAttribute() { + auto &DG = CU->getGenerator(); + auto &MC = *DG.getMCContext(); + AsmPrinter *Asm = DG.getAsmPrinter(); + + const MCSymbol *SectionStart = + Asm->getObjFileLowering().getDwarfAddrSection()->getBeginSymbol(); + + const MCExpr *Expr = MCSymbolRefExpr::create(DG.getAddrTableStartSym(), MC); + + if (!Asm->MAI->doesDwarfUseRelocationsAcrossSections()) + Expr = MCBinaryExpr::createSub( + Expr, MCSymbolRefExpr::create(SectionStart, MC), MC); + + addAttribute(dwarf::DW_AT_addr_base, DW_FORM_sec_offset, *Expr); +} + dwarfgen::DIE dwarfgen::DIE::addChild(dwarf::Tag Tag) { auto &DG = CU->getGenerator(); return dwarfgen::DIE(CU, @@ -495,9 +523,41 @@ StringPool = std::make_unique(Allocator, *Asm, StringRef()); StringOffsetsStartSym = Asm->createTempSymbol("str_offsets_base"); + AddrTableStartSym = Asm->createTempSymbol("addr_table_base"); + return Error::success(); } +unsigned dwarfgen::Generator::DummyAddressPool::getIndex(uint64_t Address) { + AddressValues.push_back(Address); + return static_cast(AddressValues.size() - 1); +} + +void dwarfgen::Generator::DummyAddressPool::emit(AsmPrinter &Asm, + MCSection *AddrSection, + MCSymbol *StartSym) { + const uint8_t AddrSize = Asm.getPointerSize(); + + // Switch to .debug_addr section + Asm.OutStreamer->switchSection(AddrSection); + + if (Asm.getDwarfVersion() >= 5) { + // Emit header + Asm.emitDwarfUnitLength(AddrSize * AddressValues.size() + 4, + "Length of contribution"); + Asm.emitInt16(Asm.getDwarfVersion()); + Asm.emitInt8(AddrSize); + Asm.emitInt8(0); + } + + if (StartSym) + Asm.OutStreamer->emitLabel(StartSym); + + // Emit addresses + for (uint64_t Addr : AddressValues) + Asm.OutStreamer->emitIntValue(Addr, AddrSize); +} + StringRef dwarfgen::Generator::generate() { // Offset from the first CU in the debug info section is 0 initially. uint64_t SecOffset = 0; @@ -521,6 +581,8 @@ StringPool->emit(*Asm, TLOF->getDwarfStrSection(), TLOF->getDwarfStrOffSection()); + AddressPool.emit(*Asm, TLOF->getDwarfAddrSection(), AddrTableStartSym); + MS->switchSection(TLOF->getDwarfInfoSection()); for (auto &CU : CompileUnits) { uint16_t Version = CU->getVersion();