brintos

brintos / llvm-project-archived public Read only

0
0
Text · 42.1 KiB · 0126c40 Raw
1220 lines · cpp
1//===-- DWARFExpressionTest.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#include "lldb/Expression/DWARFExpression.h"9#include "ValueMatcher.h"10#include <unordered_map>11#ifdef ARCH_AARCH6412#include "Plugins/ABI/AArch64/ABISysV_arm64.h"13#endif14#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"15#include "Plugins/Platform/Linux/PlatformLinux.h"16#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"17#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"18#include "Plugins/SymbolFile/DWARF/SymbolFileWasm.h"19#include "Plugins/SymbolVendor/wasm/SymbolVendorWasm.h"20#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"21#include "TestingSupport/Symbol/YAMLModuleTester.h"22#include "lldb/Core/Debugger.h"23#include "lldb/Core/PluginManager.h"24#include "lldb/Core/Value.h"25#include "lldb/Core/dwarf.h"26#include "lldb/Host/HostInfo.h"27#include "lldb/Symbol/ObjectFile.h"28#include "lldb/Target/ABI.h"29#include "lldb/Target/RegisterContext.h"30#include "lldb/Utility/RegisterValue.h"31#include "lldb/Utility/StreamString.h"32#include "llvm/ADT/StringExtras.h"33#include "llvm/Support/TargetSelect.h"34#include "llvm/Testing/Support/Error.h"35#include "gtest/gtest.h"36 37using namespace lldb_private::plugin::dwarf;38using namespace lldb_private::wasm;39using namespace lldb_private;40using namespace llvm::dwarf;41 42namespace {43/// A mock implementation of DWARFExpression::Delegate for testing.44/// This class provides default implementations of all delegate methods,45/// with the DWARF version being configurable via the constructor.46class MockDwarfDelegate : public DWARFExpression::Delegate {47public:48  static constexpr uint16_t DEFAULT_DWARF_VERSION = 5;49  static MockDwarfDelegate Dwarf5() { return MockDwarfDelegate(5); }50  static MockDwarfDelegate Dwarf2() { return MockDwarfDelegate(2); }51 52  MockDwarfDelegate() : MockDwarfDelegate(DEFAULT_DWARF_VERSION) {}53  explicit MockDwarfDelegate(uint16_t version) : m_dwarf_version(version) {}54 55  uint16_t GetVersion() const override { return m_dwarf_version; }56 57  dw_addr_t GetBaseAddress() const override { return 0; }58 59  uint8_t GetAddressByteSize() const override { return 4; }60 61  llvm::Expected<std::pair<uint64_t, bool>>62  GetDIEBitSizeAndSign(uint64_t relative_die_offset) const override {63    return llvm::createStringError(llvm::inconvertibleErrorCode(),64                                   "GetDIEBitSizeAndSign not implemented");65  }66 67  dw_addr_t ReadAddressFromDebugAddrSection(uint32_t index) const override {68    return 0;69  }70 71  lldb::offset_t GetVendorDWARFOpcodeSize(const DataExtractor &data,72                                          const lldb::offset_t data_offset,73                                          const uint8_t op) const override {74    return LLDB_INVALID_OFFSET;75  }76 77  bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,78                              lldb::offset_t &offset, RegisterContext *reg_ctx,79                              lldb::RegisterKind reg_kind,80                              DWARFExpression::Stack &stack) const override {81    return false;82  }83 84private:85  uint16_t m_dwarf_version;86};87 88/// Mock memory implementation for testing.89/// Stores predefined memory contents indexed by {address, size} pairs.90class MockMemory {91public:92  /// Represents a memory read request with an address and size.93  /// Used as a key in the memory map to look up predefined test data.94  struct Request {95    lldb::addr_t addr;96    size_t size;97 98    bool operator==(const Request &other) const {99      return addr == other.addr && size == other.size;100    }101 102    /// Hash function for Request to enable its use in unordered_map.103    struct Hash {104      size_t operator()(const Request &req) const {105        size_t h1 = std::hash<lldb::addr_t>{}(req.addr);106        size_t h2 = std::hash<size_t>{}(req.size);107        return h1 ^ (h2 << 1);108      }109    };110  };111 112  typedef std::unordered_map<Request, std::vector<uint8_t>, Request::Hash> Map;113  MockMemory() = default;114  MockMemory(Map memory) : m_memory(std::move(memory)) {115    // Make sure the requested memory size matches the returned value.116    for ([[maybe_unused]] auto &[req, bytes] : m_memory) {117      assert(bytes.size() == req.size);118    }119  }120 121  llvm::Expected<std::vector<uint8_t>> ReadMemory(lldb::addr_t addr,122                                                  size_t size) {123    if (!m_memory.count({addr, size})) {124      return llvm::createStringError(125          llvm::inconvertibleErrorCode(),126          "MockMemory::ReadMemory {address=0x%" PRIx64 ", size=%zu} not found",127          addr, size);128    }129    return m_memory[{addr, size}];130  }131 132private:133  std::unordered_map<Request, std::vector<uint8_t>, Request::Hash> m_memory;134};135 136/// A Process whose `ReadMemory` override queries MockMemory.137struct MockProcess : Process {138  using addr_t = lldb::addr_t;139 140  MockMemory m_memory;141 142  MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,143              MockMemory memory)144      : Process(target_sp, listener_sp), m_memory(std::move(memory)) {}145  size_t DoReadMemory(addr_t vm_addr, void *buf, size_t size,146                      Status &error) override {147    auto expected_memory = m_memory.ReadMemory(vm_addr, size);148    if (!expected_memory) {149      error = Status::FromError(expected_memory.takeError());150      return 0;151    }152    assert(expected_memory->size() == size);153    std::memcpy(buf, expected_memory->data(), expected_memory->size());154    return size;155  }156  size_t ReadMemory(addr_t addr, void *buf, size_t size,157                    Status &status) override {158    return DoReadMemory(addr, buf, size, status);159  }160  bool CanDebug(lldb::TargetSP, bool) override { return true; }161  Status DoDestroy() override { return Status(); }162  llvm::StringRef GetPluginName() override { return ""; }163  void RefreshStateAfterStop() override {}164  bool DoUpdateThreadList(ThreadList &, ThreadList &) override { return false; }165};166 167class MockThread : public Thread {168public:169  MockThread(Process &process) : Thread(process, /*tid=*/1), m_reg_ctx_sp() {}170  ~MockThread() override { DestroyThread(); }171 172  void RefreshStateAfterStop() override {}173 174  lldb::RegisterContextSP GetRegisterContext() override { return m_reg_ctx_sp; }175 176  lldb::RegisterContextSP177  CreateRegisterContextForFrame(StackFrame *frame) override {178    return m_reg_ctx_sp;179  }180 181  bool CalculateStopInfo() override { return false; }182 183  void SetRegisterContext(lldb::RegisterContextSP reg_ctx_sp) {184    m_reg_ctx_sp = reg_ctx_sp;185  }186 187private:188  lldb::RegisterContextSP m_reg_ctx_sp;189};190 191class MockRegisterContext : public RegisterContext {192public:193  MockRegisterContext(Thread &thread, const RegisterValue &reg_value)194      : RegisterContext(thread, 0 /*concrete_frame_idx*/),195        m_reg_value(reg_value) {}196 197  void InvalidateAllRegisters() override {}198 199  size_t GetRegisterCount() override { return 0; }200 201  const RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override {202    return &m_reg_info;203  }204 205  size_t GetRegisterSetCount() override { return 0; }206 207  const RegisterSet *GetRegisterSet(size_t reg_set) override { return nullptr; }208 209  lldb::ByteOrder GetByteOrder() override {210    return lldb::ByteOrder::eByteOrderLittle;211  }212 213  bool ReadRegister(const RegisterInfo *reg_info,214                    RegisterValue &reg_value) override {215    reg_value = m_reg_value;216    return true;217  }218 219  bool WriteRegister(const RegisterInfo *reg_info,220                     const RegisterValue &reg_value) override {221    return false;222  }223 224  uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,225                                               uint32_t num) override {226    return num;227  }228 229private:230  RegisterInfo m_reg_info{};231  RegisterValue m_reg_value{};232};233} // namespace234 235static llvm::Expected<Value> Evaluate(llvm::ArrayRef<uint8_t> expr,236                                      lldb::ModuleSP module_sp = {},237                                      DWARFExpression::Delegate *unit = nullptr,238                                      ExecutionContext *exe_ctx = nullptr,239                                      RegisterContext *reg_ctx = nullptr) {240  DataExtractor extractor(241      expr.data(), expr.size(), lldb::eByteOrderLittle,242      /*addr_size*/ exe_ctx ? exe_ctx->GetAddressByteSize() : 4);243 244  return DWARFExpression::Evaluate(exe_ctx, reg_ctx, module_sp, extractor, unit,245                                   lldb::eRegisterKindLLDB,246                                   /*initial_value_ptr=*/nullptr,247                                   /*object_address_ptr=*/nullptr);248}249 250class DWARFExpressionTester : public YAMLModuleTester {251public:252  DWARFExpressionTester(llvm::StringRef yaml_data, size_t cu_index)253      : YAMLModuleTester(yaml_data, cu_index) {}254 255  using YAMLModuleTester::YAMLModuleTester;256  llvm::Expected<Value> Eval(llvm::ArrayRef<uint8_t> expr) {257    return ::Evaluate(expr, m_module_sp, m_dwarf_unit);258  }259};260 261/// This is needed for the tests that use a mock process.262class DWARFExpressionMockProcessTest : public ::testing::Test {263public:264  void SetUp() override {265    FileSystem::Initialize();266    HostInfo::Initialize();267    platform_linux::PlatformLinux::Initialize();268  }269  void TearDown() override {270    platform_linux::PlatformLinux::Terminate();271    HostInfo::Terminate();272    FileSystem::Terminate();273  }274};275 276/// Mock target implementation for testing.277/// Provides predefined memory contents via MockMemory instead of reading from278/// a real process.279class MockTarget : public Target {280public:281  MockTarget(Debugger &debugger, const ArchSpec &target_arch,282             const lldb::PlatformSP &platform_sp, MockMemory memory)283      : Target(debugger, target_arch, platform_sp, true),284        m_memory(std::move(memory)) {}285 286  size_t ReadMemory(const Address &addr, void *dst, size_t dst_len,287                    Status &error, bool force_live_memory = false,288                    lldb::addr_t *load_addr_ptr = nullptr,289                    bool *did_read_live_memory = nullptr) override {290    auto expected_memory = m_memory.ReadMemory(addr.GetOffset(), dst_len);291    if (!expected_memory) {292      error = Status::FromError(expected_memory.takeError());293      return 0;294    }295    const size_t bytes_read = expected_memory->size();296    assert(bytes_read <= dst_len);297    std::memcpy(dst, expected_memory->data(), bytes_read);298    return bytes_read;299  }300 301private:302  MockMemory m_memory;303};304 305struct TestContext {306  lldb::PlatformSP platform_sp;307  lldb::TargetSP target_sp;308  lldb::DebuggerSP debugger_sp;309  lldb::ProcessSP process_sp;310  lldb::ThreadSP thread_sp;311  lldb::RegisterContextSP reg_ctx_sp;312};313 314/// A helper function to create TestContext objects with the315/// given triple, memory, and register contents.316static bool CreateTestContext(TestContext *ctx, llvm::StringRef triple,317                              std::optional<RegisterValue> reg_value = {},318                              std::optional<MockMemory> process_memory = {},319                              std::optional<MockMemory> target_memory = {}) {320  ArchSpec arch(triple);321  lldb::PlatformSP platform_sp =322      platform_linux::PlatformLinux::CreateInstance(true, &arch);323  Platform::SetHostPlatform(platform_sp);324  lldb::TargetSP target_sp;325  lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();326 327  Status status;328  if (target_memory)329    target_sp = std::make_shared<MockTarget>(*debugger_sp, arch, platform_sp,330                                             std::move(*target_memory));331  else332    status = debugger_sp->GetTargetList().CreateTarget(333        *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);334 335  EXPECT_TRUE(status.Success());336  if (!status.Success())337    return false;338 339  lldb::ProcessSP process_sp;340  if (!process_memory)341    process_memory = MockMemory();342  process_sp = std::make_shared<MockProcess>(343      target_sp, Listener::MakeListener("dummy"), std::move(*process_memory));344 345  auto thread_sp = std::make_shared<MockThread>(*process_sp);346 347  process_sp->GetThreadList().AddThread(thread_sp);348 349  lldb::RegisterContextSP reg_ctx_sp;350  if (reg_value) {351    reg_ctx_sp = std::make_shared<MockRegisterContext>(*thread_sp, *reg_value);352    thread_sp->SetRegisterContext(reg_ctx_sp);353  }354 355  *ctx = TestContext{platform_sp, target_sp, debugger_sp,356                     process_sp,  thread_sp, reg_ctx_sp};357  return true;358}359 360TEST(DWARFExpression, DW_OP_pick) {361  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 0}),362                       ExpectScalar(0));363  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 1}),364                       ExpectScalar(1));365  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 2}),366                       llvm::Failed());367}368 369TEST(DWARFExpression, DW_OP_const) {370  // Extend to address size.371  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1u, 0x88}), ExpectScalar(0x88));372  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1s, 0x88}),373                       ExpectScalar(0xffffff88));374  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x47, 0x88}),375                       ExpectScalar(0x8847));376  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2s, 0x47, 0x88}),377                       ExpectScalar(0xffff8847));378  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4u, 0x44, 0x42, 0x47, 0x88}),379                       ExpectScalar(0x88474244));380  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4s, 0x44, 0x42, 0x47, 0x88}),381                       ExpectScalar(0x88474244));382 383  // Truncate to address size.384  EXPECT_THAT_EXPECTED(385      Evaluate({DW_OP_const8u, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}),386      ExpectScalar(0x33221100));387  EXPECT_THAT_EXPECTED(388      Evaluate({DW_OP_const8s, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}),389      ExpectScalar(0x33221100));390 391  // Don't truncate to address size for compatibility with clang (pr48087).392  EXPECT_THAT_EXPECTED(393      Evaluate({DW_OP_constu, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}),394      ExpectScalar(0x01010101010101));395  EXPECT_THAT_EXPECTED(396      Evaluate({DW_OP_consts, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}),397      ExpectScalar(0xffff010101010101));398}399 400TEST(DWARFExpression, DW_OP_skip) {401  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1u, 0x42, DW_OP_skip, 0x02, 0x00,402                                 DW_OP_const1u, 0xff}),403                       ExpectScalar(0x42));404}405 406TEST(DWARFExpression, DW_OP_bra) {407  EXPECT_THAT_EXPECTED(408      // clang-format off409      Evaluate({410        DW_OP_const1u, 0x42,     // push 0x42411        DW_OP_const1u, 0x1,      // push 0x1412        DW_OP_bra, 0x02, 0x00,   // if 0x1 > 0, then skip 0x0002 opcodes413        DW_OP_const1u, 0xff,     // push 0xff414      }),415      // clang-format on416      ExpectScalar(0x42));417 418  EXPECT_THAT_ERROR(Evaluate({DW_OP_bra, 0x01, 0x00}).takeError(),419                    llvm::Failed());420}421 422TEST(DWARFExpression, DW_OP_convert) {423  /// Auxiliary debug info.424  const char *yamldata = R"(425--- !ELF426FileHeader:427  Class:   ELFCLASS64428  Data:    ELFDATA2LSB429  Type:    ET_EXEC430  Machine: EM_386431DWARF:432  debug_abbrev:433    - Table:434        - Code:            0x00000001435          Tag:             DW_TAG_compile_unit436          Children:        DW_CHILDREN_yes437          Attributes:438            - Attribute:       DW_AT_language439              Form:            DW_FORM_data2440        - Code:            0x00000002441          Tag:             DW_TAG_base_type442          Children:        DW_CHILDREN_no443          Attributes:444            - Attribute:       DW_AT_encoding445              Form:            DW_FORM_data1446            - Attribute:       DW_AT_byte_size447              Form:            DW_FORM_data1448  debug_info:449    - Version:         4450      AddrSize:        8451      AbbrevTableID:   0452      AbbrOffset:      0x0453      Entries:454        - AbbrCode:        0x00000001455          Values:456            - Value:           0x000000000000000C457        - AbbrCode:        0x00000000458    - Version:         4459      AddrSize:        8460      AbbrevTableID:   0461      AbbrOffset:      0x0462      Entries:463        - AbbrCode:        0x00000001464          Values:465            - Value:           0x000000000000000C466        # 0x0000000e:467        - AbbrCode:        0x00000002468          Values:469            - Value:           0x0000000000000007 # DW_ATE_unsigned470            - Value:           0x0000000000000004471        # 0x00000011:472        - AbbrCode:        0x00000002473          Values:474            - Value:           0x0000000000000007 # DW_ATE_unsigned475            - Value:           0x0000000000000008476        # 0x00000014:477        - AbbrCode:        0x00000002478          Values:479            - Value:           0x0000000000000005 # DW_ATE_signed480            - Value:           0x0000000000000008481        # 0x00000017:482        - AbbrCode:        0x00000002483          Values:484            - Value:           0x0000000000000008 # DW_ATE_unsigned_char485            - Value:           0x0000000000000001486        # 0x0000001a:487        - AbbrCode:        0x00000002488          Values:489            - Value:           0x0000000000000006 # DW_ATE_signed_char490            - Value:           0x0000000000000001491        # 0x0000001d:492        - AbbrCode:        0x00000002493          Values:494            - Value:           0x000000000000000b # DW_ATE_numeric_string495            - Value:           0x0000000000000001496        - AbbrCode:        0x00000000497 498)";499  // Compile unit relative offsets to each DW_TAG_base_type500  uint8_t offs_uint32_t = 0x0000000e;501  uint8_t offs_uint64_t = 0x00000011;502  uint8_t offs_sint64_t = 0x00000014;503  uint8_t offs_uchar = 0x00000017;504  uint8_t offs_schar = 0x0000001a;505 506  DWARFExpressionTester t(yamldata, /*cu_index=*/1);507  ASSERT_TRUE((bool)t.GetDwarfUnit());508 509  // Constant is given as little-endian.510  bool is_signed = true;511  bool not_signed = false;512 513  //514  // Positive tests.515  //516 517  // Leave as is.518  EXPECT_THAT_EXPECTED(519      t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //520              DW_OP_convert, offs_uint32_t, DW_OP_stack_value}),521      ExpectScalar(64, 0x44332211, not_signed));522 523  // Zero-extend to 64 bits.524  EXPECT_THAT_EXPECTED(525      t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //526              DW_OP_convert, offs_uint64_t, DW_OP_stack_value}),527      ExpectScalar(64, 0x44332211, not_signed));528 529  // Sign-extend to 64 bits.530  EXPECT_THAT_EXPECTED(531      t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //532              DW_OP_convert, offs_sint64_t, DW_OP_stack_value}),533      ExpectScalar(64, 0xffffffffffeeddcc, is_signed));534 535  // Sign-extend, then truncate.536  EXPECT_THAT_EXPECTED(537      t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //538              DW_OP_convert, offs_sint64_t,          //539              DW_OP_convert, offs_uint32_t, DW_OP_stack_value}),540      ExpectScalar(32, 0xffeeddcc, not_signed));541 542  // Truncate to default unspecified (pointer-sized) type.543  EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //544                               DW_OP_convert, offs_sint64_t,          //545                               DW_OP_convert, 0x00, DW_OP_stack_value}),546                       ExpectScalar(32, 0xffeeddcc, not_signed));547 548  // Truncate to 8 bits.549  EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert,550                               offs_uchar, DW_OP_stack_value}),551                       ExpectScalar(8, 'A', not_signed));552 553  // Also truncate to 8 bits.554  EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert,555                               offs_schar, DW_OP_stack_value}),556                       ExpectScalar(8, 'A', is_signed));557 558  //559  // Errors.560  //561 562  // No Module.563  EXPECT_THAT_ERROR(Evaluate({DW_OP_const1s, 'X', DW_OP_convert, 0x00}, nullptr,564                             t.GetDwarfUnit())565                        .takeError(),566                    llvm::Failed());567 568  // No DIE.569  EXPECT_THAT_ERROR(570      t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x01}).takeError(),571      llvm::Failed());572 573  // Unsupported.574  EXPECT_THAT_ERROR(575      t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x1d}).takeError(),576      llvm::Failed());577}578 579TEST(DWARFExpression, DW_OP_stack_value) {580  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed());581}582 583// This test shows that the dwarf version is used by the expression evaluation.584// Note that the different behavior tested here is not meant to imply that this585// is the correct interpretation of dwarf2 vs. dwarf5, but rather it was picked586// as an easy example that evaluates differently based on the dwarf version.587TEST(DWARFExpression, dwarf_version) {588  MockDwarfDelegate dwarf2 = MockDwarfDelegate::Dwarf2();589  MockDwarfDelegate dwarf5 = MockDwarfDelegate::Dwarf5();590 591  // In dwarf2 the constant on top of the stack is treated as a value.592  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1}, {}, &dwarf2), ExpectScalar(1));593 594  // In dwarf5 the constant on top of the stack is implicitly converted to an595  // address.596  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1}, {}, &dwarf5),597                       ExpectLoadAddress(1));598}599 600TEST(DWARFExpression, DW_OP_piece) {601  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x11, 0x22, DW_OP_piece, 2,602                                 DW_OP_const2u, 0x33, 0x44, DW_OP_piece, 2}),603                       ExpectHostAddress({0x11, 0x22, 0x33, 0x44}));604  EXPECT_THAT_EXPECTED(605      Evaluate({DW_OP_piece, 1, DW_OP_const1u, 0xff, DW_OP_piece, 1}),606      // Note that the "00" should really be "undef", but we can't607      // represent that yet.608      ExpectHostAddress({0x00, 0xff}));609 610  // This tests if ap_int is extended to the right width.611  // expect 40*8 = 320 bits size.612  std::vector<uint8_t> expected_host_buffer(40, 0);613  expected_host_buffer[0] = 2;614 615  EXPECT_THAT_EXPECTED(616      Evaluate({{DW_OP_lit2, DW_OP_stack_value, DW_OP_piece, 40}}),617      ExpectHostAddress(expected_host_buffer));618}619 620TEST(DWARFExpression, DW_OP_implicit_value) {621  unsigned char bytes = 4;622 623  EXPECT_THAT_EXPECTED(624      Evaluate({DW_OP_implicit_value, bytes, 0x11, 0x22, 0x33, 0x44}),625      ExpectHostAddress({0x11, 0x22, 0x33, 0x44}));626}627 628TEST(DWARFExpression, DW_OP_unknown) {629  EXPECT_THAT_EXPECTED(630      Evaluate({0xff}),631      llvm::FailedWithMessage(632          "Unhandled opcode DW_OP_unknown_ff in DWARFExpression"));633}634 635TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) {636  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_deref}), llvm::Failed());637 638  // Set up a mock process.639  MockMemory::Map memory = {640      {{0x4, 4}, {0x4, 0x5, 0x6, 0x7}},641  };642  TestContext test_ctx;643  ASSERT_TRUE(644      CreateTestContext(&test_ctx, "i386-pc-linux", {}, std::move(memory)));645 646  ExecutionContext exe_ctx(test_ctx.process_sp);647  // Implicit location: *0x4.648  EXPECT_THAT_EXPECTED(649      Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value}, {}, {}, &exe_ctx),650      ExpectScalar(32, 0x07060504, false));651  // Memory location: *(*0x4).652  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref}, {}, {}, &exe_ctx),653                       ExpectLoadAddress(0x07060504));654  // Memory location: *0x4.655  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4}, {}, {}, &exe_ctx),656                       ExpectScalar(Scalar(4)));657}658 659TEST_F(DWARFExpressionMockProcessTest, WASM_DW_OP_addr) {660  // Set up a wasm target661  TestContext test_ctx;662  ASSERT_TRUE(CreateTestContext(&test_ctx, "wasm32-unknown-unknown-wasm"));663 664  ExecutionContext exe_ctx(test_ctx.target_sp, false);665  // DW_OP_addr takes a single operand of address size width:666  EXPECT_THAT_EXPECTED(667      Evaluate({DW_OP_addr, 0x40, 0x0, 0x0, 0x0}, {}, {}, &exe_ctx),668      ExpectLoadAddress(0x40));669}670 671TEST_F(DWARFExpressionMockProcessTest, WASM_DW_OP_addr_index) {672  const char *yamldata = R"(673--- !ELF674FileHeader:675  Class:   ELFCLASS64676  Data:    ELFDATA2LSB677  Type:    ET_EXEC678  Machine: EM_386679DWARF:680  debug_abbrev:681    - Table:682        - Code:            0x00000001683          Tag:             DW_TAG_compile_unit684          Children:        DW_CHILDREN_no685          Attributes:686            - Attribute:       DW_AT_addr_base687              Form:            DW_FORM_sec_offset688 689  debug_info:690    - Version:         5691      AddrSize:        4692      UnitType:        DW_UT_compile693      Entries:694        - AbbrCode:        0x00000001695          Values:696            - Value:           0x8 # Offset of the first Address past the header697        - AbbrCode:        0x0698 699  debug_addr:700    - Version: 5701      AddressSize: 4702      Entries:703        - Address: 0x1234704        - Address: 0x5678705)";706 707  // Can't use DWARFExpressionTester from above because subsystems overlap with708  // the fixture.709  SubsystemRAII<ObjectFileELF, SymbolFileDWARF> subsystems;710  llvm::Expected<TestFile> file = TestFile::fromYaml(yamldata);711  EXPECT_THAT_EXPECTED(file, llvm::Succeeded());712  auto module_sp = std::make_shared<Module>(file->moduleSpec());713  auto *dwarf_cu = llvm::cast<SymbolFileDWARF>(module_sp->GetSymbolFile())714                       ->DebugInfo()715                       .GetUnitAtIndex(0);716  ASSERT_TRUE(dwarf_cu);717  dwarf_cu->ExtractDIEsIfNeeded();718 719  // Set up a wasm target720  TestContext test_ctx;721  ASSERT_TRUE(CreateTestContext(&test_ctx, "wasm32-unknown-unknown-wasm"));722  ExecutionContext exe_ctx(test_ctx.target_sp, false);723 724  auto evaluate = [&](DWARFExpression &expr) -> llvm::Expected<Value> {725    DataExtractor extractor;726    expr.GetExpressionData(extractor);727    return DWARFExpression::Evaluate(&exe_ctx, /*reg_ctx*/ nullptr,728                                     /*module_sp*/ {}, extractor, dwarf_cu,729                                     lldb::eRegisterKindLLDB,730                                     /*initial_value_ptr*/ nullptr,731                                     /*object_address_ptr*/ nullptr);732  };733 734  // DW_OP_addrx takes a single leb128 operand, the index in the addr table:735  uint8_t expr_data[] = {DW_OP_addrx, 0x01};736  DataExtractor extractor(expr_data, sizeof(expr_data), lldb::eByteOrderLittle,737                          /*addr_size*/ 4);738  DWARFExpression expr(extractor);739 740  llvm::Expected<Value> result = evaluate(expr);741  EXPECT_THAT_EXPECTED(result, ExpectLoadAddress(0x5678u));742 743  ASSERT_TRUE(expr.Update_DW_OP_addr(dwarf_cu, 0xdeadbeef));744  result = evaluate(expr);745  EXPECT_THAT_EXPECTED(result, ExpectLoadAddress(0xdeadbeefu));746}747 748class CustomSymbolFileDWARF : public SymbolFileDWARF {749  static char ID;750 751public:752  using SymbolFileDWARF::SymbolFileDWARF;753 754  bool isA(const void *ClassID) const override {755    return ClassID == &ID || SymbolFile::isA(ClassID);756  }757  static bool classof(const SymbolFile *obj) { return obj->isA(&ID); }758 759  static llvm::StringRef GetPluginNameStatic() { return "custom_dwarf"; }760 761  static llvm::StringRef GetPluginDescriptionStatic() {762    return "Symbol file reader with expression extensions.";763  }764 765  static void Initialize() {766    PluginManager::RegisterPlugin(GetPluginNameStatic(),767                                  GetPluginDescriptionStatic(), CreateInstance,768                                  SymbolFileDWARF::DebuggerInitialize);769  }770 771  static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance); }772 773  static lldb_private::SymbolFile *774  CreateInstance(lldb::ObjectFileSP objfile_sp) {775    return new CustomSymbolFileDWARF(std::move(objfile_sp),776                                     /*dwo_section_list*/ nullptr);777  }778 779  lldb::offset_t780  GetVendorDWARFOpcodeSize(const lldb_private::DataExtractor &data,781                           const lldb::offset_t data_offset,782                           const uint8_t op) const final {783    auto offset = data_offset;784    if (op != DW_OP_WASM_location) {785      return LLDB_INVALID_OFFSET;786    }787 788    // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32789    // Called with "arguments" 0x03 and 0x04790    // Location type:791    if (data.GetU8(&offset) != /* global */ 0x03) {792      return LLDB_INVALID_OFFSET;793    }794 795    // Index796    if (data.GetU32(&offset) != 0x04) {797      return LLDB_INVALID_OFFSET;798    }799 800    // Report the skipped distance:801    return offset - data_offset;802  }803 804  virtual bool ParseVendorDWARFOpcode(805      uint8_t op, const lldb_private::DataExtractor &opcodes,806      lldb::offset_t &offset,807 808      RegisterContext *reg_ctx, lldb::RegisterKind reg_kind,809      std::vector<lldb_private::Value> &stack) const override {810    if (op != DW_OP_WASM_location) {811      return false;812    }813 814    // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32815    // Called with "arguments" 0x03 and  0x04816    // Location type:817    if (opcodes.GetU8(&offset) != /* global */ 0x03) {818      return false;819    }820 821    // Index:822    if (opcodes.GetU32(&offset) != 0x04) {823      return false;824    }825 826    // Return some value:827    stack.push_back({GetScalar(32, 42, false)});828    return true;829  }830};831 832char CustomSymbolFileDWARF::ID;833 834static auto testExpressionVendorExtensions(lldb::ModuleSP module_sp,835                                           DWARFUnit &dwarf_unit,836                                           RegisterContext *reg_ctx) {837  // Test that expression extensions can be evaluated, for example838  // DW_OP_WASM_location which is not currently handled by DWARFExpression:839  EXPECT_THAT_EXPECTED(840      Evaluate({DW_OP_WASM_location, 0x03, // WASM_GLOBAL:0x03841                0x04, 0x00, 0x00,          // index:u32842                0x00, DW_OP_stack_value},843               module_sp, &dwarf_unit, nullptr, reg_ctx),844      ExpectScalar(32, 42, false, Value::ContextType::RegisterInfo));845 846  // Test that searches for opcodes work in the presence of extensions:847  uint8_t expr[] = {DW_OP_WASM_location,   0x03, 0x04, 0x00, 0x00, 0x00,848                    DW_OP_form_tls_address};849  DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle,850                          /*addr_size*/ 4);851  DWARFExpression dwarf_expr(extractor);852  ASSERT_TRUE(dwarf_expr.ContainsThreadLocalStorage(&dwarf_unit));853}854 855TEST(DWARFExpression, Extensions) {856  const char *yamldata = R"(857--- !WASM858FileHeader:859  Version:         0x1860Sections:861  - Type:            TYPE862    Signatures:863      - Index:           0864        ParamTypes:865          - I32866        ReturnTypes:867          - I32868  - Type:            FUNCTION869    FunctionTypes:   [ 0 ]870  - Type:            TABLE871    Tables:872      - Index:           0873        ElemType:        FUNCREF874        Limits:875          Flags:           [ HAS_MAX ]876          Minimum:         0x1877          Maximum:         0x1878  - Type:            MEMORY879    Memories:880      - Flags:           [ HAS_MAX ]881        Minimum:         0x100882        Maximum:         0x100883  - Type:            GLOBAL884    Globals:885      - Index:           0886        Type:            I32887        Mutable:         true888        InitExpr:889          Opcode:          I32_CONST890          Value:           65536891  - Type:            EXPORT892    Exports:893      - Name:            memory894        Kind:            MEMORY895        Index:           0896      - Name:            square897        Kind:            FUNCTION898        Index:           0899      - Name:            __indirect_function_table900        Kind:            TABLE901        Index:           0902  - Type:            CODE903    Functions:904      - Index:           0905        Locals:906          - Type:            I32907            Count:           1908          - Type:            I32909            Count:           1910          - Type:            I32911            Count:           1912          - Type:            I32913            Count:           1914          - Type:            I32915            Count:           1916          - Type:            I32917            Count:           1918        Body:            2300210141102102200120026B21032003200036020C200328020C2104200328020C2105200420056C210620060F0B919  - Type:            CUSTOM920    Name:            name921    FunctionNames:922      - Index:           0923        Name:            square924    GlobalNames:925      - Index:           0926        Name:            __stack_pointer927  - Type:            CUSTOM928    Name:            .debug_abbrev929    Payload:         011101250E1305030E10171B0E110112060000022E01110112064018030E3A0B3B0B271949133F1900000305000218030E3A0B3B0B49130000042400030E3E0B0B0B000000930  - Type:            CUSTOM931    Name:            .debug_info932    Payload:         510000000400000000000401670000001D005E000000000000000A000000020000003C00000002020000003C00000004ED00039F5700000001014D0000000302910C0400000001014D000000000400000000050400933  - Type:            CUSTOM934    Name:            .debug_str935    Payload:         696E740076616C756500513A5C70616F6C6F7365764D5346545C6C6C766D2D70726F6A6563745C6C6C64625C746573745C4150495C66756E6374696F6E616C69746965735C6764625F72656D6F74655F636C69656E745C737175617265007371756172652E6300636C616E672076657273696F6E2031382E302E30202868747470733A2F2F6769746875622E636F6D2F6C6C766D2F6C6C766D2D70726F6A65637420373535303166353336323464653932616166636532663164613639386232343961373239336463372900936  - Type:            CUSTOM937    Name:            .debug_line938    Payload:         64000000040020000000010101FB0E0D000101010100000001000001007371756172652E6300000000000005020200000001000502250000000301050A0A010005022C00000005120601000502330000000510010005023A0000000503010005023E000000000101939)";940 941  SubsystemRAII<FileSystem, HostInfo, ObjectFileWasm, SymbolVendorWasm>942      subsystems;943 944  // Set up a wasm target.945  TestContext test_ctx;946  const uint32_t kExpectedValue = 42;947  ASSERT_TRUE(CreateTestContext(&test_ctx, "wasm32-unknown-unknown-wasm",948                                RegisterValue(kExpectedValue)));949 950  llvm::Expected<TestFile> file = TestFile::fromYaml(yamldata);951  EXPECT_THAT_EXPECTED(file, llvm::Succeeded());952  auto module_sp = std::make_shared<Module>(file->moduleSpec());953  auto obj_file_sp = module_sp->GetObjectFile()->shared_from_this();954  SymbolFileWasm sym_file_wasm(obj_file_sp, nullptr);955  auto *dwarf_unit = sym_file_wasm.DebugInfo().GetUnitAtIndex(0);956 957  testExpressionVendorExtensions(module_sp, *dwarf_unit,958                                 test_ctx.reg_ctx_sp.get());959}960 961TEST(DWARFExpression, ExtensionsSplitSymbols) {962  const char *skeleton_yamldata = R"(963--- !WASM964FileHeader:965  Version:         0x1966Sections:967  - Type:            TYPE968    Signatures:969      - Index:           0970        ParamTypes:971          - I32972        ReturnTypes:973          - I32974  - Type:            FUNCTION975    FunctionTypes:   [ 0 ]976  - Type:            TABLE977    Tables:978      - Index:           0979        ElemType:        FUNCREF980        Limits:981          Flags:           [ HAS_MAX ]982          Minimum:         0x1983          Maximum:         0x1984  - Type:            MEMORY985    Memories:986      - Flags:           [ HAS_MAX ]987        Minimum:         0x100988        Maximum:         0x100989  - Type:            GLOBAL990    Globals:991      - Index:           0992        Type:            I32993        Mutable:         true994        InitExpr:995          Opcode:          I32_CONST996          Value:           65536997  - Type:            EXPORT998    Exports:999      - Name:            memory1000        Kind:            MEMORY1001        Index:           01002      - Name:            square1003        Kind:            FUNCTION1004        Index:           01005      - Name:            __indirect_function_table1006        Kind:            TABLE1007        Index:           01008  - Type:            CODE1009    Functions:1010      - Index:           01011        Locals:1012          - Type:            I321013            Count:           11014          - Type:            I321015            Count:           11016          - Type:            I321017            Count:           11018          - Type:            I321019            Count:           11020          - Type:            I321021            Count:           11022          - Type:            I321023            Count:           11024        Body:            2300210141102102200120026B21032003200036020C200328020C2104200328020C2105200420056C210620060F0B1025  - Type:            CUSTOM1026    Name:            name1027    FunctionNames:1028      - Index:           01029        Name:            square1030    GlobalNames:1031      - Index:           01032        Name:            __stack_pointer1033  - Type:            CUSTOM1034    Name:            external_debug_info1035    Payload:         167371756172652E7761736D2E64656275672E7761736D1036)";1037 1038  const char *sym_yamldata = R"(1039--- !WASM1040FileHeader:1041  Version:         0x11042Sections:1043  - Type:            TYPE1044    Signatures:1045      - Index:           01046        ParamTypes:1047          - I321048        ReturnTypes:1049          - I321050  - Type:            FUNCTION1051    FunctionTypes:   [ 0 ]1052  - Type:            TABLE1053    Tables:1054      - Index:           01055        ElemType:        FUNCREF1056        Limits:1057          Flags:           [ HAS_MAX ]1058          Minimum:         0x11059          Maximum:         0x11060  - Type:            MEMORY1061    Memories:1062      - Flags:           [ HAS_MAX ]1063        Minimum:         0x1001064        Maximum:         0x1001065  - Type:            GLOBAL1066    Globals:1067      - Index:           01068        Type:            I321069        Mutable:         true1070        InitExpr:1071          Opcode:          I32_CONST1072          Value:           655361073  - Type:            EXPORT1074    Exports:1075      - Name:            memory1076        Kind:            MEMORY1077        Index:           01078      - Name:            square1079        Kind:            FUNCTION1080        Index:           01081      - Name:            __indirect_function_table1082        Kind:            TABLE1083        Index:           01084  - Type:            CODE1085    Functions:1086      - Index:           01087        Locals:1088          - Type:            I321089            Count:           11090          - Type:            I321091            Count:           11092          - Type:            I321093            Count:           11094          - Type:            I321095            Count:           11096          - Type:            I321097            Count:           11098          - Type:            I321099            Count:           11100        Body:            2300210141102102200120026B21032003200036020C200328020C2104200328020C2105200420056C210620060F0B1101  - Type:            CUSTOM1102    Name:            name1103    FunctionNames:1104      - Index:           01105        Name:            square1106    GlobalNames:1107      - Index:           01108        Name:            __stack_pointer1109  - Type:            CUSTOM1110    Name:            .debug_abbrev1111    Payload:         011101250E1305030E10171B0E110112060000022E01110112064018030E3A0B3B0B271949133F1900000305000218030E3A0B3B0B49130000042400030E3E0B0B0B0000001112  - Type:            CUSTOM1113    Name:            .debug_info1114    Payload:         510000000400000000000401670000001D005E0000000000000004000000020000003C00000002020000003C00000004ED00039F5700000001014D0000000302910C5100000001014D0000000004000000000504001115  - Type:            CUSTOM1116    Name:            .debug_str1117    Payload:         696E7400513A5C70616F6C6F7365764D5346545C6C6C766D2D70726F6A6563745C6C6C64625C746573745C4150495C66756E6374696F6E616C69746965735C6764625F72656D6F74655F636C69656E740076616C756500737175617265007371756172652E6300636C616E672076657273696F6E2031382E302E30202868747470733A2F2F6769746875622E636F6D2F6C6C766D2F6C6C766D2D70726F6A656374203735353031663533363234646539326161666365326631646136393862323439613732393364633729001118  - Type:            CUSTOM1119    Name:            .debug_line1120    Payload:         64000000040020000000010101FB0E0D000101010100000001000001007371756172652E6300000000000005020200000001000502250000000301050A0A010005022C00000005120601000502330000000510010005023A0000000503010005023E0000000001011121)";1122 1123  SubsystemRAII<FileSystem, HostInfo, ObjectFileWasm, SymbolVendorWasm>1124      subsystems;1125 1126  // Set up a wasm target.1127  TestContext test_ctx;1128  const uint32_t kExpectedValue = 42;1129  ASSERT_TRUE(CreateTestContext(&test_ctx, "wasm32-unknown-unknown-wasm",1130                                RegisterValue(kExpectedValue)));1131 1132  llvm::Expected<TestFile> skeleton_file =1133      TestFile::fromYaml(skeleton_yamldata);1134  EXPECT_THAT_EXPECTED(skeleton_file, llvm::Succeeded());1135  auto skeleton_module_sp =1136      std::make_shared<Module>(skeleton_file->moduleSpec());1137 1138  llvm::Expected<TestFile> sym_file = TestFile::fromYaml(sym_yamldata);1139  EXPECT_THAT_EXPECTED(sym_file, llvm::Succeeded());1140  auto sym_module_sp = std::make_shared<Module>(sym_file->moduleSpec());1141 1142  auto obj_file_sp = sym_module_sp->GetObjectFile()->shared_from_this();1143  SymbolFileWasm sym_file_wasm(obj_file_sp, nullptr);1144  auto *dwarf_unit = sym_file_wasm.DebugInfo().GetUnitAtIndex(0);1145 1146  testExpressionVendorExtensions(sym_module_sp, *dwarf_unit,1147                                 test_ctx.reg_ctx_sp.get());1148}1149 1150TEST_F(DWARFExpressionMockProcessTest, DW_OP_piece_file_addr) {1151  using ::testing::ByMove;1152  using ::testing::ElementsAre;1153  using ::testing::Return;1154 1155  // Set up a mock process.1156  TestContext test_ctx;1157  MockMemory::Map memory = {1158      {{0x40, 1}, {0x11}},1159      {{0x50, 1}, {0x22}},1160  };1161  ASSERT_TRUE(1162      CreateTestContext(&test_ctx, "i386-pc-linux", {}, {}, std::move(memory)));1163  ASSERT_TRUE(test_ctx.target_sp->GetArchitecture().IsValid());1164 1165  ExecutionContext exe_ctx(test_ctx.target_sp, false);1166 1167  uint8_t expr[] = {DW_OP_addr, 0x40, 0x0, 0x0, 0x0, DW_OP_piece, 1,1168                    DW_OP_addr, 0x50, 0x0, 0x0, 0x0, DW_OP_piece, 1};1169  EXPECT_THAT_EXPECTED(Evaluate(expr, {}, {}, &exe_ctx),1170                       ExpectHostAddress({0x11, 0x22}));1171}1172 1173class DWARFExpressionMockProcessTestWithAArch1174    : public DWARFExpressionMockProcessTest {1175public:1176  void SetUp() override {1177    DWARFExpressionMockProcessTest::SetUp();1178#ifdef ARCH_AARCH641179    LLVMInitializeAArch64TargetInfo();1180    LLVMInitializeAArch64TargetMC();1181    ABISysV_arm64::Initialize();1182#endif1183  }1184  void TearDown() override {1185    DWARFExpressionMockProcessTest::TearDown();1186#ifdef ARCH_AARCH641187    ABISysV_arm64::Terminate();1188#endif1189  }1190};1191 1192/// Sets the value of register x22 to "42".1193/// Creates a process whose memory address 42 contains the value1194///   memory[42] = ((0xffULL) << 56) | 0xabcdef;1195/// The expression DW_OP_breg22, 0, DW_OP_deref should produce that same value,1196/// without clearing the top byte 0xff.1197TEST_F(DWARFExpressionMockProcessTestWithAArch, DW_op_deref_no_ptr_fixing) {1198  constexpr lldb::addr_t expected_value = ((0xffULL) << 56) | 0xabcdefULL;1199  constexpr lldb::addr_t addr = 42;1200  MockMemory::Map memory = {1201      {{addr, sizeof(addr)}, {0xef, 0xcd, 0xab, 0x00, 0x00, 0x00, 0x00, 0xff}}};1202 1203  TestContext test_ctx;1204  ASSERT_TRUE(CreateTestContext(&test_ctx, "aarch64-pc-linux",1205                                RegisterValue(addr), std::move(memory)));1206 1207  auto evaluate_expr = [&](auto &expr_data) {1208    ExecutionContext exe_ctx(test_ctx.process_sp);1209    return Evaluate(expr_data, {}, {}, &exe_ctx, test_ctx.reg_ctx_sp.get());1210  };1211 1212  uint8_t expr_reg[] = {DW_OP_breg22, 0};1213  llvm::Expected<Value> result_reg = evaluate_expr(expr_reg);1214  EXPECT_THAT_EXPECTED(result_reg, ExpectLoadAddress(addr));1215 1216  uint8_t expr_deref[] = {DW_OP_breg22, 0, DW_OP_deref};1217  llvm::Expected<Value> result_deref = evaluate_expr(expr_deref);1218  EXPECT_THAT_EXPECTED(result_deref, ExpectLoadAddress(expected_value));1219}1220