forked from OSchip/llvm-project
[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
This commit is contained in:
parent
4195ed9959
commit
050edef853
|
@ -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 @@ public:
|
|||
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,
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -14,6 +14,7 @@ set(LLVM_LINK_COMPONENTS
|
|||
add_llvm_unittest(MCTests
|
||||
Disassembler.cpp
|
||||
DwarfLineTables.cpp
|
||||
DwarfLineTableHeaders.cpp
|
||||
MCInstPrinter.cpp
|
||||
StringTableBuilderTest.cpp
|
||||
TargetRegistry.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});
|
||||
}
|
Loading…
Reference in New Issue