From bffd929d5b0668363917972eebe3d530ad8add67 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Thu, 26 Jul 2018 14:36:07 +0000 Subject: [PATCH] dwarfgen: Add support for generating the debug_str_offsets section, take 3 Previous version of this patch failed on darwin targets because of different handling of cross-debug-section relocations. This fixes the tests to emit the DW_AT_str_offsets_base attribute correctly in both cases. Since doing this is a non-trivial amount of code, and I'm going to need it in more than one test, I've added a helper function to the dwarfgen DIE class to do it. Original commit message follows: The motivation for this is D49493, where we'd like to test details of debug_str_offsets behavior which is difficult to trigger from a traditional test. This adds the plubming necessary for dwarfgen to generate this section. The more interesting changes are: - I've moved emitStringOffsetsTableHeader function from DwarfFile to DwarfStringPool, so I can generate the section header more easily from the unit test. - added a new addAttribute overload taking an MCExpr*. This is used to generate the DW_AT_str_offsets_base, which links a compile unit to the offset table. I've also added a basic test for reading and writing DW_form_strx forms. Reviewers: dblaikie, JDevlieghere, probinson Subscribers: llvm-commits, aprantl Differential Revision: https://reviews.llvm.org/D49670 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@338031 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 10 ++-- lib/CodeGen/AsmPrinter/DwarfFile.cpp | 20 -------- lib/CodeGen/AsmPrinter/DwarfFile.h | 3 -- lib/CodeGen/AsmPrinter/DwarfStringPool.cpp | 22 +++++++++ lib/CodeGen/AsmPrinter/DwarfStringPool.h | 4 ++ .../DebugInfo/DWARF/DWARFDebugInfoTest.cpp | 48 +++++++++++++++++- unittests/DebugInfo/DWARF/DwarfGenerator.cpp | 49 +++++++++++++++++-- unittests/DebugInfo/DWARF/DwarfGenerator.h | 14 ++++++ 8 files changed, 138 insertions(+), 32 deletions(-) diff --git a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index f1e61b488a2..d2f123ce78e 100644 --- a/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1506,8 +1506,9 @@ void DwarfDebug::emitAbbreviations() { void DwarfDebug::emitStringOffsetsTableHeader() { DwarfFile &Holder = useSplitDwarf() ? SkeletonHolder : InfoHolder; - Holder.emitStringOffsetsTableHeader( - Asm->getObjFileLowering().getDwarfStrOffSection()); + Holder.getStringPool().emitStringOffsetsTableHeader( + *Asm, Asm->getObjFileLowering().getDwarfStrOffSection(), + Holder.getStringOffsetsStartSym()); } template @@ -2292,8 +2293,9 @@ void DwarfDebug::emitDebugLineDWO() { void DwarfDebug::emitStringOffsetsTableHeaderDWO() { assert(useSplitDwarf() && "No split dwarf?"); - InfoHolder.emitStringOffsetsTableHeader( - Asm->getObjFileLowering().getDwarfStrOffDWOSection()); + InfoHolder.getStringPool().emitStringOffsetsTableHeader( + *Asm, Asm->getObjFileLowering().getDwarfStrOffDWOSection(), + InfoHolder.getStringOffsetsStartSym()); } // Emit the .debug_str.dwo section for separated dwarf. This contains the diff --git a/lib/CodeGen/AsmPrinter/DwarfFile.cpp b/lib/CodeGen/AsmPrinter/DwarfFile.cpp index f3a3cbdbc74..c90bd568162 100644 --- a/lib/CodeGen/AsmPrinter/DwarfFile.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfFile.cpp @@ -28,26 +28,6 @@ void DwarfFile::addUnit(std::unique_ptr U) { CUs.push_back(std::move(U)); } -void DwarfFile::emitStringOffsetsTableHeader(MCSection *Section) { - if (StrPool.empty()) - return; - Asm->OutStreamer->SwitchSection(Section); - unsigned EntrySize = 4; - // FIXME: DWARF64 - // We are emitting the header for a contribution to the string offsets - // table. The header consists of an entry with the contribution's - // size (not including the size of the length field), the DWARF version and - // 2 bytes of padding. - Asm->emitInt32(StrPool.size() * EntrySize + 4); - Asm->emitInt16(Asm->getDwarfVersion()); - Asm->emitInt16(0); - // Define the symbol that marks the start of the contribution. It is - // referenced by most unit headers via DW_AT_str_offsets_base. - // Split units do not use the attribute. - if (StringOffsetsStartSym) - Asm->OutStreamer->EmitLabel(StringOffsetsStartSym); -} - // Emit the various dwarf units to the unit section USection with // the abbreviations going into ASection. void DwarfFile::emitUnits(bool UseOffsets) { diff --git a/lib/CodeGen/AsmPrinter/DwarfFile.h b/lib/CodeGen/AsmPrinter/DwarfFile.h index 272a26851b7..8dfbc4e1c43 100644 --- a/lib/CodeGen/AsmPrinter/DwarfFile.h +++ b/lib/CodeGen/AsmPrinter/DwarfFile.h @@ -91,9 +91,6 @@ public: /// Add a unit to the list of CUs. void addUnit(std::unique_ptr U); - /// Emit the string table offsets header. - void emitStringOffsetsTableHeader(MCSection *Section); - /// Emit all of the units to the section listed with the given /// abbreviation section. void emitUnits(bool UseOffsets); diff --git a/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp b/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp index f2964673a6b..a61fa83cfb0 100644 --- a/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp +++ b/lib/CodeGen/AsmPrinter/DwarfStringPool.cpp @@ -39,6 +39,28 @@ DwarfStringPool::EntryRef DwarfStringPool::getEntry(AsmPrinter &Asm, return EntryRef(*I.first); } +void DwarfStringPool::emitStringOffsetsTableHeader(AsmPrinter &Asm, + MCSection *Section, + MCSymbol *StartSym) { + if (empty()) + return; + Asm.OutStreamer->SwitchSection(Section); + unsigned EntrySize = 4; + // FIXME: DWARF64 + // We are emitting the header for a contribution to the string offsets + // table. The header consists of an entry with the contribution's + // size (not including the size of the length field), the DWARF version and + // 2 bytes of padding. + Asm.emitInt32(size() * EntrySize + 4); + Asm.emitInt16(Asm.getDwarfVersion()); + Asm.emitInt16(0); + // Define the symbol that marks the start of the contribution. It is + // referenced by most unit headers via DW_AT_str_offsets_base. + // Split units do not use the attribute. + if (StartSym) + Asm.OutStreamer->EmitLabel(StartSym); +} + void DwarfStringPool::emit(AsmPrinter &Asm, MCSection *StrSection, MCSection *OffsetSection, bool UseRelativeOffsets) { if (Pool.empty()) diff --git a/lib/CodeGen/AsmPrinter/DwarfStringPool.h b/lib/CodeGen/AsmPrinter/DwarfStringPool.h index 069c124d1a7..6e6988ea4ad 100644 --- a/lib/CodeGen/AsmPrinter/DwarfStringPool.h +++ b/lib/CodeGen/AsmPrinter/DwarfStringPool.h @@ -19,6 +19,7 @@ namespace llvm { class AsmPrinter; class MCSection; +class MCSymbol; // Collection of strings for this unit and assorted symbols. // A String->Symbol mapping of strings used by indirect @@ -36,6 +37,9 @@ public: DwarfStringPool(BumpPtrAllocator &A, AsmPrinter &Asm, StringRef Prefix); + void emitStringOffsetsTableHeader(AsmPrinter &Asm, MCSection *OffsetSection, + MCSymbol *StartSym); + void emit(AsmPrinter &Asm, MCSection *StrSection, MCSection *OffsetSection = nullptr, bool UseRelativeOffsets = false); diff --git a/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp b/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp index 6b26318802a..442dea3c52f 100644 --- a/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp +++ b/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp @@ -67,12 +67,21 @@ void TestAllForms() { const uint32_t Dwarf32Values[] = {1, 2, 3, 4, 5, 6, 7, 8}; const char *StringValue = "Hello"; const char *StrpValue = "World"; + const char *StrxValue = "Indexed"; + const char *Strx1Value = "Indexed1"; + const char *Strx2Value = "Indexed2"; + const char *Strx3Value = "Indexed3"; + const char *Strx4Value = "Indexed4"; auto ExpectedDG = dwarfgen::Generator::create(Triple, Version); ASSERT_THAT_EXPECTED(ExpectedDG, Succeeded()); dwarfgen::Generator *DG = ExpectedDG.get().get(); dwarfgen::CompileUnit &CU = DG->addCompileUnit(); dwarfgen::DIE CUDie = CU.getUnitDIE(); + + if (Version >= 5) + CUDie.addStrOffsetsBaseAttribute(); + uint16_t Attr = DW_AT_lo_user; //---------------------------------------------------------------------- @@ -122,6 +131,19 @@ void TestAllForms() { const auto Attr_DW_FORM_string = static_cast(Attr++); CUDie.addAttribute(Attr_DW_FORM_string, DW_FORM_string, StringValue); + const auto Attr_DW_FORM_strx = static_cast(Attr++); + const auto Attr_DW_FORM_strx1 = static_cast(Attr++); + const auto Attr_DW_FORM_strx2 = static_cast(Attr++); + const auto Attr_DW_FORM_strx3 = static_cast(Attr++); + const auto Attr_DW_FORM_strx4 = static_cast(Attr++); + if (Version >= 5) { + CUDie.addAttribute(Attr_DW_FORM_strx, DW_FORM_strx, StrxValue); + CUDie.addAttribute(Attr_DW_FORM_strx1, DW_FORM_strx1, Strx1Value); + CUDie.addAttribute(Attr_DW_FORM_strx2, DW_FORM_strx2, Strx2Value); + CUDie.addAttribute(Attr_DW_FORM_strx3, DW_FORM_strx3, Strx3Value); + CUDie.addAttribute(Attr_DW_FORM_strx4, DW_FORM_strx4, Strx4Value); + } + const auto Attr_DW_FORM_strp = static_cast(Attr++); CUDie.addAttribute(Attr_DW_FORM_strp, DW_FORM_strp, StrpValue); @@ -281,11 +303,33 @@ void TestAllForms() { //---------------------------------------------------------------------- auto ExtractedStringValue = toString(DieDG.find(Attr_DW_FORM_string)); EXPECT_TRUE((bool)ExtractedStringValue); - EXPECT_TRUE(strcmp(StringValue, *ExtractedStringValue) == 0); + EXPECT_STREQ(StringValue, *ExtractedStringValue); + + if (Version >= 5) { + auto ExtractedStrxValue = toString(DieDG.find(Attr_DW_FORM_strx)); + EXPECT_TRUE((bool)ExtractedStrxValue); + EXPECT_STREQ(StrxValue, *ExtractedStrxValue); + + auto ExtractedStrx1Value = toString(DieDG.find(Attr_DW_FORM_strx1)); + EXPECT_TRUE((bool)ExtractedStrx1Value); + EXPECT_STREQ(Strx1Value, *ExtractedStrx1Value); + + auto ExtractedStrx2Value = toString(DieDG.find(Attr_DW_FORM_strx2)); + EXPECT_TRUE((bool)ExtractedStrx2Value); + EXPECT_STREQ(Strx2Value, *ExtractedStrx2Value); + + auto ExtractedStrx3Value = toString(DieDG.find(Attr_DW_FORM_strx3)); + EXPECT_TRUE((bool)ExtractedStrx3Value); + EXPECT_STREQ(Strx3Value, *ExtractedStrx3Value); + + auto ExtractedStrx4Value = toString(DieDG.find(Attr_DW_FORM_strx4)); + EXPECT_TRUE((bool)ExtractedStrx4Value); + EXPECT_STREQ(Strx4Value, *ExtractedStrx4Value); + } auto ExtractedStrpValue = toString(DieDG.find(Attr_DW_FORM_strp)); EXPECT_TRUE((bool)ExtractedStrpValue); - EXPECT_TRUE(strcmp(StrpValue, *ExtractedStrpValue) == 0); + EXPECT_STREQ(StrpValue, *ExtractedStrpValue); //---------------------------------------------------------------------- // Test reference forms diff --git a/unittests/DebugInfo/DWARF/DwarfGenerator.cpp b/unittests/DebugInfo/DWARF/DwarfGenerator.cpp index 4f4a7375eaa..adc400c2fd0 100644 --- a/unittests/DebugInfo/DWARF/DwarfGenerator.cpp +++ b/unittests/DebugInfo/DWARF/DwarfGenerator.cpp @@ -54,17 +54,36 @@ void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, uint64_t U) { DIEInteger(U)); } +void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, const MCExpr &Expr) { + auto &DG = CU->getGenerator(); + Die->addValue(DG.getAllocator(), static_cast(A), Form, + DIEExpr(&Expr)); +} + void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, StringRef String) { auto &DG = CU->getGenerator(); - if (Form == DW_FORM_string) { + switch (Form) { + case DW_FORM_string: Die->addValue(DG.getAllocator(), static_cast(A), Form, new (DG.getAllocator()) DIEInlineString(String, DG.getAllocator())); - } else { + break; + + case DW_FORM_strp: + case DW_FORM_GNU_str_index: + case DW_FORM_strx: + case DW_FORM_strx1: + case DW_FORM_strx2: + case DW_FORM_strx3: + case DW_FORM_strx4: Die->addValue( DG.getAllocator(), static_cast(A), Form, DIEString(DG.getStringPool().getEntry(*DG.getAsmPrinter(), String))); + break; + + default: + llvm_unreachable("Unhandled form!"); } } @@ -97,6 +116,24 @@ void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form) { DIEInteger(1)); } +void dwarfgen::DIE::addStrOffsetsBaseAttribute() { + auto &DG = CU->getGenerator(); + auto &MC = *DG.getMCContext(); + AsmPrinter *Asm = DG.getAsmPrinter(); + + const MCSymbol *SectionStart = + Asm->getObjFileLowering().getDwarfStrOffSection()->getBeginSymbol(); + + const MCExpr *Expr = + MCSymbolRefExpr::create(DG.getStringOffsetsStartSym(), MC); + + if (!Asm->MAI->doesDwarfUseRelocationsAcrossSections()) + Expr = MCBinaryExpr::createSub( + Expr, MCSymbolRefExpr::create(SectionStart, MC), MC); + + addAttribute(dwarf::DW_AT_str_offsets_base, DW_FORM_sec_offset, *Expr); +} + dwarfgen::DIE dwarfgen::DIE::addChild(dwarf::Tag Tag) { auto &DG = CU->getGenerator(); return dwarfgen::DIE(CU, @@ -429,6 +466,7 @@ llvm::Error dwarfgen::Generator::init(Triple TheTriple, uint16_t V) { Asm->setDwarfVersion(Version); StringPool = llvm::make_unique(Allocator, *Asm, StringRef()); + StringOffsetsStartSym = Asm->createTempSymbol("str_offsets_base"); return Error::success(); } @@ -450,7 +488,12 @@ StringRef dwarfgen::Generator::generate() { CU->setLength(CUOffset - 4); } Abbreviations.Emit(Asm.get(), TLOF->getDwarfAbbrevSection()); - StringPool->emit(*Asm, TLOF->getDwarfStrSection()); + + StringPool->emitStringOffsetsTableHeader(*Asm, TLOF->getDwarfStrOffSection(), + StringOffsetsStartSym); + StringPool->emit(*Asm, TLOF->getDwarfStrSection(), + TLOF->getDwarfStrOffSection()); + MS->SwitchSection(TLOF->getDwarfInfoSection()); for (auto &CU : CompileUnits) { uint16_t Version = CU->getVersion(); diff --git a/unittests/DebugInfo/DWARF/DwarfGenerator.h b/unittests/DebugInfo/DWARF/DwarfGenerator.h index 72cb0696b97..40ecaa98d05 100644 --- a/unittests/DebugInfo/DWARF/DwarfGenerator.h +++ b/unittests/DebugInfo/DWARF/DwarfGenerator.h @@ -89,6 +89,14 @@ public: /// \param U the unsigned integer to encode. void addAttribute(uint16_t Attr, dwarf::Form Form, uint64_t U); + /// Add an attribute value to be encoded as a DIEExpr + /// + /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that + /// represents a user defined DWARF attribute. + /// \param Form the dwarf::Form to use when encoding the attribute. + /// \param Expr the MC expression used to compute the value. + void addAttribute(uint16_t Attr, dwarf::Form Form, const MCExpr &Expr); + /// Add an attribute value to be encoded as a DIEString or DIEInlinedString. /// /// \param Attr a dwarf::Attribute enumeration value or any uint16_t that @@ -123,6 +131,9 @@ public: /// \param S the size in bytes of the data pointed to by P . void addAttribute(uint16_t Attr, dwarf::Form Form, const void *P, size_t S); + /// Add a DW_AT_str_offsets_base attribute to this DIE. + void addStrOffsetsBaseAttribute(); + /// Add a new child to this DIE object. /// /// \param Tag the dwarf::Tag to assing to the llvm::DIE object. @@ -242,6 +253,8 @@ class Generator { std::vector> LineTables; DIEAbbrevSet Abbreviations; + MCSymbol *StringOffsetsStartSym; + SmallString<4096> FileBytes; /// The stream we use to generate the DWARF into as an ELF file. std::unique_ptr Stream; @@ -293,6 +306,7 @@ public: MCContext *getMCContext() const { return MC.get(); } DIEAbbrevSet &getAbbrevSet() { return Abbreviations; } DwarfStringPool &getStringPool() { return *StringPool; } + MCSymbol *getStringOffsetsStartSym() const { return StringOffsetsStartSym; } /// Save the generated DWARF file to disk. ///