diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h --- a/llvm/include/llvm/MC/MCDwarf.h +++ b/llvm/include/llvm/MC/MCDwarf.h @@ -62,6 +62,9 @@ /// Emit the .debug_line_str section if appropriate. void emitSection(MCStreamer *MCOS); + + /// Returns finalized section. + SmallString<0> getFinalizedData(); }; /// Instances of this class represent the name of the dwarf .file directive and diff --git a/llvm/include/llvm/MC/StringTableBuilder.h b/llvm/include/llvm/MC/StringTableBuilder.h --- a/llvm/include/llvm/MC/StringTableBuilder.h +++ b/llvm/include/llvm/MC/StringTableBuilder.h @@ -85,7 +85,6 @@ void write(raw_ostream &OS) const; void write(uint8_t *Buf) const; -private: bool isFinalized() const { return Finalized; } }; diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp --- a/llvm/lib/MC/MCDwarf.cpp +++ b/llvm/lib/MC/MCDwarf.cpp @@ -334,12 +334,18 @@ // Switch to the .debug_line_str section. MCOS->SwitchSection( MCOS->getContext().getObjectFileInfo()->getDwarfLineStrSection()); + SmallString<0> Data = getFinalizedData(); + MCOS->emitBinaryData(Data.str()); +} + +SmallString<0> MCDwarfLineStr::getFinalizedData() { // Emit the strings without perturbing the offsets we used. - LineStrings.finalizeInOrder(); + if (!LineStrings.isFinalized()) + LineStrings.finalizeInOrder(); SmallString<0> Data; Data.resize(LineStrings.getSize()); LineStrings.write((uint8_t *)Data.data()); - MCOS->emitBinaryData(Data.str()); + return Data; } void MCDwarfLineStr::emitRef(MCStreamer *MCOS, StringRef Path) { diff --git a/llvm/unittests/MC/DwarfLineTableHeaders.cpp b/llvm/unittests/MC/DwarfLineTableHeaders.cpp --- a/llvm/unittests/MC/DwarfLineTableHeaders.cpp +++ b/llvm/unittests/MC/DwarfLineTableHeaders.cpp @@ -29,6 +29,7 @@ #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" #include "gtest/gtest.h" +#include using namespace llvm; @@ -131,8 +132,13 @@ LineEntries.push_back(LineEntry); MCDwarfLineTable::emitOne(TheStreamer, Section, LineEntries); TheStreamer->emitLabel(LineEndSym); - if (LineStr) - LineStr->emitSection(TheStreamer); + if (LineStr) { + SmallString<0> Data = LineStr->getFinalizedData(); + TheStreamer->SwitchSection(TheStreamer->getContext() + .getObjectFileInfo() + ->getDwarfLineStrSection()); + TheStreamer->emitBinaryData(Data.str()); + } } /// Check contents of .debug_line section @@ -156,15 +162,37 @@ llvm_unreachable(".debug_line not found"); } + /// Check contents of .debug_line_str section + void verifyDebugLineStrContents(const llvm::object::ObjectFile &E) { + for (const llvm::object::SectionRef &Section : E.sections()) { + Expected SectionNameOrErr = Section.getName(); + ASSERT_TRUE(static_cast(SectionNameOrErr)); + StringRef SectionName = *SectionNameOrErr; + if (SectionName.empty() || SectionName != ".debug_line_str") + continue; + Expected ContentsOrErr = Section.getContents(); + ASSERT_TRUE(static_cast(ContentsOrErr)); + StringRef Contents = *ContentsOrErr; + ASSERT_TRUE(Contents.find("dir") != StringRef::npos); + ASSERT_TRUE(Contents.find("file") != StringRef::npos); + ASSERT_TRUE(Contents.size() == 9); + return; + } + llvm_unreachable(".debug_line_str not found"); + } + /// Open ObjFileData as an object file and read its .debug_line section - void readAndCheckDebugLineContents(StringRef ObjFileData, - ArrayRef Expected) { + void readAndCheckDebugContents(StringRef ObjFileData, + ArrayRef Expected, uint8_t DwarfVersion) { std::unique_ptr MB = MemoryBuffer::getMemBuffer(ObjFileData, "", false); std::unique_ptr Bin = cantFail(llvm::object::createBinary(MB->getMemBufferRef())); if (auto *E = dyn_cast(&*Bin)) { - return verifyDebugLineContents(*E, Expected); + verifyDebugLineContents(*E, Expected); + if (DwarfVersion >= 5) + verifyDebugLineStrContents(*E); + return; } llvm_unreachable("ELF object file not found"); } @@ -178,20 +206,21 @@ SmallString<0> EmittedBinContents; raw_svector_ostream VecOS(EmittedBinContents); StreamerContext C = createStreamer(VecOS); - C.Ctx->setDwarfVersion(4); + constexpr uint8_t DwarfVersion = 4; + C.Ctx->setDwarfVersion(DwarfVersion); emitDebugLineSection(C); C.Streamer->Finish(); - readAndCheckDebugLineContents( + readAndCheckDebugContents( EmittedBinContents.str(), {/* Total length=*/0x30, 0, 0, 0, - /* DWARF version=*/4, 0, + /* DWARF version=*/DwarfVersion, 0, /* Prologue length=*/0x14, 0, 0, 0, /* min_inst_length=*/1, /*max_ops_per_inst=*/1, /* default_is_stmt=*/DWARF2_LINE_DEFAULT_IS_STMT, /* line_base=*/static_cast(-5), /* line_range=*/14, - /* opcode_base=*/13}); + /* opcode_base=*/13}, DwarfVersion); } TEST_F(DwarfLineTableHeaders, TestDWARF5HeaderEmission) { @@ -201,13 +230,14 @@ SmallString<0> EmittedBinContents; raw_svector_ostream VecOS(EmittedBinContents); StreamerContext C = createStreamer(VecOS); - C.Ctx->setDwarfVersion(5); + constexpr uint8_t DwarfVersion = 5; + C.Ctx->setDwarfVersion(DwarfVersion); emitDebugLineSection(C); C.Streamer->Finish(); - readAndCheckDebugLineContents( + readAndCheckDebugContents( EmittedBinContents.str(), {/* Total length=*/0x43, 0, 0, 0, - /* DWARF version=*/5, 0, + /* DWARF version=*/DwarfVersion, 0, /* ptr size=*/8, /* segment=*/0, /* Prologue length=*/0x25, 0, 0, 0, @@ -216,5 +246,5 @@ /* default_is_stmt=*/DWARF2_LINE_DEFAULT_IS_STMT, /* line_base=*/static_cast(-5), /* line_range=*/14, - /* opcode_base=*/13}); + /* opcode_base=*/13}, DwarfVersion); }