|
7 | 7 | //===----------------------------------------------------------------------===//
|
8 | 8 |
|
9 | 9 | #include "lldb/Expression/DWARFExpression.h"
|
| 10 | +#ifdef ARCH_AARCH64 |
| 11 | +#include "Plugins/ABI/AArch64/ABISysV_arm64.h" |
| 12 | +#endif |
10 | 13 | #include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"
|
11 | 14 | #include "Plugins/Platform/Linux/PlatformLinux.h"
|
12 | 15 | #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
|
|
21 | 24 | #include "lldb/Core/dwarf.h"
|
22 | 25 | #include "lldb/Host/HostInfo.h"
|
23 | 26 | #include "lldb/Symbol/ObjectFile.h"
|
| 27 | +#include "lldb/Target/ABI.h" |
24 | 28 | #include "lldb/Target/RegisterContext.h"
|
25 | 29 | #include "lldb/Utility/RegisterValue.h"
|
26 | 30 | #include "lldb/Utility/StreamString.h"
|
27 | 31 | #include "llvm/ADT/StringExtras.h"
|
| 32 | +#include "llvm/Support/TargetSelect.h" |
28 | 33 | #include "llvm/Testing/Support/Error.h"
|
29 | 34 | #include "gtest/gtest.h"
|
30 | 35 |
|
@@ -199,6 +204,26 @@ class DWARFExpressionMockProcessTest : public ::testing::Test {
|
199 | 204 | }
|
200 | 205 | };
|
201 | 206 |
|
| 207 | +struct PlatformTargetDebugger { |
| 208 | + lldb::PlatformSP platform_sp; |
| 209 | + lldb::TargetSP target_sp; |
| 210 | + lldb::DebuggerSP debugger_sp; |
| 211 | +}; |
| 212 | + |
| 213 | +/// A helper function to create <Platform, Target, Debugger> objects with the |
| 214 | +/// "aarch64-pc-linux" ArchSpec. |
| 215 | +static PlatformTargetDebugger CreateTarget() { |
| 216 | + ArchSpec arch("aarch64-pc-linux"); |
| 217 | + Platform::SetHostPlatform( |
| 218 | + platform_linux::PlatformLinux::CreateInstance(true, &arch)); |
| 219 | + lldb::PlatformSP platform_sp; |
| 220 | + lldb::TargetSP target_sp; |
| 221 | + lldb::DebuggerSP debugger_sp = Debugger::CreateInstance(); |
| 222 | + debugger_sp->GetTargetList().CreateTarget( |
| 223 | + *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp); |
| 224 | + return PlatformTargetDebugger{platform_sp, target_sp, debugger_sp}; |
| 225 | +} |
| 226 | + |
202 | 227 | // NB: This class doesn't use the override keyword to avoid
|
203 | 228 | // -Winconsistent-missing-override warnings from the compiler. The
|
204 | 229 | // inconsistency comes from the overriding definitions in the MOCK_*** macros.
|
@@ -1135,3 +1160,96 @@ TEST_F(DWARFExpressionMockProcessTest, DW_OP_piece_file_addr) {
|
1135 | 1160 | ASSERT_EQ(result->GetValueType(), Value::ValueType::HostAddress);
|
1136 | 1161 | ASSERT_THAT(result->GetBuffer().GetData(), ElementsAre(0x11, 0x22));
|
1137 | 1162 | }
|
| 1163 | + |
| 1164 | +/// A Process whose `ReadMemory` override queries a DenseMap. |
| 1165 | +struct MockProcessWithMemRead : Process { |
| 1166 | + using addr_t = lldb::addr_t; |
| 1167 | + |
| 1168 | + llvm::DenseMap<addr_t, addr_t> memory_map; |
| 1169 | + |
| 1170 | + MockProcessWithMemRead(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, |
| 1171 | + llvm::DenseMap<addr_t, addr_t> &&memory_map) |
| 1172 | + : Process(target_sp, listener_sp), memory_map(memory_map) {} |
| 1173 | + size_t DoReadMemory(addr_t vm_addr, void *buf, size_t size, |
| 1174 | + Status &error) override { |
| 1175 | + assert(memory_map.contains(vm_addr)); |
| 1176 | + assert(size == sizeof(addr_t)); |
| 1177 | + *reinterpret_cast<addr_t *>(buf) = memory_map[vm_addr]; |
| 1178 | + return sizeof(addr_t); |
| 1179 | + } |
| 1180 | + size_t ReadMemory(addr_t addr, void *buf, size_t size, |
| 1181 | + Status &status) override { |
| 1182 | + return DoReadMemory(addr, buf, size, status); |
| 1183 | + } |
| 1184 | + bool CanDebug(lldb::TargetSP, bool) override { return true; } |
| 1185 | + Status DoDestroy() override { return Status(); } |
| 1186 | + llvm::StringRef GetPluginName() override { return ""; } |
| 1187 | + void RefreshStateAfterStop() override {} |
| 1188 | + bool DoUpdateThreadList(ThreadList &, ThreadList &) override { return false; } |
| 1189 | +}; |
| 1190 | + |
| 1191 | +class DWARFExpressionMockProcessTestWithAArch |
| 1192 | + : public DWARFExpressionMockProcessTest { |
| 1193 | +public: |
| 1194 | + void SetUp() override { |
| 1195 | + DWARFExpressionMockProcessTest::SetUp(); |
| 1196 | +#ifdef ARCH_AARCH64 |
| 1197 | + LLVMInitializeAArch64TargetInfo(); |
| 1198 | + LLVMInitializeAArch64TargetMC(); |
| 1199 | + ABISysV_arm64::Initialize(); |
| 1200 | +#endif |
| 1201 | + } |
| 1202 | + void TearDown() override { |
| 1203 | + DWARFExpressionMockProcessTest::TearDown(); |
| 1204 | +#ifdef ARCH_AARCH64 |
| 1205 | + ABISysV_arm64::Terminate(); |
| 1206 | +#endif |
| 1207 | + } |
| 1208 | +}; |
| 1209 | + |
| 1210 | +/// Sets the value of register x22 to "42". |
| 1211 | +/// Creates a process whose memory address 42 contains the value |
| 1212 | +/// memory[42] = ((0xffULL) << 56) | 0xabcdef; |
| 1213 | +/// The expression DW_OP_breg22, 0, DW_OP_deref should produce that same value, |
| 1214 | +/// without clearing the top byte 0xff. |
| 1215 | +TEST_F(DWARFExpressionMockProcessTestWithAArch, DW_op_deref_no_ptr_fixing) { |
| 1216 | + llvm::DenseMap<lldb::addr_t, lldb::addr_t> memory; |
| 1217 | + constexpr lldb::addr_t expected_value = ((0xffULL) << 56) | 0xabcdefULL; |
| 1218 | + constexpr lldb::addr_t addr = 42; |
| 1219 | + memory[addr] = expected_value; |
| 1220 | + |
| 1221 | + PlatformTargetDebugger test_setup = CreateTarget(); |
| 1222 | + lldb::ProcessSP process_sp = std::make_shared<MockProcessWithMemRead>( |
| 1223 | + test_setup.target_sp, Listener::MakeListener("dummy"), std::move(memory)); |
| 1224 | + auto thread = std::make_shared<MockThread>(*process_sp); |
| 1225 | + lldb::RegisterContextSP reg_ctx_sp = |
| 1226 | + std::make_shared<MockRegisterContext>(*thread, RegisterValue(addr)); |
| 1227 | + thread->SetRegisterContext(reg_ctx_sp); |
| 1228 | + process_sp->GetThreadList().AddThread(thread); |
| 1229 | + |
| 1230 | + auto evaluate_expr = [&](auto &expr_data) { |
| 1231 | + DataExtractor extractor(expr_data, sizeof(expr_data), |
| 1232 | + lldb::eByteOrderLittle, |
| 1233 | + /*addr_size*/ 8); |
| 1234 | + DWARFExpression expr(extractor); |
| 1235 | + |
| 1236 | + ExecutionContext exe_ctx(process_sp); |
| 1237 | + llvm::Expected<Value> result = DWARFExpression::Evaluate( |
| 1238 | + &exe_ctx, reg_ctx_sp.get(), /*module_sp*/ nullptr, extractor, |
| 1239 | + /*unit*/ nullptr, lldb::eRegisterKindLLDB, |
| 1240 | + /*initial_value_ptr=*/nullptr, |
| 1241 | + /*object_address_ptr=*/nullptr); |
| 1242 | + return result; |
| 1243 | + }; |
| 1244 | + |
| 1245 | + uint8_t expr_reg[] = {DW_OP_breg22, 0}; |
| 1246 | + llvm::Expected<Value> result_reg = evaluate_expr(expr_reg); |
| 1247 | + ASSERT_THAT_EXPECTED(result_reg, llvm::Succeeded()); |
| 1248 | + ASSERT_EQ(result_reg->GetValueType(), Value::ValueType::LoadAddress); |
| 1249 | + ASSERT_EQ(result_reg->GetScalar().ULongLong(), addr); |
| 1250 | + |
| 1251 | + uint8_t expr_deref[] = {DW_OP_breg22, 0, DW_OP_deref}; |
| 1252 | + llvm::Expected<Value> result_deref = evaluate_expr(expr_deref); |
| 1253 | + ASSERT_THAT_EXPECTED(result_deref, llvm::Succeeded()); |
| 1254 | + ASSERT_EQ(result_deref->GetScalar().ULongLong(), expected_value); |
| 1255 | +} |
0 commit comments