[llvm] 050edef - [MC] Make MCDwarfLineStr class public

Rafael Auler via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 30 12:32:24 PDT 2021


Author: Maksim Panchenko
Date: 2021-09-30T12:31:59-07:00
New Revision: 050edef8538e82264928ddf1840e785f1544ca7f

URL: https://github.com/llvm/llvm-project/commit/050edef8538e82264928ddf1840e785f1544ca7f
DIFF: https://github.com/llvm/llvm-project/commit/050edef8538e82264928ddf1840e785f1544ca7f.diff

LOG: [MC] Make MCDwarfLineStr class public

Add MCDwarfLineStr class to the public API.

Note that MCDwarfLineTableHeader::Emit(), takes MCDwarfLineStr as
an Optional<> parameter making it impossible to use the API if the class
is not publicly defined.

Reviewed By: alexander-shaposhnikov

Differential Revision: https://reviews.llvm.org/D109412

Added: 
    llvm/unittests/MC/DwarfLineTableHeaders.cpp

Modified: 
    llvm/include/llvm/MC/MCDwarf.h
    llvm/lib/MC/MCDwarf.cpp
    llvm/unittests/MC/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h
index 23efdc70609b6..84386f1d40cd1 100644
--- a/llvm/include/llvm/MC/MCDwarf.h
+++ b/llvm/include/llvm/MC/MCDwarf.h
@@ -20,6 +20,7 @@
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/MC/MCSection.h"
+#include "llvm/MC/StringTableBuilder.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/MD5.h"
 #include <cassert>
@@ -34,7 +35,6 @@ namespace llvm {
 template <typename T> class ArrayRef;
 class MCAsmBackend;
 class MCContext;
-class MCDwarfLineStr;
 class MCObjectStreamer;
 class MCStreamer;
 class MCSymbol;
@@ -47,6 +47,24 @@ namespace mcdwarf {
 MCSymbol *emitListsTableHeaderStart(MCStreamer &S);
 } // namespace mcdwarf
 
+/// Manage the .debug_line_str section contents, if we use it.
+class MCDwarfLineStr {
+  MCSymbol *LineStrLabel = nullptr;
+  StringTableBuilder LineStrings{StringTableBuilder::DWARF};
+  bool UseRelocs = false;
+
+public:
+  /// Construct an instance that can emit .debug_line_str (for use in a normal
+  /// v5 line table).
+  explicit MCDwarfLineStr(MCContext &Ctx);
+
+  /// Emit a reference to the string.
+  void emitRef(MCStreamer *MCOS, StringRef Path);
+
+  /// Emit the .debug_line_str section if appropriate.
+  void emitSection(MCStreamer *MCOS);
+};
+
 /// Instances of this class represent the name of the dwarf .file directive and
 /// its associated dwarf file number in the MC file. MCDwarfFile's are created
 /// and uniqued by the MCContext class. In Dwarf 4 file numbers start from 1;
@@ -317,6 +335,11 @@ class MCDwarfLineTable {
   void emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params,
               Optional<MCDwarfLineStr> &LineStr) const;
 
+  // This emits a single line table associated with a given Section.
+  static void
+  emitOne(MCStreamer *MCOS, MCSection *Section,
+          const MCLineSection::MCDwarfLineEntryCollection &LineEntries);
+
   Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
                                 Optional<MD5::MD5Result> Checksum,
                                 Optional<StringRef> Source,

diff  --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index 27bb7a1031652..ef0cc8108e1d0 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -27,7 +27,6 @@
 #include "llvm/MC/MCSection.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSymbol.h"
-#include "llvm/MC/StringTableBuilder.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/EndianStream.h"
@@ -66,29 +65,6 @@ MCSymbol *mcdwarf::emitListsTableHeaderStart(MCStreamer &S) {
   return End;
 }
 
-/// Manage the .debug_line_str section contents, if we use it.
-class llvm::MCDwarfLineStr {
-  MCSymbol *LineStrLabel = nullptr;
-  StringTableBuilder LineStrings{StringTableBuilder::DWARF};
-  bool UseRelocs = false;
-
-public:
-  /// Construct an instance that can emit .debug_line_str (for use in a normal
-  /// v5 line table).
-  explicit MCDwarfLineStr(MCContext &Ctx) {
-    UseRelocs = Ctx.getAsmInfo()->doesDwarfUseRelocationsAcrossSections();
-    if (UseRelocs)
-      LineStrLabel =
-          Ctx.getObjectFileInfo()->getDwarfLineStrSection()->getBeginSymbol();
-  }
-
-  /// Emit a reference to the string.
-  void emitRef(MCStreamer *MCOS, StringRef Path);
-
-  /// Emit the .debug_line_str section if appropriate.
-  void emitSection(MCStreamer *MCOS);
-};
-
 static inline uint64_t ScaleAddrDelta(MCContext &Context, uint64_t AddrDelta) {
   unsigned MinInsnLength = Context.getAsmInfo()->getMinInstAlignment();
   if (MinInsnLength == 1)
@@ -100,6 +76,13 @@ static inline uint64_t ScaleAddrDelta(MCContext &Context, uint64_t AddrDelta) {
   return AddrDelta / MinInsnLength;
 }
 
+MCDwarfLineStr::MCDwarfLineStr(MCContext &Ctx) {
+  UseRelocs = Ctx.getAsmInfo()->doesDwarfUseRelocationsAcrossSections();
+  if (UseRelocs)
+    LineStrLabel =
+        Ctx.getObjectFileInfo()->getDwarfLineStrSection()->getBeginSymbol();
+}
+
 //
 // This is called when an instruction is assembled into the specified section
 // and if there is information from the last .loc directive that has yet to have
@@ -162,7 +145,7 @@ makeStartPlusIntExpr(MCContext &Ctx, const MCSymbol &Start, int IntVal) {
 // This emits the Dwarf line table for the specified section from the entries
 // in the LineSection.
 //
-static inline void emitDwarfLineTable(
+void MCDwarfLineTable::emitOne(
     MCStreamer *MCOS, MCSection *Section,
     const MCLineSection::MCDwarfLineEntryCollection &LineEntries) {
   unsigned FileNum = 1;
@@ -522,7 +505,7 @@ void MCDwarfLineTable::emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params,
 
   // Put out the line tables.
   for (const auto &LineSec : MCLineSections.getMCLineEntries())
-    emitDwarfLineTable(MCOS, LineSec.first, LineSec.second);
+    emitOne(MCOS, LineSec.first, LineSec.second);
 
   // This is the end of the section, so set the value of the symbol at the end
   // of this section (that was used in a previous expression).

diff  --git a/llvm/unittests/MC/CMakeLists.txt b/llvm/unittests/MC/CMakeLists.txt
index 3827a2b4fc435..c0ba2f910c786 100644
--- a/llvm/unittests/MC/CMakeLists.txt
+++ b/llvm/unittests/MC/CMakeLists.txt
@@ -14,6 +14,7 @@ set(LLVM_LINK_COMPONENTS
 add_llvm_unittest(MCTests
   Disassembler.cpp
   DwarfLineTables.cpp
+  DwarfLineTableHeaders.cpp
   MCInstPrinter.cpp
   StringTableBuilderTest.cpp
   TargetRegistry.cpp

diff  --git a/llvm/unittests/MC/DwarfLineTableHeaders.cpp b/llvm/unittests/MC/DwarfLineTableHeaders.cpp
new file mode 100644
index 0000000000000..3b9ff76abe9e6
--- /dev/null
+++ b/llvm/unittests/MC/DwarfLineTableHeaders.cpp
@@ -0,0 +1,218 @@
+//===- llvm/unittest/MC/DwarfLineTableHeaders.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/ADT/STLExtras.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+class DwarfLineTableHeaders : public ::testing::Test {
+public:
+  const char *TripleName = "x86_64-pc-linux";
+  std::unique_ptr<MCRegisterInfo> MRI;
+  std::unique_ptr<MCAsmInfo> MAI;
+  std::unique_ptr<const MCSubtargetInfo> STI;
+  const Target *TheTarget;
+
+  struct StreamerContext {
+    std::unique_ptr<MCObjectFileInfo> MOFI;
+    std::unique_ptr<MCContext> Ctx;
+    std::unique_ptr<const MCInstrInfo> MII;
+    std::unique_ptr<MCStreamer> Streamer;
+  };
+
+  DwarfLineTableHeaders() {
+    llvm::InitializeAllTargetInfos();
+    llvm::InitializeAllTargetMCs();
+    llvm::InitializeAllDisassemblers();
+
+    // If we didn't build x86, do not run the test.
+    std::string Error;
+    TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
+    if (!TheTarget)
+      return;
+
+    MRI.reset(TheTarget->createMCRegInfo(TripleName));
+    MCTargetOptions MCOptions;
+    MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
+    STI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
+  }
+
+  /// Create all data structures necessary to operate an assembler
+  StreamerContext createStreamer(raw_pwrite_stream &OS) {
+    StreamerContext Res;
+    Res.Ctx =
+        std::make_unique<MCContext>(Triple(TripleName), MAI.get(), MRI.get(),
+                                    /*MSTI=*/nullptr);
+    Res.MOFI.reset(TheTarget->createMCObjectFileInfo(*Res.Ctx.get(),
+                                                     /*PIC=*/false));
+    Res.Ctx->setObjectFileInfo(Res.MOFI.get());
+
+    Res.MII.reset(TheTarget->createMCInstrInfo());
+    MCCodeEmitter *MCE =
+        TheTarget->createMCCodeEmitter(*Res.MII, *MRI, *Res.Ctx);
+    MCAsmBackend *MAB =
+        TheTarget->createMCAsmBackend(*STI, *MRI, MCTargetOptions());
+    std::unique_ptr<MCObjectWriter> OW = MAB->createObjectWriter(OS);
+    Res.Streamer.reset(TheTarget->createMCObjectStreamer(
+        Triple(TripleName), *Res.Ctx, std::unique_ptr<MCAsmBackend>(MAB),
+        std::move(OW), std::unique_ptr<MCCodeEmitter>(MCE), *STI,
+        /* RelaxAll */ false,
+        /* IncrementalLinkerCompatible */ false,
+        /* DWARFMustBeAtTheEnd */ false));
+    return Res;
+  }
+
+  /// Emit a .debug_line section with the given context parameters
+  void emitDebugLineSection(StreamerContext &C) {
+    MCContext &Ctx = *C.Ctx;
+    MCStreamer *TheStreamer = C.Streamer.get();
+    MCAssembler &Assembler =
+        static_cast<MCObjectStreamer *>(TheStreamer)->getAssembler();
+    TheStreamer->initSections(false, *STI);
+
+    // Create a mock function
+    MCSection *Section = C.MOFI->getTextSection();
+    Section->setHasInstructions(true);
+    TheStreamer->SwitchSection(Section);
+    TheStreamer->emitCFIStartProc(true);
+
+    // Create a mock dwarfloc
+    Ctx.setCurrentDwarfLoc(/*FileNo=*/0, /*Line=*/1, /*Column=*/1, /*Flags=*/0,
+                           /*Isa=*/0, /*Discriminator=*/0);
+    MCDwarfLoc Loc = Ctx.getCurrentDwarfLoc();
+    MCSymbol *LineSym = Ctx.createTempSymbol();
+    // Set the value of the symbol to use for the MCDwarfLineEntry.
+    TheStreamer->emitLabel(LineSym);
+    TheStreamer->emitNops(4, 1, SMLoc(), *STI);
+    TheStreamer->emitCFIEndProc();
+
+    // Start emission of .debug_line
+    TheStreamer->SwitchSection(C.MOFI->getDwarfLineSection());
+    MCDwarfLineTableHeader Header;
+    MCDwarfLineTableParams Params = Assembler.getDWARFLinetableParams();
+    Optional<MCDwarfLineStr> LineStr(None);
+    if (Ctx.getDwarfVersion() >= 5) {
+      LineStr = MCDwarfLineStr(Ctx);
+      Header.setRootFile("dir", "file", None, None);
+    }
+    MCSymbol *LineEndSym = Header.Emit(TheStreamer, Params, LineStr).second;
+
+    // Put out the line tables.
+    MCLineSection::MCDwarfLineEntryCollection LineEntries;
+    MCDwarfLineEntry LineEntry(LineSym, Loc);
+    LineEntries.push_back(LineEntry);
+    MCDwarfLineTable::emitOne(TheStreamer, Section, LineEntries);
+    TheStreamer->emitLabel(LineEndSym);
+    if (LineStr)
+      LineStr->emitSection(TheStreamer);
+  }
+
+  /// Check contents of .debug_line section
+  void verifyDebugLineContents(const llvm::object::ObjectFile &E,
+                               ArrayRef<uint8_t> ExpectedEncoding) {
+    for (const llvm::object::SectionRef &Section : E.sections()) {
+      Expected<StringRef> SectionNameOrErr = Section.getName();
+      ASSERT_TRUE(static_cast<bool>(SectionNameOrErr));
+      StringRef SectionName = *SectionNameOrErr;
+      if (SectionName.empty() || SectionName != ".debug_line")
+        continue;
+      Expected<StringRef> ContentsOrErr = Section.getContents();
+      ASSERT_TRUE(static_cast<bool>(ContentsOrErr));
+      StringRef Contents = *ContentsOrErr;
+      ASSERT_TRUE(Contents.size() > ExpectedEncoding.size());
+      EXPECT_EQ(
+          arrayRefFromStringRef(Contents.slice(0, ExpectedEncoding.size())),
+          ExpectedEncoding);
+      return;
+    }
+    llvm_unreachable(".debug_line not found");
+  }
+
+  ///  Open ObjFileData as an object file and read its .debug_line section
+  void readAndCheckDebugLineContents(StringRef ObjFileData,
+                                     ArrayRef<uint8_t> Expected) {
+    std::unique_ptr<MemoryBuffer> MB =
+        MemoryBuffer::getMemBuffer(ObjFileData, "", false);
+    std::unique_ptr<object::Binary> Bin =
+        cantFail(llvm::object::createBinary(MB->getMemBufferRef()));
+    if (auto *E = dyn_cast<llvm::object::ELFObjectFileBase>(&*Bin)) {
+      return verifyDebugLineContents(*E, Expected);
+    }
+    llvm_unreachable("ELF object file not found");
+  }
+};
+} // namespace
+
+TEST_F(DwarfLineTableHeaders, TestDWARF4HeaderEmission) {
+  if (!MRI)
+    return;
+
+  SmallString<0> EmittedBinContents;
+  raw_svector_ostream VecOS(EmittedBinContents);
+  StreamerContext C = createStreamer(VecOS);
+  C.Ctx->setDwarfVersion(4);
+  emitDebugLineSection(C);
+  C.Streamer->Finish();
+  readAndCheckDebugLineContents(
+      EmittedBinContents.str(),
+      {/*    Total length=*/0x30, 0, 0, 0,
+       /*   DWARF version=*/4, 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<uint8_t>(-5),
+       /*      line_range=*/14,
+       /*     opcode_base=*/13});
+}
+
+TEST_F(DwarfLineTableHeaders, TestDWARF5HeaderEmission) {
+  if (!MRI)
+    return;
+
+  SmallString<0> EmittedBinContents;
+  raw_svector_ostream VecOS(EmittedBinContents);
+  StreamerContext C = createStreamer(VecOS);
+  C.Ctx->setDwarfVersion(5);
+  emitDebugLineSection(C);
+  C.Streamer->Finish();
+  readAndCheckDebugLineContents(
+      EmittedBinContents.str(),
+      {/*    Total length=*/0x43, 0, 0, 0,
+       /*   DWARF version=*/5, 0,
+       /*        ptr size=*/8,
+       /*         segment=*/0,
+       /* Prologue length=*/0x25, 0, 0, 0,
+       /* min_inst_length=*/1,
+       /*max_ops_per_inst=*/1,
+       /* default_is_stmt=*/DWARF2_LINE_DEFAULT_IS_STMT,
+       /*       line_base=*/static_cast<uint8_t>(-5),
+       /*      line_range=*/14,
+       /*     opcode_base=*/13});
+}


        


More information about the llvm-commits mailing list