diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index 13110ef7cbb0a..88bbf863e4435 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -39,6 +39,51 @@ using namespace lldb_private; using namespace llvm::dwarf; namespace { +/// A mock implementation of DWARFExpression::Delegate for testing. +/// This class provides default implementations of all delegate methods, +/// with the DWARF version being configurable via the constructor. +class MockDwarfDelegate : public DWARFExpression::Delegate { +public: + static constexpr uint16_t DEFAULT_DWARF_VERSION = 5; + static MockDwarfDelegate Dwarf5() { return MockDwarfDelegate(5); } + static MockDwarfDelegate Dwarf2() { return MockDwarfDelegate(2); } + + MockDwarfDelegate() : MockDwarfDelegate(DEFAULT_DWARF_VERSION) {} + explicit MockDwarfDelegate(uint16_t version) : m_version(version) {} + + uint16_t GetVersion() const override { return m_version; } + + dw_addr_t GetBaseAddress() const override { return 0; } + + uint8_t GetAddressByteSize() const override { return 4; } + + llvm::Expected> + GetDIEBitSizeAndSign(uint64_t relative_die_offset) const override { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "GetDIEBitSizeAndSign not implemented"); + } + + dw_addr_t ReadAddressFromDebugAddrSection(uint32_t index) const override { + return 0; + } + + lldb::offset_t GetVendorDWARFOpcodeSize(const DataExtractor &data, + const lldb::offset_t data_offset, + const uint8_t op) const override { + return LLDB_INVALID_OFFSET; + } + + bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes, + lldb::offset_t &offset, RegisterContext *reg_ctx, + lldb::RegisterKind reg_kind, + DWARFExpression::Stack &stack) const override { + return false; + } + +private: + uint16_t m_version; +}; + struct MockProcess : Process { MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp) : Process(target_sp, listener_sp) {} @@ -164,7 +209,7 @@ class MockRegisterContext : public RegisterContext { static llvm::Expected Evaluate(llvm::ArrayRef expr, lldb::ModuleSP module_sp = {}, - DWARFUnit *unit = nullptr, + DWARFExpression::Delegate *unit = nullptr, ExecutionContext *exe_ctx = nullptr, RegisterContext *reg_ctx = nullptr) { DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle, @@ -505,6 +550,19 @@ TEST(DWARFExpression, DW_OP_stack_value) { EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed()); } +TEST(DWARFExpression, dwarf_version) { + MockDwarfDelegate dwarf2 = MockDwarfDelegate::Dwarf2(); + MockDwarfDelegate dwarf5 = MockDwarfDelegate::Dwarf5(); + + // In dwarf2 the constant on top of the stack is treated as a value. + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1}, {}, &dwarf2), ExpectScalar(1)); + + // In dwarf5 the constant on top of the stack is implicitly converted to an + // address. + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1}, {}, &dwarf5), + ExpectLoadAddress(1)); +} + TEST(DWARFExpression, DW_OP_piece) { EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x11, 0x22, DW_OP_piece, 2, DW_OP_const2u, 0x33, 0x44, DW_OP_piece, 2}),