Skip to content

Commit b97ac12

Browse files
committed
[lldb] Add mock dwarf delegate for testing dwarf expressions
This commit adds a `MockDwarfDelegate` class that can be used to control what dwarf version is used when evaluating an expression. We also add a simple test that shows how dwarf version can change the result of the expression.
1 parent f6ebb35 commit b97ac12

File tree

1 file changed

+59
-1
lines changed

1 file changed

+59
-1
lines changed

lldb/unittests/Expression/DWARFExpressionTest.cpp

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,51 @@ using namespace lldb_private;
3939
using namespace llvm::dwarf;
4040

4141
namespace {
42+
/// A mock implementation of DWARFExpression::Delegate for testing.
43+
/// This class provides default implementations of all delegate methods,
44+
/// with the DWARF version being configurable via the constructor.
45+
class MockDwarfDelegate : public DWARFExpression::Delegate {
46+
public:
47+
static constexpr uint16_t DEFAULT_DWARF_VERSION = 5;
48+
static MockDwarfDelegate Dwarf5() { return MockDwarfDelegate(5); }
49+
static MockDwarfDelegate Dwarf2() { return MockDwarfDelegate(2); }
50+
51+
MockDwarfDelegate() : MockDwarfDelegate(DEFAULT_DWARF_VERSION) {}
52+
explicit MockDwarfDelegate(uint16_t version) : m_version(version) {}
53+
54+
uint16_t GetVersion() const override { return m_version; }
55+
56+
dw_addr_t GetBaseAddress() const override { return 0; }
57+
58+
uint8_t GetAddressByteSize() const override { return 4; }
59+
60+
llvm::Expected<std::pair<uint64_t, bool>>
61+
GetDIEBitSizeAndSign(uint64_t relative_die_offset) const override {
62+
return llvm::createStringError(llvm::inconvertibleErrorCode(),
63+
"GetDIEBitSizeAndSign not implemented");
64+
}
65+
66+
dw_addr_t ReadAddressFromDebugAddrSection(uint32_t index) const override {
67+
return 0;
68+
}
69+
70+
lldb::offset_t GetVendorDWARFOpcodeSize(const DataExtractor &data,
71+
const lldb::offset_t data_offset,
72+
const uint8_t op) const override {
73+
return LLDB_INVALID_OFFSET;
74+
}
75+
76+
bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,
77+
lldb::offset_t &offset, RegisterContext *reg_ctx,
78+
lldb::RegisterKind reg_kind,
79+
DWARFExpression::Stack &stack) const override {
80+
return false;
81+
}
82+
83+
private:
84+
uint16_t m_version;
85+
};
86+
4287
struct MockProcess : Process {
4388
MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
4489
: Process(target_sp, listener_sp) {}
@@ -164,7 +209,7 @@ class MockRegisterContext : public RegisterContext {
164209

165210
static llvm::Expected<Value> Evaluate(llvm::ArrayRef<uint8_t> expr,
166211
lldb::ModuleSP module_sp = {},
167-
DWARFUnit *unit = nullptr,
212+
DWARFExpression::Delegate *unit = nullptr,
168213
ExecutionContext *exe_ctx = nullptr,
169214
RegisterContext *reg_ctx = nullptr) {
170215
DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle,
@@ -505,6 +550,19 @@ TEST(DWARFExpression, DW_OP_stack_value) {
505550
EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed());
506551
}
507552

553+
TEST(DWARFExpression, dwarf_version) {
554+
MockDwarfDelegate dwarf2 = MockDwarfDelegate::Dwarf2();
555+
MockDwarfDelegate dwarf5 = MockDwarfDelegate::Dwarf5();
556+
557+
// In dwarf2 the constant on top of the stack is treated as a value.
558+
EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1}, {}, &dwarf2), ExpectScalar(1));
559+
560+
// In dwarf5 the constant on top of the stack is implicitly converted to an
561+
// address.
562+
EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1}, {}, &dwarf5),
563+
ExpectLoadAddress(1));
564+
}
565+
508566
TEST(DWARFExpression, DW_OP_piece) {
509567
EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x11, 0x22, DW_OP_piece, 2,
510568
DW_OP_const2u, 0x33, 0x44, DW_OP_piece, 2}),

0 commit comments

Comments
 (0)