brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.1 KiB · f685f28 Raw
247 lines · cpp
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-exception6//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/MCAssembler.h"14#include "llvm/MC/MCCodeEmitter.h"15#include "llvm/MC/MCContext.h"16#include "llvm/MC/MCDwarf.h"17#include "llvm/MC/MCInstrInfo.h"18#include "llvm/MC/MCObjectStreamer.h"19#include "llvm/MC/MCObjectWriter.h"20#include "llvm/MC/MCRegisterInfo.h"21#include "llvm/MC/MCStreamer.h"22#include "llvm/MC/MCSubtargetInfo.h"23#include "llvm/MC/MCTargetOptions.h"24#include "llvm/MC/TargetRegistry.h"25#include "llvm/Object/Binary.h"26#include "llvm/Object/ELFObjectFile.h"27#include "llvm/Support/FileSystem.h"28#include "llvm/Support/MemoryBuffer.h"29#include "llvm/Support/TargetSelect.h"30#include "llvm/Support/ToolOutputFile.h"31#include "gtest/gtest.h"32 33using namespace llvm;34 35namespace {36 37class DwarfLineTableHeaders : public ::testing::Test {38public:39  static constexpr char TripleName[] = "x86_64-pc-linux";40  Triple TT;41  std::unique_ptr<MCRegisterInfo> MRI;42  std::unique_ptr<MCAsmInfo> MAI;43  std::unique_ptr<const MCSubtargetInfo> STI;44  const Target *TheTarget;45 46  struct StreamerContext {47    std::unique_ptr<MCObjectFileInfo> MOFI;48    std::unique_ptr<MCContext> Ctx;49    std::unique_ptr<const MCInstrInfo> MII;50    std::unique_ptr<MCStreamer> Streamer;51  };52 53  DwarfLineTableHeaders() : TT(TripleName) {54    llvm::InitializeAllTargetInfos();55    llvm::InitializeAllTargetMCs();56    llvm::InitializeAllDisassemblers();57 58    // If we didn't build x86, do not run the test.59    std::string Error;60    TheTarget = TargetRegistry::lookupTarget(TT, Error);61    if (!TheTarget)62      return;63 64    MRI.reset(TheTarget->createMCRegInfo(TT));65    MCTargetOptions MCOptions;66    MAI.reset(TheTarget->createMCAsmInfo(*MRI, TT, MCOptions));67    STI.reset(TheTarget->createMCSubtargetInfo(TT, "", ""));68  }69 70  /// Create all data structures necessary to operate an assembler71  StreamerContext createStreamer(raw_pwrite_stream &OS) {72    StreamerContext Res;73    Res.Ctx = std::make_unique<MCContext>(TT, MAI.get(), MRI.get(),74                                          /*MSTI=*/nullptr);75    Res.MOFI.reset(TheTarget->createMCObjectFileInfo(*Res.Ctx,76                                                     /*PIC=*/false));77    Res.Ctx->setObjectFileInfo(Res.MOFI.get());78 79    Res.MII.reset(TheTarget->createMCInstrInfo());80    MCCodeEmitter *MCE = TheTarget->createMCCodeEmitter(*Res.MII, *Res.Ctx);81    MCAsmBackend *MAB =82        TheTarget->createMCAsmBackend(*STI, *MRI, MCTargetOptions());83    std::unique_ptr<MCObjectWriter> OW = MAB->createObjectWriter(OS);84    Res.Streamer.reset(TheTarget->createMCObjectStreamer(85        TT, *Res.Ctx, std::unique_ptr<MCAsmBackend>(MAB), std::move(OW),86        std::unique_ptr<MCCodeEmitter>(MCE), *STI));87    return Res;88  }89 90  /// Emit a .debug_line section with the given context parameters91  void emitDebugLineSection(StreamerContext &C) {92    MCContext &Ctx = *C.Ctx;93    MCStreamer *TheStreamer = C.Streamer.get();94    MCAssembler &Assembler =95        static_cast<MCObjectStreamer *>(TheStreamer)->getAssembler();96    TheStreamer->initSections(false, *STI);97 98    // Create a mock function99    MCSection *Section = C.MOFI->getTextSection();100    Section->setHasInstructions(true);101    TheStreamer->switchSection(Section);102    TheStreamer->emitCFIStartProc(true);103 104    // Create a mock dwarfloc105    Ctx.setCurrentDwarfLoc(/*FileNo=*/0, /*Line=*/1, /*Column=*/1, /*Flags=*/0,106                           /*Isa=*/0, /*Discriminator=*/0);107    MCDwarfLoc Loc = Ctx.getCurrentDwarfLoc();108    MCSymbol *LineSym = Ctx.createTempSymbol();109    // Set the value of the symbol to use for the MCDwarfLineEntry.110    TheStreamer->emitLabel(LineSym);111    TheStreamer->emitNops(4, 1, SMLoc(), *STI);112    TheStreamer->emitCFIEndProc();113 114    // Start emission of .debug_line115    TheStreamer->switchSection(C.MOFI->getDwarfLineSection());116    MCDwarfLineTableHeader Header;117    MCDwarfLineTableParams Params = Assembler.getDWARFLinetableParams();118    std::optional<MCDwarfLineStr> LineStr(std::nullopt);119    if (Ctx.getDwarfVersion() >= 5) {120      LineStr.emplace(Ctx);121      Header.setRootFile("dir", "file", std::nullopt, std::nullopt);122    }123    MCSymbol *LineEndSym = Header.Emit(TheStreamer, Params, LineStr).second;124 125    // Put out the line tables.126    MCLineSection::MCDwarfLineEntryCollection LineEntries;127    MCDwarfLineEntry LineEntry(LineSym, Loc);128    LineEntries.push_back(LineEntry);129    MCDwarfLineTable::emitOne(TheStreamer, Section, LineEntries);130    TheStreamer->emitLabel(LineEndSym);131    if (LineStr) {132      SmallString<0> Data = LineStr->getFinalizedData();133      TheStreamer->switchSection(TheStreamer->getContext()134                                     .getObjectFileInfo()135                                     ->getDwarfLineStrSection());136      TheStreamer->emitBinaryData(Data.str());137    }138  }139 140  /// Check contents of .debug_line section141  void verifyDebugLineContents(const llvm::object::ObjectFile &E,142                               ArrayRef<uint8_t> ExpectedEncoding) {143    for (const llvm::object::SectionRef &Section : E.sections()) {144      Expected<StringRef> SectionNameOrErr = Section.getName();145      ASSERT_TRUE(static_cast<bool>(SectionNameOrErr));146      StringRef SectionName = *SectionNameOrErr;147      if (SectionName.empty() || SectionName != ".debug_line")148        continue;149      Expected<StringRef> ContentsOrErr = Section.getContents();150      ASSERT_TRUE(static_cast<bool>(ContentsOrErr));151      StringRef Contents = *ContentsOrErr;152      ASSERT_TRUE(Contents.size() > ExpectedEncoding.size());153      EXPECT_EQ(154          arrayRefFromStringRef(Contents.slice(0, ExpectedEncoding.size())),155          ExpectedEncoding);156      return;157    }158    llvm_unreachable(".debug_line not found");159  }160 161  /// Check contents of .debug_line_str section162  void verifyDebugLineStrContents(const llvm::object::ObjectFile &E) {163    for (const llvm::object::SectionRef &Section : E.sections()) {164      Expected<StringRef> SectionNameOrErr = Section.getName();165      ASSERT_TRUE(static_cast<bool>(SectionNameOrErr));166      StringRef SectionName = *SectionNameOrErr;167      if (SectionName.empty() || SectionName != ".debug_line_str")168        continue;169      Expected<StringRef> ContentsOrErr = Section.getContents();170      ASSERT_TRUE(static_cast<bool>(ContentsOrErr));171      StringRef Contents = *ContentsOrErr;172      ASSERT_TRUE(Contents.contains("dir"));173      ASSERT_TRUE(Contents.contains("file"));174      ASSERT_TRUE(Contents.size() == 9);175      return;176    }177    llvm_unreachable(".debug_line_str not found");178  }179 180  ///  Open ObjFileData as an object file and read its .debug_line section181  void readAndCheckDebugContents(StringRef ObjFileData,182                                     ArrayRef<uint8_t> Expected, uint8_t DwarfVersion) {183    std::unique_ptr<MemoryBuffer> MB =184        MemoryBuffer::getMemBuffer(ObjFileData, "", false);185    std::unique_ptr<object::Binary> Bin =186        cantFail(llvm::object::createBinary(MB->getMemBufferRef()));187    if (auto *E = dyn_cast<llvm::object::ELFObjectFileBase>(&*Bin)) {188      verifyDebugLineContents(*E, Expected);189      if (DwarfVersion >= 5)190        verifyDebugLineStrContents(*E);191      return;192    }193    llvm_unreachable("ELF object file not found");194  }195};196} // namespace197 198TEST_F(DwarfLineTableHeaders, TestDWARF4HeaderEmission) {199  if (!MRI)200    GTEST_SKIP();201 202  SmallString<0> EmittedBinContents;203  raw_svector_ostream VecOS(EmittedBinContents);204  StreamerContext C = createStreamer(VecOS);205  constexpr uint8_t DwarfVersion = 4;206  C.Ctx->setDwarfVersion(DwarfVersion);207  emitDebugLineSection(C);208  C.Streamer->finish();209  readAndCheckDebugContents(210      EmittedBinContents.str(),211      {/*    Total length=*/0x30, 0, 0, 0,212       /*   DWARF version=*/DwarfVersion, 0,213       /* Prologue length=*/0x14, 0, 0, 0,214       /* min_inst_length=*/1,215       /*max_ops_per_inst=*/1,216       /* default_is_stmt=*/DWARF2_LINE_DEFAULT_IS_STMT,217       /*       line_base=*/static_cast<uint8_t>(-5),218       /*      line_range=*/14,219       /*     opcode_base=*/13}, DwarfVersion);220}221 222TEST_F(DwarfLineTableHeaders, TestDWARF5HeaderEmission) {223  if (!MRI)224    GTEST_SKIP();225 226  SmallString<0> EmittedBinContents;227  raw_svector_ostream VecOS(EmittedBinContents);228  StreamerContext C = createStreamer(VecOS);229  constexpr uint8_t DwarfVersion = 5;230  C.Ctx->setDwarfVersion(DwarfVersion);231  emitDebugLineSection(C);232  C.Streamer->finish();233  readAndCheckDebugContents(234      EmittedBinContents.str(),235      {/*    Total length=*/0x43, 0, 0, 0,236       /*   DWARF version=*/DwarfVersion, 0,237       /*        ptr size=*/8,238       /*         segment=*/0,239       /* Prologue length=*/0x25, 0, 0, 0,240       /* min_inst_length=*/1,241       /*max_ops_per_inst=*/1,242       /* default_is_stmt=*/DWARF2_LINE_DEFAULT_IS_STMT,243       /*       line_base=*/static_cast<uint8_t>(-5),244       /*      line_range=*/14,245       /*     opcode_base=*/13}, DwarfVersion);246}247