brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.7 KiB · f51c200 Raw
245 lines · cpp
1//===- llvm/unittest/DebugInfo/DWARFExpressionRawDataTest.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/ArrayRef.h"10#include "llvm/BinaryFormat/Dwarf.h"11#include "llvm/DebugInfo/DWARF/DWARFContext.h"12#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"13#include "llvm/DebugInfo/DWARF/DWARFDie.h"14#include "llvm/DebugInfo/DWARF/LowLevel/DWARFExpression.h"15#include "llvm/MC/MCAsmBackend.h"16#include "llvm/MC/MCAsmInfo.h"17#include "llvm/MC/MCCodeEmitter.h"18#include "llvm/MC/MCContext.h"19#include "llvm/MC/MCInstrInfo.h"20#include "llvm/MC/MCObjectWriter.h"21#include "llvm/MC/MCRegisterInfo.h"22#include "llvm/MC/MCStreamer.h"23#include "llvm/MC/MCSubtargetInfo.h"24#include "llvm/MC/MCTargetOptions.h"25#include "llvm/MC/TargetRegistry.h"26#include "llvm/Object/Binary.h"27#include "llvm/Object/ELFObjectFile.h"28#include "llvm/Support/DataExtractor.h"29#include "llvm/Support/LEB128.h"30#include "llvm/Support/MemoryBuffer.h"31#include "llvm/Support/TargetSelect.h"32#include "llvm/TargetParser/Triple.h"33#include "llvm/Testing/Support/Error.h"34#include "gtest/gtest.h"35 36using namespace llvm;37using namespace dwarf;38 39namespace {40 41/// Tests that a client of DebugInfo/DWARF is able to read raw data bytes of a42/// DWARFExpression parsed from CFI with the intent of writing them back as is43/// via MC layer / cfi_escape.44/// This is relevant for binary tools that need to rewrite/copy unwind and45/// debug info from input to output binary.46class DWARFExpressionCopyBytesTest : public ::testing::Test {47public:48  static constexpr char TripleName[] = "x86_64-pc-linux";49  Triple TheTriple;50 51  std::unique_ptr<MCRegisterInfo> MRI;52  std::unique_ptr<MCAsmInfo> MAI;53  std::unique_ptr<const MCSubtargetInfo> STI;54  const Target *TheTarget;55 56  DWARFExpressionCopyBytesTest() : TheTriple(TripleName) {57    InitializeAllTargets();58    InitializeAllTargetMCs();59    InitializeAllAsmPrinters();60 61    std::string ErrorStr;62    TheTarget = TargetRegistry::lookupTarget(TheTriple, ErrorStr);63    if (!TheTarget)64      return;65 66    MRI.reset(TheTarget->createMCRegInfo(TheTriple));67    MAI.reset(TheTarget->createMCAsmInfo(*MRI, TheTriple, MCTargetOptions()));68    STI.reset(TheTarget->createMCSubtargetInfo(TheTriple, "", ""));69  }70 71  struct StreamerContext {72    std::unique_ptr<MCObjectFileInfo> MOFI;73    std::unique_ptr<MCContext> Ctx;74    std::unique_ptr<const MCInstrInfo> MII;75    std::unique_ptr<MCStreamer> Streamer;76  };77 78  /// Create all data structures necessary to operate an assembler79  StreamerContext createStreamer(raw_pwrite_stream &OS);80  /// Emit a dummy obj file with a single CFI instruction,81  /// DW_CFA_def_cfa_expression, encoding as its operand the DWARF expression82  /// represented by ExprBytes83  SmallString<0> emitObjFile(StringRef ExprBytes);84  /// Peruse the object file looking for the encoded DWARF expression, and check85  /// that its operand was encoded correctly86  void parseCFIsAndCheckExpression(const llvm::object::ObjectFile &E,87                                   ArrayRef<uint8_t> Expected);88  /// Open the in-memory relocatable object file and verify that it contains89  /// the expected DWARF expression bytes90  void readAndCheckObjFile(StringRef ObjFileData, ArrayRef<uint8_t> Expected);91  /// Run this test on the DWARF expression represented by the bytes in92  /// ExprData. Check that the getData() API retrieves these original bytes and93  /// that we can use them to encode a CFI with those bytes as operands (via94  /// cfi_escape).95  void testExpr(ArrayRef<uint8_t> ExprData);96};97 98} // namespace99 100DWARFExpressionCopyBytesTest::StreamerContext101DWARFExpressionCopyBytesTest::createStreamer(raw_pwrite_stream &OS) {102  StreamerContext Res;103  Res.Ctx =104      std::make_unique<MCContext>(Triple(TripleName), MAI.get(), MRI.get(),105                                  /*MSTI=*/nullptr);106  Res.MOFI.reset(TheTarget->createMCObjectFileInfo(*Res.Ctx,107                                                   /*PIC=*/false));108  Res.Ctx->setObjectFileInfo(Res.MOFI.get());109 110  Res.MII.reset(TheTarget->createMCInstrInfo());111  MCCodeEmitter *MCE = TheTarget->createMCCodeEmitter(*Res.MII, *Res.Ctx);112  MCAsmBackend *MAB =113      TheTarget->createMCAsmBackend(*STI, *MRI, MCTargetOptions());114  std::unique_ptr<MCObjectWriter> OW = MAB->createObjectWriter(OS);115  Res.Streamer.reset(TheTarget->createMCObjectStreamer(116      Triple(TripleName), *Res.Ctx, std::unique_ptr<MCAsmBackend>(MAB),117      std::move(OW), std::unique_ptr<MCCodeEmitter>(MCE), *STI));118  return Res;119}120 121SmallString<0> DWARFExpressionCopyBytesTest::emitObjFile(StringRef ExprBytes) {122  auto EncodeDefCfaExpr = [&](StringRef Bytes) {123    std::string Str;124    raw_string_ostream OS(Str);125    OS << static_cast<uint8_t>(dwarf::DW_CFA_def_cfa_expression);126    encodeULEB128(Bytes.size(), OS);127    OS << Bytes;128    return Str;129  };130 131  SmallString<0> Storage;132  raw_svector_ostream VecOS(Storage);133  StreamerContext C = createStreamer(VecOS);134  C.Streamer->initSections(false, *STI);135  MCSection *Section = C.MOFI->getTextSection();136  Section->setHasInstructions(true);137  C.Streamer->switchSection(Section);138  C.Streamer->emitCFIStartProc(true);139  auto Str = EncodeDefCfaExpr(ExprBytes);140  C.Streamer->emitCFIEscape(Str);141  C.Streamer->emitNops(4, 1, SMLoc(), *STI);142  C.Streamer->emitCFIEndProc();143  C.Streamer->finish();144  return Storage;145}146 147void DWARFExpressionCopyBytesTest::parseCFIsAndCheckExpression(148    const llvm::object::ObjectFile &E, ArrayRef<uint8_t> Expected) {149  auto FetchFirstCfaExpression = [](const DWARFDebugFrame &EHFrame)150      -> std::optional<CFIProgram::Instruction> {151    for (const dwarf::FrameEntry &Entry : EHFrame.entries()) {152      const auto *CurFDE = dyn_cast<dwarf::FDE>(&Entry);153      if (!CurFDE)154        continue;155      for (const CFIProgram::Instruction &Instr : CurFDE->cfis()) {156        if (Instr.Opcode != dwarf::DW_CFA_def_cfa_expression)157          continue;158        return Instr;159      }160    }161    return std::nullopt;162  };163 164  std::unique_ptr<DWARFContext> Ctx = DWARFContext::create(E);165  const DWARFDebugFrame *EHFrame = cantFail(Ctx->getEHFrame());166  ASSERT_NE(nullptr, EHFrame);167  auto CfiInstr = FetchFirstCfaExpression(*EHFrame);168  ASSERT_TRUE(CfiInstr);169  DWARFExpression Expr = *(CfiInstr->Expression);170  StringRef ExprData = Expr.getData();171  EXPECT_EQ(ExprData.size(), Expected.size());172  for (unsigned I = 0, E = ExprData.size(); I != E; ++I) {173    EXPECT_EQ(static_cast<uint8_t>(ExprData[I]), Expected[I]);174  }175}176 177void DWARFExpressionCopyBytesTest::readAndCheckObjFile(178    StringRef ObjFileData, ArrayRef<uint8_t> Expected) {179  std::unique_ptr<MemoryBuffer> MB =180      MemoryBuffer::getMemBuffer(ObjFileData, "", false);181  std::unique_ptr<object::Binary> Bin =182      cantFail(llvm::object::createBinary(MB->getMemBufferRef()));183  if (auto *E = dyn_cast<llvm::object::ELFObjectFileBase>(&*Bin)) {184    parseCFIsAndCheckExpression(*E, Expected);185  }186}187 188void DWARFExpressionCopyBytesTest::testExpr(ArrayRef<uint8_t> ExprData) {189  // If we didn't build x86, do not run the test.190  if (!MRI)191    GTEST_SKIP();192 193  DataExtractor DE(ExprData, true, 8);194  DWARFExpression Expr(DE, 8);195 196  // Copy this expression into the CFI of a binary and check that we are able to197  // get it back correctly from this binary.198  const SmallString<0> EmittedBinContents = emitObjFile(Expr.getData());199  readAndCheckObjFile(EmittedBinContents.str(), ExprData);200}201 202TEST_F(DWARFExpressionCopyBytesTest, Test_OP_reg0) { testExpr({DW_OP_reg0}); }203 204TEST_F(DWARFExpressionCopyBytesTest, Test_OP_reg10) { testExpr({DW_OP_reg10}); }205 206TEST_F(DWARFExpressionCopyBytesTest, Test_OP_regx) {207  testExpr({DW_OP_regx, 0x80, 0x02});208}209 210TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg0) {211  testExpr({DW_OP_breg0, 0x04});212}213 214TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg0_large_offset) {215  testExpr({DW_OP_breg0, 0x80, 0x02});216}217 218TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg13) {219  testExpr({DW_OP_breg13, 0x10});220}221 222TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg13_zero_offset) {223  testExpr({DW_OP_breg13, 0x00});224}225 226TEST_F(DWARFExpressionCopyBytesTest, Test_OP_breg0_negative) {227  testExpr({DW_OP_breg0, 0x70});228}229 230TEST_F(DWARFExpressionCopyBytesTest, Test_OP_bregx) {231  testExpr({DW_OP_bregx, 0x0d, 0x28});232}233 234TEST_F(DWARFExpressionCopyBytesTest, Test_OP_stack_value) {235  testExpr({DW_OP_breg13, 0x04, DW_OP_stack_value});236}237 238TEST_F(DWARFExpressionCopyBytesTest, Test_OP_entry_value) {239  testExpr({DW_OP_entry_value, 0x01, DW_OP_reg0, DW_OP_stack_value});240}241 242TEST_F(DWARFExpressionCopyBytesTest, Test_OP_entry_value_mem) {243  testExpr({DW_OP_entry_value, 0x02, DW_OP_breg13, 0x10, DW_OP_stack_value});244}245