Skip to content

Commit 050edef

Browse files
maksfbrafaelauler
authored andcommitted
[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
1 parent 4195ed9 commit 050edef

File tree

4 files changed

+252
-27
lines changed

4 files changed

+252
-27
lines changed

llvm/include/llvm/MC/MCDwarf.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "llvm/ADT/StringMap.h"
2121
#include "llvm/ADT/StringRef.h"
2222
#include "llvm/MC/MCSection.h"
23+
#include "llvm/MC/StringTableBuilder.h"
2324
#include "llvm/Support/Error.h"
2425
#include "llvm/Support/MD5.h"
2526
#include <cassert>
@@ -34,7 +35,6 @@ namespace llvm {
3435
template <typename T> class ArrayRef;
3536
class MCAsmBackend;
3637
class MCContext;
37-
class MCDwarfLineStr;
3838
class MCObjectStreamer;
3939
class MCStreamer;
4040
class MCSymbol;
@@ -47,6 +47,24 @@ namespace mcdwarf {
4747
MCSymbol *emitListsTableHeaderStart(MCStreamer &S);
4848
} // namespace mcdwarf
4949

50+
/// Manage the .debug_line_str section contents, if we use it.
51+
class MCDwarfLineStr {
52+
MCSymbol *LineStrLabel = nullptr;
53+
StringTableBuilder LineStrings{StringTableBuilder::DWARF};
54+
bool UseRelocs = false;
55+
56+
public:
57+
/// Construct an instance that can emit .debug_line_str (for use in a normal
58+
/// v5 line table).
59+
explicit MCDwarfLineStr(MCContext &Ctx);
60+
61+
/// Emit a reference to the string.
62+
void emitRef(MCStreamer *MCOS, StringRef Path);
63+
64+
/// Emit the .debug_line_str section if appropriate.
65+
void emitSection(MCStreamer *MCOS);
66+
};
67+
5068
/// Instances of this class represent the name of the dwarf .file directive and
5169
/// its associated dwarf file number in the MC file. MCDwarfFile's are created
5270
/// and uniqued by the MCContext class. In Dwarf 4 file numbers start from 1;
@@ -317,6 +335,11 @@ class MCDwarfLineTable {
317335
void emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params,
318336
Optional<MCDwarfLineStr> &LineStr) const;
319337

338+
// This emits a single line table associated with a given Section.
339+
static void
340+
emitOne(MCStreamer *MCOS, MCSection *Section,
341+
const MCLineSection::MCDwarfLineEntryCollection &LineEntries);
342+
320343
Expected<unsigned> tryGetFile(StringRef &Directory, StringRef &FileName,
321344
Optional<MD5::MD5Result> Checksum,
322345
Optional<StringRef> Source,

llvm/lib/MC/MCDwarf.cpp

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
#include "llvm/MC/MCSection.h"
2828
#include "llvm/MC/MCStreamer.h"
2929
#include "llvm/MC/MCSymbol.h"
30-
#include "llvm/MC/StringTableBuilder.h"
3130
#include "llvm/Support/Casting.h"
3231
#include "llvm/Support/Endian.h"
3332
#include "llvm/Support/EndianStream.h"
@@ -66,29 +65,6 @@ MCSymbol *mcdwarf::emitListsTableHeaderStart(MCStreamer &S) {
6665
return End;
6766
}
6867

69-
/// Manage the .debug_line_str section contents, if we use it.
70-
class llvm::MCDwarfLineStr {
71-
MCSymbol *LineStrLabel = nullptr;
72-
StringTableBuilder LineStrings{StringTableBuilder::DWARF};
73-
bool UseRelocs = false;
74-
75-
public:
76-
/// Construct an instance that can emit .debug_line_str (for use in a normal
77-
/// v5 line table).
78-
explicit MCDwarfLineStr(MCContext &Ctx) {
79-
UseRelocs = Ctx.getAsmInfo()->doesDwarfUseRelocationsAcrossSections();
80-
if (UseRelocs)
81-
LineStrLabel =
82-
Ctx.getObjectFileInfo()->getDwarfLineStrSection()->getBeginSymbol();
83-
}
84-
85-
/// Emit a reference to the string.
86-
void emitRef(MCStreamer *MCOS, StringRef Path);
87-
88-
/// Emit the .debug_line_str section if appropriate.
89-
void emitSection(MCStreamer *MCOS);
90-
};
91-
9268
static inline uint64_t ScaleAddrDelta(MCContext &Context, uint64_t AddrDelta) {
9369
unsigned MinInsnLength = Context.getAsmInfo()->getMinInstAlignment();
9470
if (MinInsnLength == 1)
@@ -100,6 +76,13 @@ static inline uint64_t ScaleAddrDelta(MCContext &Context, uint64_t AddrDelta) {
10076
return AddrDelta / MinInsnLength;
10177
}
10278

79+
MCDwarfLineStr::MCDwarfLineStr(MCContext &Ctx) {
80+
UseRelocs = Ctx.getAsmInfo()->doesDwarfUseRelocationsAcrossSections();
81+
if (UseRelocs)
82+
LineStrLabel =
83+
Ctx.getObjectFileInfo()->getDwarfLineStrSection()->getBeginSymbol();
84+
}
85+
10386
//
10487
// This is called when an instruction is assembled into the specified section
10588
// 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) {
162145
// This emits the Dwarf line table for the specified section from the entries
163146
// in the LineSection.
164147
//
165-
static inline void emitDwarfLineTable(
148+
void MCDwarfLineTable::emitOne(
166149
MCStreamer *MCOS, MCSection *Section,
167150
const MCLineSection::MCDwarfLineEntryCollection &LineEntries) {
168151
unsigned FileNum = 1;
@@ -522,7 +505,7 @@ void MCDwarfLineTable::emitCU(MCStreamer *MCOS, MCDwarfLineTableParams Params,
522505

523506
// Put out the line tables.
524507
for (const auto &LineSec : MCLineSections.getMCLineEntries())
525-
emitDwarfLineTable(MCOS, LineSec.first, LineSec.second);
508+
emitOne(MCOS, LineSec.first, LineSec.second);
526509

527510
// This is the end of the section, so set the value of the symbol at the end
528511
// of this section (that was used in a previous expression).

llvm/unittests/MC/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ set(LLVM_LINK_COMPONENTS
1414
add_llvm_unittest(MCTests
1515
Disassembler.cpp
1616
DwarfLineTables.cpp
17+
DwarfLineTableHeaders.cpp
1718
MCInstPrinter.cpp
1819
StringTableBuilderTest.cpp
1920
TargetRegistry.cpp
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
//===- llvm/unittest/MC/DwarfLineTableHeaders.cpp -------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/ADT/STLExtras.h"
10+
#include "llvm/BinaryFormat/Dwarf.h"
11+
#include "llvm/MC/MCAsmBackend.h"
12+
#include "llvm/MC/MCAsmInfo.h"
13+
#include "llvm/MC/MCCodeEmitter.h"
14+
#include "llvm/MC/MCContext.h"
15+
#include "llvm/MC/MCDwarf.h"
16+
#include "llvm/MC/MCInstrInfo.h"
17+
#include "llvm/MC/MCObjectStreamer.h"
18+
#include "llvm/MC/MCObjectWriter.h"
19+
#include "llvm/MC/MCRegisterInfo.h"
20+
#include "llvm/MC/MCStreamer.h"
21+
#include "llvm/MC/MCTargetOptions.h"
22+
#include "llvm/Object/Binary.h"
23+
#include "llvm/Object/ELFObjectFile.h"
24+
#include "llvm/Support/FileSystem.h"
25+
#include "llvm/Support/TargetRegistry.h"
26+
#include "llvm/Support/TargetSelect.h"
27+
#include "llvm/Support/ToolOutputFile.h"
28+
#include "gtest/gtest.h"
29+
30+
using namespace llvm;
31+
32+
namespace {
33+
34+
class DwarfLineTableHeaders : public ::testing::Test {
35+
public:
36+
const char *TripleName = "x86_64-pc-linux";
37+
std::unique_ptr<MCRegisterInfo> MRI;
38+
std::unique_ptr<MCAsmInfo> MAI;
39+
std::unique_ptr<const MCSubtargetInfo> STI;
40+
const Target *TheTarget;
41+
42+
struct StreamerContext {
43+
std::unique_ptr<MCObjectFileInfo> MOFI;
44+
std::unique_ptr<MCContext> Ctx;
45+
std::unique_ptr<const MCInstrInfo> MII;
46+
std::unique_ptr<MCStreamer> Streamer;
47+
};
48+
49+
DwarfLineTableHeaders() {
50+
llvm::InitializeAllTargetInfos();
51+
llvm::InitializeAllTargetMCs();
52+
llvm::InitializeAllDisassemblers();
53+
54+
// If we didn't build x86, do not run the test.
55+
std::string Error;
56+
TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
57+
if (!TheTarget)
58+
return;
59+
60+
MRI.reset(TheTarget->createMCRegInfo(TripleName));
61+
MCTargetOptions MCOptions;
62+
MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
63+
STI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
64+
}
65+
66+
/// Create all data structures necessary to operate an assembler
67+
StreamerContext createStreamer(raw_pwrite_stream &OS) {
68+
StreamerContext Res;
69+
Res.Ctx =
70+
std::make_unique<MCContext>(Triple(TripleName), MAI.get(), MRI.get(),
71+
/*MSTI=*/nullptr);
72+
Res.MOFI.reset(TheTarget->createMCObjectFileInfo(*Res.Ctx.get(),
73+
/*PIC=*/false));
74+
Res.Ctx->setObjectFileInfo(Res.MOFI.get());
75+
76+
Res.MII.reset(TheTarget->createMCInstrInfo());
77+
MCCodeEmitter *MCE =
78+
TheTarget->createMCCodeEmitter(*Res.MII, *MRI, *Res.Ctx);
79+
MCAsmBackend *MAB =
80+
TheTarget->createMCAsmBackend(*STI, *MRI, MCTargetOptions());
81+
std::unique_ptr<MCObjectWriter> OW = MAB->createObjectWriter(OS);
82+
Res.Streamer.reset(TheTarget->createMCObjectStreamer(
83+
Triple(TripleName), *Res.Ctx, std::unique_ptr<MCAsmBackend>(MAB),
84+
std::move(OW), std::unique_ptr<MCCodeEmitter>(MCE), *STI,
85+
/* RelaxAll */ false,
86+
/* IncrementalLinkerCompatible */ false,
87+
/* DWARFMustBeAtTheEnd */ false));
88+
return Res;
89+
}
90+
91+
/// Emit a .debug_line section with the given context parameters
92+
void emitDebugLineSection(StreamerContext &C) {
93+
MCContext &Ctx = *C.Ctx;
94+
MCStreamer *TheStreamer = C.Streamer.get();
95+
MCAssembler &Assembler =
96+
static_cast<MCObjectStreamer *>(TheStreamer)->getAssembler();
97+
TheStreamer->initSections(false, *STI);
98+
99+
// Create a mock function
100+
MCSection *Section = C.MOFI->getTextSection();
101+
Section->setHasInstructions(true);
102+
TheStreamer->SwitchSection(Section);
103+
TheStreamer->emitCFIStartProc(true);
104+
105+
// Create a mock dwarfloc
106+
Ctx.setCurrentDwarfLoc(/*FileNo=*/0, /*Line=*/1, /*Column=*/1, /*Flags=*/0,
107+
/*Isa=*/0, /*Discriminator=*/0);
108+
MCDwarfLoc Loc = Ctx.getCurrentDwarfLoc();
109+
MCSymbol *LineSym = Ctx.createTempSymbol();
110+
// Set the value of the symbol to use for the MCDwarfLineEntry.
111+
TheStreamer->emitLabel(LineSym);
112+
TheStreamer->emitNops(4, 1, SMLoc(), *STI);
113+
TheStreamer->emitCFIEndProc();
114+
115+
// Start emission of .debug_line
116+
TheStreamer->SwitchSection(C.MOFI->getDwarfLineSection());
117+
MCDwarfLineTableHeader Header;
118+
MCDwarfLineTableParams Params = Assembler.getDWARFLinetableParams();
119+
Optional<MCDwarfLineStr> LineStr(None);
120+
if (Ctx.getDwarfVersion() >= 5) {
121+
LineStr = MCDwarfLineStr(Ctx);
122+
Header.setRootFile("dir", "file", None, None);
123+
}
124+
MCSymbol *LineEndSym = Header.Emit(TheStreamer, Params, LineStr).second;
125+
126+
// Put out the line tables.
127+
MCLineSection::MCDwarfLineEntryCollection LineEntries;
128+
MCDwarfLineEntry LineEntry(LineSym, Loc);
129+
LineEntries.push_back(LineEntry);
130+
MCDwarfLineTable::emitOne(TheStreamer, Section, LineEntries);
131+
TheStreamer->emitLabel(LineEndSym);
132+
if (LineStr)
133+
LineStr->emitSection(TheStreamer);
134+
}
135+
136+
/// Check contents of .debug_line section
137+
void verifyDebugLineContents(const llvm::object::ObjectFile &E,
138+
ArrayRef<uint8_t> ExpectedEncoding) {
139+
for (const llvm::object::SectionRef &Section : E.sections()) {
140+
Expected<StringRef> SectionNameOrErr = Section.getName();
141+
ASSERT_TRUE(static_cast<bool>(SectionNameOrErr));
142+
StringRef SectionName = *SectionNameOrErr;
143+
if (SectionName.empty() || SectionName != ".debug_line")
144+
continue;
145+
Expected<StringRef> ContentsOrErr = Section.getContents();
146+
ASSERT_TRUE(static_cast<bool>(ContentsOrErr));
147+
StringRef Contents = *ContentsOrErr;
148+
ASSERT_TRUE(Contents.size() > ExpectedEncoding.size());
149+
EXPECT_EQ(
150+
arrayRefFromStringRef(Contents.slice(0, ExpectedEncoding.size())),
151+
ExpectedEncoding);
152+
return;
153+
}
154+
llvm_unreachable(".debug_line not found");
155+
}
156+
157+
/// Open ObjFileData as an object file and read its .debug_line section
158+
void readAndCheckDebugLineContents(StringRef ObjFileData,
159+
ArrayRef<uint8_t> Expected) {
160+
std::unique_ptr<MemoryBuffer> MB =
161+
MemoryBuffer::getMemBuffer(ObjFileData, "", false);
162+
std::unique_ptr<object::Binary> Bin =
163+
cantFail(llvm::object::createBinary(MB->getMemBufferRef()));
164+
if (auto *E = dyn_cast<llvm::object::ELFObjectFileBase>(&*Bin)) {
165+
return verifyDebugLineContents(*E, Expected);
166+
}
167+
llvm_unreachable("ELF object file not found");
168+
}
169+
};
170+
} // namespace
171+
172+
TEST_F(DwarfLineTableHeaders, TestDWARF4HeaderEmission) {
173+
if (!MRI)
174+
return;
175+
176+
SmallString<0> EmittedBinContents;
177+
raw_svector_ostream VecOS(EmittedBinContents);
178+
StreamerContext C = createStreamer(VecOS);
179+
C.Ctx->setDwarfVersion(4);
180+
emitDebugLineSection(C);
181+
C.Streamer->Finish();
182+
readAndCheckDebugLineContents(
183+
EmittedBinContents.str(),
184+
{/* Total length=*/0x30, 0, 0, 0,
185+
/* DWARF version=*/4, 0,
186+
/* Prologue length=*/0x14, 0, 0, 0,
187+
/* min_inst_length=*/1,
188+
/*max_ops_per_inst=*/1,
189+
/* default_is_stmt=*/DWARF2_LINE_DEFAULT_IS_STMT,
190+
/* line_base=*/static_cast<uint8_t>(-5),
191+
/* line_range=*/14,
192+
/* opcode_base=*/13});
193+
}
194+
195+
TEST_F(DwarfLineTableHeaders, TestDWARF5HeaderEmission) {
196+
if (!MRI)
197+
return;
198+
199+
SmallString<0> EmittedBinContents;
200+
raw_svector_ostream VecOS(EmittedBinContents);
201+
StreamerContext C = createStreamer(VecOS);
202+
C.Ctx->setDwarfVersion(5);
203+
emitDebugLineSection(C);
204+
C.Streamer->Finish();
205+
readAndCheckDebugLineContents(
206+
EmittedBinContents.str(),
207+
{/* Total length=*/0x43, 0, 0, 0,
208+
/* DWARF version=*/5, 0,
209+
/* ptr size=*/8,
210+
/* segment=*/0,
211+
/* Prologue length=*/0x25, 0, 0, 0,
212+
/* min_inst_length=*/1,
213+
/*max_ops_per_inst=*/1,
214+
/* default_is_stmt=*/DWARF2_LINE_DEFAULT_IS_STMT,
215+
/* line_base=*/static_cast<uint8_t>(-5),
216+
/* line_range=*/14,
217+
/* opcode_base=*/13});
218+
}

0 commit comments

Comments
 (0)