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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Expression/DWARFExpression.h" 10 #include "Plugins/Platform/Linux/PlatformLinux.h" 11 #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" 12 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" 13 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" 14 #include "TestingSupport/Symbol/YAMLModuleTester.h" 15 #include "lldb/Core/Debugger.h" 16 #include "lldb/Core/PluginManager.h" 17 #include "lldb/Core/Value.h" 18 #include "lldb/Core/dwarf.h" 19 #include "lldb/Host/HostInfo.h" 20 #include "lldb/Symbol/ObjectFile.h" 21 #include "lldb/Utility/StreamString.h" 22 #include "llvm/ADT/StringExtras.h" 23 #include "llvm/Testing/Support/Error.h" 24 #include "gtest/gtest.h" 25 26 using namespace lldb_private; 27 using namespace lldb_private::dwarf; 28 using namespace lldb_private::plugin::dwarf; 29 30 static llvm::Expected<Scalar> Evaluate(llvm::ArrayRef<uint8_t> expr, 31 lldb::ModuleSP module_sp = {}, 32 DWARFUnit *unit = nullptr, 33 ExecutionContext *exe_ctx = nullptr) { 34 DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle, 35 /*addr_size*/ 4); 36 37 llvm::Expected<Value> result = 38 DWARFExpression::Evaluate(exe_ctx, /*reg_ctx*/ nullptr, module_sp, 39 extractor, unit, lldb::eRegisterKindLLDB, 40 /*initial_value_ptr*/ nullptr, 41 /*object_address_ptr*/ nullptr); 42 if (!result) 43 return result.takeError(); 44 45 switch (result->GetValueType()) { 46 case Value::ValueType::Scalar: 47 return result->GetScalar(); 48 case Value::ValueType::LoadAddress: 49 return LLDB_INVALID_ADDRESS; 50 case Value::ValueType::HostAddress: { 51 // Convert small buffers to scalars to simplify the tests. 52 DataBufferHeap &buf = result->GetBuffer(); 53 if (buf.GetByteSize() <= 8) { 54 uint64_t val = 0; 55 memcpy(&val, buf.GetBytes(), buf.GetByteSize()); 56 return Scalar(llvm::APInt(buf.GetByteSize()*8, val, false)); 57 } 58 } 59 [[fallthrough]]; 60 default: 61 break; 62 } 63 return llvm::createStringError("unsupported value type"); 64 } 65 66 class DWARFExpressionTester : public YAMLModuleTester { 67 public: 68 DWARFExpressionTester(llvm::StringRef yaml_data, size_t cu_index) : 69 YAMLModuleTester(yaml_data, cu_index) {} 70 71 using YAMLModuleTester::YAMLModuleTester; 72 llvm::Expected<Scalar> Eval(llvm::ArrayRef<uint8_t> expr) { 73 return ::Evaluate(expr, m_module_sp, m_dwarf_unit); 74 } 75 }; 76 77 /// Unfortunately Scalar's operator==() is really picky. 78 static Scalar GetScalar(unsigned bits, uint64_t value, bool sign) { 79 Scalar scalar(value); 80 scalar.TruncOrExtendTo(bits, sign); 81 return scalar; 82 } 83 84 /// This is needed for the tests that use a mock process. 85 class DWARFExpressionMockProcessTest : public ::testing::Test { 86 public: 87 void SetUp() override { 88 FileSystem::Initialize(); 89 HostInfo::Initialize(); 90 platform_linux::PlatformLinux::Initialize(); 91 } 92 void TearDown() override { 93 platform_linux::PlatformLinux::Terminate(); 94 HostInfo::Terminate(); 95 FileSystem::Terminate(); 96 } 97 }; 98 99 // NB: This class doesn't use the override keyword to avoid 100 // -Winconsistent-missing-override warnings from the compiler. The 101 // inconsistency comes from the overriding definitions in the MOCK_*** macros. 102 class MockTarget : public Target { 103 public: 104 MockTarget(Debugger &debugger, const ArchSpec &target_arch, 105 const lldb::PlatformSP &platform_sp) 106 : Target(debugger, target_arch, platform_sp, true) {} 107 108 MOCK_METHOD2(ReadMemory, 109 llvm::Expected<std::vector<uint8_t>>(lldb::addr_t addr, 110 size_t size)); 111 112 size_t ReadMemory(const Address &addr, void *dst, size_t dst_len, 113 Status &error, bool force_live_memory = false, 114 lldb::addr_t *load_addr_ptr = nullptr) /*override*/ { 115 auto expected_memory = this->ReadMemory(addr.GetOffset(), dst_len); 116 if (!expected_memory) { 117 llvm::consumeError(expected_memory.takeError()); 118 return 0; 119 } 120 const size_t bytes_read = expected_memory->size(); 121 assert(bytes_read <= dst_len); 122 std::memcpy(dst, expected_memory->data(), bytes_read); 123 return bytes_read; 124 } 125 }; 126 127 TEST(DWARFExpression, DW_OP_pick) { 128 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 0}), 129 llvm::HasValue(0)); 130 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 1}), 131 llvm::HasValue(1)); 132 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 2}), 133 llvm::Failed()); 134 } 135 136 TEST(DWARFExpression, DW_OP_const) { 137 // Extend to address size. 138 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1u, 0x88}), llvm::HasValue(0x88)); 139 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1s, 0x88}), 140 llvm::HasValue(0xffffff88)); 141 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x47, 0x88}), 142 llvm::HasValue(0x8847)); 143 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2s, 0x47, 0x88}), 144 llvm::HasValue(0xffff8847)); 145 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4u, 0x44, 0x42, 0x47, 0x88}), 146 llvm::HasValue(0x88474244)); 147 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4s, 0x44, 0x42, 0x47, 0x88}), 148 llvm::HasValue(0x88474244)); 149 150 // Truncate to address size. 151 EXPECT_THAT_EXPECTED( 152 Evaluate({DW_OP_const8u, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}), 153 llvm::HasValue(0x33221100)); 154 EXPECT_THAT_EXPECTED( 155 Evaluate({DW_OP_const8s, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}), 156 llvm::HasValue(0x33221100)); 157 158 // Don't truncate to address size for compatibility with clang (pr48087). 159 EXPECT_THAT_EXPECTED( 160 Evaluate({DW_OP_constu, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}), 161 llvm::HasValue(0x01010101010101)); 162 EXPECT_THAT_EXPECTED( 163 Evaluate({DW_OP_consts, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}), 164 llvm::HasValue(0xffff010101010101)); 165 } 166 167 TEST(DWARFExpression, DW_OP_skip) { 168 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1u, 0x42, DW_OP_skip, 0x02, 0x00, 169 DW_OP_const1u, 0xff}), 170 llvm::HasValue(0x42)); 171 } 172 173 TEST(DWARFExpression, DW_OP_bra) { 174 EXPECT_THAT_EXPECTED( 175 // clang-format off 176 Evaluate({ 177 DW_OP_const1u, 0x42, // push 0x42 178 DW_OP_const1u, 0x1, // push 0x1 179 DW_OP_bra, 0x02, 0x00, // if 0x1 > 0, then skip 0x0002 opcodes 180 DW_OP_const1u, 0xff, // push 0xff 181 }), 182 // clang-format on 183 llvm::HasValue(0x42)); 184 185 EXPECT_THAT_ERROR(Evaluate({DW_OP_bra, 0x01, 0x00}).takeError(), 186 llvm::Failed()); 187 } 188 189 TEST(DWARFExpression, DW_OP_convert) { 190 /// Auxiliary debug info. 191 const char *yamldata = R"( 192 --- !ELF 193 FileHeader: 194 Class: ELFCLASS64 195 Data: ELFDATA2LSB 196 Type: ET_EXEC 197 Machine: EM_386 198 DWARF: 199 debug_abbrev: 200 - Table: 201 - Code: 0x00000001 202 Tag: DW_TAG_compile_unit 203 Children: DW_CHILDREN_yes 204 Attributes: 205 - Attribute: DW_AT_language 206 Form: DW_FORM_data2 207 - Code: 0x00000002 208 Tag: DW_TAG_base_type 209 Children: DW_CHILDREN_no 210 Attributes: 211 - Attribute: DW_AT_encoding 212 Form: DW_FORM_data1 213 - Attribute: DW_AT_byte_size 214 Form: DW_FORM_data1 215 debug_info: 216 - Version: 4 217 AddrSize: 8 218 AbbrevTableID: 0 219 AbbrOffset: 0x0 220 Entries: 221 - AbbrCode: 0x00000001 222 Values: 223 - Value: 0x000000000000000C 224 - AbbrCode: 0x00000000 225 - Version: 4 226 AddrSize: 8 227 AbbrevTableID: 0 228 AbbrOffset: 0x0 229 Entries: 230 - AbbrCode: 0x00000001 231 Values: 232 - Value: 0x000000000000000C 233 # 0x0000000e: 234 - AbbrCode: 0x00000002 235 Values: 236 - Value: 0x0000000000000007 # DW_ATE_unsigned 237 - Value: 0x0000000000000004 238 # 0x00000011: 239 - AbbrCode: 0x00000002 240 Values: 241 - Value: 0x0000000000000007 # DW_ATE_unsigned 242 - Value: 0x0000000000000008 243 # 0x00000014: 244 - AbbrCode: 0x00000002 245 Values: 246 - Value: 0x0000000000000005 # DW_ATE_signed 247 - Value: 0x0000000000000008 248 # 0x00000017: 249 - AbbrCode: 0x00000002 250 Values: 251 - Value: 0x0000000000000008 # DW_ATE_unsigned_char 252 - Value: 0x0000000000000001 253 # 0x0000001a: 254 - AbbrCode: 0x00000002 255 Values: 256 - Value: 0x0000000000000006 # DW_ATE_signed_char 257 - Value: 0x0000000000000001 258 # 0x0000001d: 259 - AbbrCode: 0x00000002 260 Values: 261 - Value: 0x000000000000000b # DW_ATE_numeric_string 262 - Value: 0x0000000000000001 263 - AbbrCode: 0x00000000 264 265 )"; 266 // Compile unit relative offsets to each DW_TAG_base_type 267 uint8_t offs_uint32_t = 0x0000000e; 268 uint8_t offs_uint64_t = 0x00000011; 269 uint8_t offs_sint64_t = 0x00000014; 270 uint8_t offs_uchar = 0x00000017; 271 uint8_t offs_schar = 0x0000001a; 272 273 DWARFExpressionTester t(yamldata, /*cu_index=*/1); 274 ASSERT_TRUE((bool)t.GetDwarfUnit()); 275 276 // Constant is given as little-endian. 277 bool is_signed = true; 278 bool not_signed = false; 279 280 // 281 // Positive tests. 282 // 283 284 // Leave as is. 285 EXPECT_THAT_EXPECTED( 286 t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, // 287 DW_OP_convert, offs_uint32_t, DW_OP_stack_value}), 288 llvm::HasValue(GetScalar(64, 0x44332211, not_signed))); 289 290 // Zero-extend to 64 bits. 291 EXPECT_THAT_EXPECTED( 292 t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, // 293 DW_OP_convert, offs_uint64_t, DW_OP_stack_value}), 294 llvm::HasValue(GetScalar(64, 0x44332211, not_signed))); 295 296 // Sign-extend to 64 bits. 297 EXPECT_THAT_EXPECTED( 298 t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, // 299 DW_OP_convert, offs_sint64_t, DW_OP_stack_value}), 300 llvm::HasValue(GetScalar(64, 0xffffffffffeeddcc, is_signed))); 301 302 // Sign-extend, then truncate. 303 EXPECT_THAT_EXPECTED( 304 t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, // 305 DW_OP_convert, offs_sint64_t, // 306 DW_OP_convert, offs_uint32_t, DW_OP_stack_value}), 307 llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed))); 308 309 // Truncate to default unspecified (pointer-sized) type. 310 EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, // 311 DW_OP_convert, offs_sint64_t, // 312 DW_OP_convert, 0x00, DW_OP_stack_value}), 313 llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed))); 314 315 // Truncate to 8 bits. 316 EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert, 317 offs_uchar, DW_OP_stack_value}), 318 llvm::HasValue(GetScalar(8, 'A', not_signed))); 319 320 // Also truncate to 8 bits. 321 EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert, 322 offs_schar, DW_OP_stack_value}), 323 llvm::HasValue(GetScalar(8, 'A', is_signed))); 324 325 // 326 // Errors. 327 // 328 329 // No Module. 330 EXPECT_THAT_ERROR(Evaluate({DW_OP_const1s, 'X', DW_OP_convert, 0x00}, nullptr, 331 t.GetDwarfUnit()) 332 .takeError(), 333 llvm::Failed()); 334 335 // No DIE. 336 EXPECT_THAT_ERROR( 337 t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x01}).takeError(), 338 llvm::Failed()); 339 340 // Unsupported. 341 EXPECT_THAT_ERROR( 342 t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x1d}).takeError(), 343 llvm::Failed()); 344 } 345 346 TEST(DWARFExpression, DW_OP_stack_value) { 347 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed()); 348 } 349 350 TEST(DWARFExpression, DW_OP_piece) { 351 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x11, 0x22, DW_OP_piece, 2, 352 DW_OP_const2u, 0x33, 0x44, DW_OP_piece, 2}), 353 llvm::HasValue(GetScalar(32, 0x44332211, true))); 354 EXPECT_THAT_EXPECTED( 355 Evaluate({DW_OP_piece, 1, DW_OP_const1u, 0xff, DW_OP_piece, 1}), 356 // Note that the "00" should really be "undef", but we can't 357 // represent that yet. 358 llvm::HasValue(GetScalar(16, 0xff00, true))); 359 } 360 361 TEST(DWARFExpression, DW_OP_implicit_value) { 362 unsigned char bytes = 4; 363 364 EXPECT_THAT_EXPECTED( 365 Evaluate({DW_OP_implicit_value, bytes, 0x11, 0x22, 0x33, 0x44}), 366 llvm::HasValue(GetScalar(8 * bytes, 0x44332211, true))); 367 } 368 369 TEST(DWARFExpression, DW_OP_unknown) { 370 EXPECT_THAT_EXPECTED( 371 Evaluate({0xff}), 372 llvm::FailedWithMessage( 373 "Unhandled opcode DW_OP_unknown_ff in DWARFExpression")); 374 } 375 376 TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) { 377 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_deref}), llvm::Failed()); 378 379 struct MockProcess : Process { 380 MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp) 381 : Process(target_sp, listener_sp) {} 382 383 llvm::StringRef GetPluginName() override { return "mock process"; } 384 bool CanDebug(lldb::TargetSP target, 385 bool plugin_specified_by_name) override { 386 return false; 387 }; 388 Status DoDestroy() override { return {}; } 389 void RefreshStateAfterStop() override {} 390 bool DoUpdateThreadList(ThreadList &old_thread_list, 391 ThreadList &new_thread_list) override { 392 return false; 393 }; 394 size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, 395 Status &error) override { 396 for (size_t i = 0; i < size; ++i) 397 ((char *)buf)[i] = (vm_addr + i) & 0xff; 398 error.Clear(); 399 return size; 400 } 401 }; 402 403 // Set up a mock process. 404 ArchSpec arch("i386-pc-linux"); 405 Platform::SetHostPlatform( 406 platform_linux::PlatformLinux::CreateInstance(true, &arch)); 407 lldb::DebuggerSP debugger_sp = Debugger::CreateInstance(); 408 ASSERT_TRUE(debugger_sp); 409 lldb::TargetSP target_sp; 410 lldb::PlatformSP platform_sp; 411 debugger_sp->GetTargetList().CreateTarget( 412 *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp); 413 ASSERT_TRUE(target_sp); 414 ASSERT_TRUE(target_sp->GetArchitecture().IsValid()); 415 ASSERT_TRUE(platform_sp); 416 lldb::ListenerSP listener_sp(Listener::MakeListener("dummy")); 417 lldb::ProcessSP process_sp = 418 std::make_shared<MockProcess>(target_sp, listener_sp); 419 ASSERT_TRUE(process_sp); 420 421 ExecutionContext exe_ctx(process_sp); 422 // Implicit location: *0x4. 423 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value}, 424 {}, {}, &exe_ctx), 425 llvm::HasValue(GetScalar(32, 0x07060504, false))); 426 // Memory location: *(*0x4). 427 // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses. 428 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref}, {}, {}, &exe_ctx), 429 llvm::HasValue(Scalar(LLDB_INVALID_ADDRESS))); 430 // Memory location: *0x4. 431 // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses. 432 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4}, {}, {}, &exe_ctx), 433 llvm::HasValue(Scalar(4))); 434 // Implicit location: *0x4. 435 // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses. 436 EXPECT_THAT_EXPECTED( 437 Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value}, {}, {}, &exe_ctx), 438 llvm::HasValue(GetScalar(32, 0x07060504, false))); 439 } 440 441 TEST_F(DWARFExpressionMockProcessTest, WASM_DW_OP_addr) { 442 // Set up a wasm target 443 ArchSpec arch("wasm32-unknown-unknown-wasm"); 444 lldb::PlatformSP host_platform_sp = 445 platform_linux::PlatformLinux::CreateInstance(true, &arch); 446 ASSERT_TRUE(host_platform_sp); 447 Platform::SetHostPlatform(host_platform_sp); 448 lldb::DebuggerSP debugger_sp = Debugger::CreateInstance(); 449 ASSERT_TRUE(debugger_sp); 450 lldb::TargetSP target_sp; 451 lldb::PlatformSP platform_sp; 452 debugger_sp->GetTargetList().CreateTarget(*debugger_sp, "", arch, 453 lldb_private::eLoadDependentsNo, 454 platform_sp, target_sp); 455 456 ExecutionContext exe_ctx(target_sp, false); 457 // DW_OP_addr takes a single operand of address size width: 458 uint8_t expr[] = {DW_OP_addr, 0x40, 0x0, 0x0, 0x0}; 459 DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle, 460 /*addr_size*/ 4); 461 462 llvm::Expected<Value> result = DWARFExpression::Evaluate( 463 &exe_ctx, /*reg_ctx*/ nullptr, /*module_sp*/ {}, extractor, 464 /*unit*/ nullptr, lldb::eRegisterKindLLDB, 465 /*initial_value_ptr*/ nullptr, 466 /*object_address_ptr*/ nullptr); 467 468 ASSERT_THAT_EXPECTED(result, llvm::Succeeded()); 469 ASSERT_EQ(result->GetValueType(), Value::ValueType::LoadAddress); 470 } 471 472 TEST_F(DWARFExpressionMockProcessTest, WASM_DW_OP_addr_index) { 473 const char *yamldata = R"( 474 --- !ELF 475 FileHeader: 476 Class: ELFCLASS64 477 Data: ELFDATA2LSB 478 Type: ET_EXEC 479 Machine: EM_386 480 DWARF: 481 debug_abbrev: 482 - Table: 483 - Code: 0x00000001 484 Tag: DW_TAG_compile_unit 485 Children: DW_CHILDREN_no 486 Attributes: 487 - Attribute: DW_AT_addr_base 488 Form: DW_FORM_sec_offset 489 490 debug_info: 491 - Version: 5 492 AddrSize: 4 493 UnitType: DW_UT_compile 494 Entries: 495 - AbbrCode: 0x00000001 496 Values: 497 - Value: 0x8 # Offset of the first Address past the header 498 - AbbrCode: 0x0 499 500 debug_addr: 501 - Version: 5 502 AddressSize: 4 503 Entries: 504 - Address: 0x1234 505 - Address: 0x5678 506 )"; 507 508 // Can't use DWARFExpressionTester from above because subsystems overlap with 509 // the fixture. 510 SubsystemRAII<ObjectFileELF, SymbolFileDWARF> subsystems; 511 llvm::Expected<TestFile> file = TestFile::fromYaml(yamldata); 512 EXPECT_THAT_EXPECTED(file, llvm::Succeeded()); 513 auto module_sp = std::make_shared<Module>(file->moduleSpec()); 514 auto *dwarf_cu = llvm::cast<SymbolFileDWARF>(module_sp->GetSymbolFile()) 515 ->DebugInfo() 516 .GetUnitAtIndex(0); 517 ASSERT_TRUE(dwarf_cu); 518 dwarf_cu->ExtractDIEsIfNeeded(); 519 520 // Set up a wasm target 521 ArchSpec arch("wasm32-unknown-unknown-wasm"); 522 lldb::PlatformSP host_platform_sp = 523 platform_linux::PlatformLinux::CreateInstance(true, &arch); 524 ASSERT_TRUE(host_platform_sp); 525 Platform::SetHostPlatform(host_platform_sp); 526 lldb::DebuggerSP debugger_sp = Debugger::CreateInstance(); 527 ASSERT_TRUE(debugger_sp); 528 lldb::TargetSP target_sp; 529 lldb::PlatformSP platform_sp; 530 debugger_sp->GetTargetList().CreateTarget(*debugger_sp, "", arch, 531 lldb_private::eLoadDependentsNo, 532 platform_sp, target_sp); 533 534 ExecutionContext exe_ctx(target_sp, false); 535 536 auto evaluate = [&](DWARFExpression &expr) -> llvm::Expected<Value> { 537 DataExtractor extractor; 538 expr.GetExpressionData(extractor); 539 return DWARFExpression::Evaluate(&exe_ctx, /*reg_ctx*/ nullptr, 540 /*module_sp*/ {}, extractor, dwarf_cu, 541 lldb::eRegisterKindLLDB, 542 /*initial_value_ptr*/ nullptr, 543 /*object_address_ptr*/ nullptr); 544 }; 545 546 // DW_OP_addrx takes a single leb128 operand, the index in the addr table: 547 uint8_t expr_data[] = {DW_OP_addrx, 0x01}; 548 DataExtractor extractor(expr_data, sizeof(expr_data), lldb::eByteOrderLittle, 549 /*addr_size*/ 4); 550 DWARFExpression expr(extractor); 551 552 llvm::Expected<Value> result = evaluate(expr); 553 ASSERT_THAT_EXPECTED(result, llvm::Succeeded()); 554 ASSERT_EQ(result->GetValueType(), Value::ValueType::LoadAddress); 555 ASSERT_EQ(result->GetScalar().UInt(), 0x5678u); 556 557 ASSERT_TRUE(expr.Update_DW_OP_addr(dwarf_cu, 0xdeadbeef)); 558 result = evaluate(expr); 559 ASSERT_THAT_EXPECTED(result, llvm::Succeeded()); 560 ASSERT_EQ(result->GetValueType(), Value::ValueType::LoadAddress); 561 ASSERT_EQ(result->GetScalar().UInt(), 0xdeadbeefu); 562 } 563 564 class CustomSymbolFileDWARF : public SymbolFileDWARF { 565 static char ID; 566 567 public: 568 using SymbolFileDWARF::SymbolFileDWARF; 569 570 bool isA(const void *ClassID) const override { 571 return ClassID == &ID || SymbolFile::isA(ClassID); 572 } 573 static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } 574 575 static llvm::StringRef GetPluginNameStatic() { return "custom_dwarf"; } 576 577 static llvm::StringRef GetPluginDescriptionStatic() { 578 return "Symbol file reader with expression extensions."; 579 } 580 581 static void Initialize() { 582 PluginManager::RegisterPlugin(GetPluginNameStatic(), 583 GetPluginDescriptionStatic(), CreateInstance, 584 SymbolFileDWARF::DebuggerInitialize); 585 } 586 587 static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance); } 588 589 static lldb_private::SymbolFile * 590 CreateInstance(lldb::ObjectFileSP objfile_sp) { 591 return new CustomSymbolFileDWARF(std::move(objfile_sp), 592 /*dwo_section_list*/ nullptr); 593 } 594 595 lldb::offset_t 596 GetVendorDWARFOpcodeSize(const lldb_private::DataExtractor &data, 597 const lldb::offset_t data_offset, 598 const uint8_t op) const final { 599 auto offset = data_offset; 600 if (op != DW_OP_WASM_location) { 601 return LLDB_INVALID_OFFSET; 602 } 603 604 // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32 605 // Called with "arguments" 0x03 and 0x04 606 // Location type: 607 if (data.GetU8(&offset) != /* global */ 0x03) { 608 return LLDB_INVALID_OFFSET; 609 } 610 611 // Index 612 if (data.GetU32(&offset) != 0x04) { 613 return LLDB_INVALID_OFFSET; 614 } 615 616 // Report the skipped distance: 617 return offset - data_offset; 618 } 619 620 bool 621 ParseVendorDWARFOpcode(uint8_t op, const lldb_private::DataExtractor &opcodes, 622 lldb::offset_t &offset, 623 std::vector<lldb_private::Value> &stack) const final { 624 if (op != DW_OP_WASM_location) { 625 return false; 626 } 627 628 // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32 629 // Called with "arguments" 0x03 and 0x04 630 // Location type: 631 if (opcodes.GetU8(&offset) != /* global */ 0x03) { 632 return false; 633 } 634 635 // Index: 636 if (opcodes.GetU32(&offset) != 0x04) { 637 return false; 638 } 639 640 // Return some value: 641 stack.push_back({GetScalar(32, 42, false)}); 642 return true; 643 } 644 }; 645 646 char CustomSymbolFileDWARF::ID; 647 648 static auto testExpressionVendorExtensions(lldb::ModuleSP module_sp, 649 DWARFUnit &dwarf_unit) { 650 // Test that expression extensions can be evaluated, for example 651 // DW_OP_WASM_location which is not currently handled by DWARFExpression: 652 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_WASM_location, 0x03, // WASM_GLOBAL:0x03 653 0x04, 0x00, 0x00, // index:u32 654 0x00, DW_OP_stack_value}, 655 module_sp, &dwarf_unit), 656 llvm::HasValue(GetScalar(32, 42, false))); 657 658 // Test that searches for opcodes work in the presence of extensions: 659 uint8_t expr[] = {DW_OP_WASM_location, 0x03, 0x04, 0x00, 0x00, 0x00, 660 DW_OP_form_tls_address}; 661 DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle, 662 /*addr_size*/ 4); 663 DWARFExpression dwarf_expr(extractor); 664 ASSERT_TRUE(dwarf_expr.ContainsThreadLocalStorage(&dwarf_unit)); 665 } 666 667 TEST(DWARFExpression, Extensions) { 668 const char *yamldata = R"( 669 --- !ELF 670 FileHeader: 671 Class: ELFCLASS64 672 Data: ELFDATA2LSB 673 Type: ET_EXEC 674 Machine: EM_386 675 DWARF: 676 debug_abbrev: 677 - Table: 678 - Code: 0x00000001 679 Tag: DW_TAG_compile_unit 680 Children: DW_CHILDREN_no 681 debug_info: 682 - Version: 4 683 AddrSize: 4 684 Entries: 685 - AbbrCode: 0x1 686 - AbbrCode: 0x0 687 )"; 688 689 SubsystemRAII<FileSystem, HostInfo, TypeSystemClang, ObjectFileELF, 690 CustomSymbolFileDWARF> 691 subsystems; 692 693 llvm::Expected<TestFile> file = TestFile::fromYaml(yamldata); 694 EXPECT_THAT_EXPECTED(file, llvm::Succeeded()); 695 696 auto module_sp = std::make_shared<Module>(file->moduleSpec()); 697 auto &symfile = 698 *llvm::cast<CustomSymbolFileDWARF>(module_sp->GetSymbolFile()); 699 auto *dwarf_unit = symfile.DebugInfo().GetUnitAtIndex(0); 700 701 testExpressionVendorExtensions(module_sp, *dwarf_unit); 702 } 703 704 TEST(DWARFExpression, ExtensionsDWO) { 705 const char *skeleton_yamldata = R"( 706 --- !ELF 707 FileHeader: 708 Class: ELFCLASS64 709 Data: ELFDATA2LSB 710 Type: ET_EXEC 711 Machine: EM_386 712 DWARF: 713 debug_abbrev: 714 - Table: 715 - Code: 0x00000001 716 Tag: DW_TAG_skeleton_unit 717 Children: DW_CHILDREN_no 718 Attributes: 719 - Attribute: DW_AT_dwo_name 720 Form: DW_FORM_string 721 - Attribute: DW_AT_dwo_id 722 Form: DW_FORM_data4 723 debug_info: 724 - Version: 4 725 AddrSize: 4 726 Entries: 727 - AbbrCode: 0x1 728 Values: 729 - CStr: "dwo_unit" 730 - Value: 0x01020304 731 - AbbrCode: 0x0 732 )"; 733 734 // .dwo sections aren't currently supported by dwarfyaml. The dwo_yamldata 735 // contents where generated by roundtripping the following yaml through 736 // yaml2obj | obj2yaml and renaming the sections. This works because the 737 // structure of the .dwo and non-.dwo sections is identical. 738 // 739 // --- !ELF 740 // FileHeader: 741 // Class: ELFCLASS64 742 // Data: ELFDATA2LSB 743 // Type: ET_EXEC 744 // Machine: EM_386 745 // DWARF: 746 // debug_abbrev: #.dwo 747 // - Table: 748 // - Code: 0x00000001 749 // Tag: DW_TAG_compile_unit 750 // Children: DW_CHILDREN_no 751 // Attributes: 752 // - Attribute: DW_AT_dwo_id 753 // Form: DW_FORM_data4 754 // debug_info: #.dwo 755 // - Version: 4 756 // AddrSize: 4 757 // Entries: 758 // - AbbrCode: 0x1 759 // Values: 760 // - Value: 0x0120304 761 // - AbbrCode: 0x0 762 const char *dwo_yamldata = R"( 763 --- !ELF 764 FileHeader: 765 Class: ELFCLASS64 766 Data: ELFDATA2LSB 767 Type: ET_EXEC 768 Machine: EM_386 769 Sections: 770 - Name: .debug_abbrev.dwo 771 Type: SHT_PROGBITS 772 AddressAlign: 0x1 773 Content: '0111007506000000' 774 - Name: .debug_info.dwo 775 Type: SHT_PROGBITS 776 AddressAlign: 0x1 777 Content: 0D00000004000000000004010403020100 778 )"; 779 780 SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, CustomSymbolFileDWARF> 781 subsystems; 782 783 llvm::Expected<TestFile> skeleton_file = 784 TestFile::fromYaml(skeleton_yamldata); 785 EXPECT_THAT_EXPECTED(skeleton_file, llvm::Succeeded()); 786 llvm::Expected<TestFile> dwo_file = TestFile::fromYaml(dwo_yamldata); 787 EXPECT_THAT_EXPECTED(dwo_file, llvm::Succeeded()); 788 789 auto skeleton_module_sp = 790 std::make_shared<Module>(skeleton_file->moduleSpec()); 791 auto &skeleton_symfile = 792 *llvm::cast<CustomSymbolFileDWARF>(skeleton_module_sp->GetSymbolFile()); 793 794 auto dwo_module_sp = std::make_shared<Module>(dwo_file->moduleSpec()); 795 SymbolFileDWARFDwo dwo_symfile( 796 skeleton_symfile, dwo_module_sp->GetObjectFile()->shared_from_this(), 797 0x0120304); 798 auto *dwo_dwarf_unit = dwo_symfile.DebugInfo().GetUnitAtIndex(0); 799 800 testExpressionVendorExtensions(dwo_module_sp, *dwo_dwarf_unit); 801 } 802 803 TEST_F(DWARFExpressionMockProcessTest, DW_OP_piece_file_addr) { 804 using ::testing::ByMove; 805 using ::testing::ElementsAre; 806 using ::testing::Return; 807 808 // Set up a mock process. 809 ArchSpec arch("i386-pc-linux"); 810 Platform::SetHostPlatform( 811 platform_linux::PlatformLinux::CreateInstance(true, &arch)); 812 lldb::DebuggerSP debugger_sp = Debugger::CreateInstance(); 813 ASSERT_TRUE(debugger_sp); 814 lldb::PlatformSP platform_sp; 815 auto target_sp = 816 std::make_shared<MockTarget>(*debugger_sp, arch, platform_sp); 817 ASSERT_TRUE(target_sp); 818 ASSERT_TRUE(target_sp->GetArchitecture().IsValid()); 819 820 EXPECT_CALL(*target_sp, ReadMemory(0x40, 1)) 821 .WillOnce(Return(ByMove(std::vector<uint8_t>{0x11}))); 822 EXPECT_CALL(*target_sp, ReadMemory(0x50, 1)) 823 .WillOnce(Return(ByMove(std::vector<uint8_t>{0x22}))); 824 825 ExecutionContext exe_ctx(static_cast<lldb::TargetSP>(target_sp), false); 826 827 uint8_t expr[] = {DW_OP_addr, 0x40, 0x0, 0x0, 0x0, DW_OP_piece, 1, 828 DW_OP_addr, 0x50, 0x0, 0x0, 0x0, DW_OP_piece, 1}; 829 DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle, 830 /*addr_size*/ 4); 831 llvm::Expected<Value> result = DWARFExpression::Evaluate( 832 &exe_ctx, /*reg_ctx*/ nullptr, /*module_sp*/ {}, extractor, 833 /*unit*/ nullptr, lldb::eRegisterKindLLDB, 834 /*initial_value_ptr*/ nullptr, 835 /*object_address_ptr*/ nullptr); 836 837 ASSERT_THAT_EXPECTED(result, llvm::Succeeded()); 838 ASSERT_EQ(result->GetValueType(), Value::ValueType::HostAddress); 839 ASSERT_THAT(result->GetBuffer().GetData(), ElementsAre(0x11, 0x22)); 840 } 841