[libc] Switch to using the generic `<gpuintrin.h>` implementations (#121810)
[llvm-project.git] / lldb / unittests / Expression / DWARFExpressionTest.cpp
blobfdc9bfae1876c518182f2c0ba933b31e3f551d4d
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 //===----------------------------------------------------------------------===//
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"
26 using namespace lldb_private;
27 using namespace lldb_private::dwarf;
28 using namespace lldb_private::plugin::dwarf;
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);
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();
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));
59 [[fallthrough]];
60 default:
61 break;
63 return llvm::createStringError("unsupported value type");
66 class DWARFExpressionTester : public YAMLModuleTester {
67 public:
68 DWARFExpressionTester(llvm::StringRef yaml_data, size_t cu_index) :
69 YAMLModuleTester(yaml_data, cu_index) {}
71 using YAMLModuleTester::YAMLModuleTester;
72 llvm::Expected<Scalar> Eval(llvm::ArrayRef<uint8_t> expr) {
73 return ::Evaluate(expr, m_module_sp, m_dwarf_unit);
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;
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();
92 void TearDown() override {
93 platform_linux::PlatformLinux::Terminate();
94 HostInfo::Terminate();
95 FileSystem::Terminate();
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) {}
108 MOCK_METHOD2(ReadMemory,
109 llvm::Expected<std::vector<uint8_t>>(lldb::addr_t addr,
110 size_t size));
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;
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;
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());
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));
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));
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));
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));
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
182 // clang-format on
183 llvm::HasValue(0x42));
185 EXPECT_THAT_ERROR(Evaluate({DW_OP_bra, 0x01, 0x00}).takeError(),
186 llvm::Failed());
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
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;
273 DWARFExpressionTester t(yamldata, /*cu_index=*/1);
274 ASSERT_TRUE((bool)t.GetDwarfUnit());
276 // Constant is given as little-endian.
277 bool is_signed = true;
278 bool not_signed = false;
281 // Positive tests.
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)));
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)));
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)));
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)));
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)));
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)));
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)));
326 // Errors.
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());
335 // No DIE.
336 EXPECT_THAT_ERROR(
337 t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x01}).takeError(),
338 llvm::Failed());
340 // Unsupported.
341 EXPECT_THAT_ERROR(
342 t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x1d}).takeError(),
343 llvm::Failed());
346 TEST(DWARFExpression, DW_OP_stack_value) {
347 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed());
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)));
361 TEST(DWARFExpression, DW_OP_implicit_value) {
362 unsigned char bytes = 4;
364 EXPECT_THAT_EXPECTED(
365 Evaluate({DW_OP_implicit_value, bytes, 0x11, 0x22, 0x33, 0x44}),
366 llvm::HasValue(GetScalar(8 * bytes, 0x44332211, true)));
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"));
376 TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) {
377 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_deref}), llvm::Failed());
379 struct MockProcess : Process {
380 MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
381 : Process(target_sp, listener_sp) {}
383 llvm::StringRef GetPluginName() override { return "mock process"; }
384 bool CanDebug(lldb::TargetSP target,
385 bool plugin_specified_by_name) override {
386 return false;
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;
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;
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);
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)));
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);
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);
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);
468 ASSERT_THAT_EXPECTED(result, llvm::Succeeded());
469 ASSERT_EQ(result->GetValueType(), Value::ValueType::LoadAddress);
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
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
500 debug_addr:
501 - Version: 5
502 AddressSize: 4
503 Entries:
504 - Address: 0x1234
505 - Address: 0x5678
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();
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);
534 ExecutionContext exe_ctx(target_sp, false);
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);
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);
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);
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);
564 class CustomSymbolFileDWARF : public SymbolFileDWARF {
565 static char ID;
567 public:
568 using SymbolFileDWARF::SymbolFileDWARF;
570 bool isA(const void *ClassID) const override {
571 return ClassID == &ID || SymbolFile::isA(ClassID);
573 static bool classof(const SymbolFile *obj) { return obj->isA(&ID); }
575 static llvm::StringRef GetPluginNameStatic() { return "custom_dwarf"; }
577 static llvm::StringRef GetPluginDescriptionStatic() {
578 return "Symbol file reader with expression extensions.";
581 static void Initialize() {
582 PluginManager::RegisterPlugin(GetPluginNameStatic(),
583 GetPluginDescriptionStatic(), CreateInstance,
584 SymbolFileDWARF::DebuggerInitialize);
587 static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance); }
589 static lldb_private::SymbolFile *
590 CreateInstance(lldb::ObjectFileSP objfile_sp) {
591 return new CustomSymbolFileDWARF(std::move(objfile_sp),
592 /*dwo_section_list*/ nullptr);
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;
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;
611 // Index
612 if (data.GetU32(&offset) != 0x04) {
613 return LLDB_INVALID_OFFSET;
616 // Report the skipped distance:
617 return offset - data_offset;
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;
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;
635 // Index:
636 if (opcodes.GetU32(&offset) != 0x04) {
637 return false;
640 // Return some value:
641 stack.push_back({GetScalar(32, 42, false)});
642 return true;
646 char CustomSymbolFileDWARF::ID;
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)));
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));
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
689 SubsystemRAII<FileSystem, HostInfo, TypeSystemClang, ObjectFileELF,
690 CustomSymbolFileDWARF>
691 subsystems;
693 llvm::Expected<TestFile> file = TestFile::fromYaml(yamldata);
694 EXPECT_THAT_EXPECTED(file, llvm::Succeeded());
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);
701 testExpressionVendorExtensions(module_sp, *dwarf_unit);
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
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.
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
780 SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, CustomSymbolFileDWARF>
781 subsystems;
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());
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());
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);
800 testExpressionVendorExtensions(dwo_module_sp, *dwo_dwarf_unit);
803 TEST_F(DWARFExpressionMockProcessTest, DW_OP_piece_file_addr) {
804 using ::testing::ByMove;
805 using ::testing::ElementsAre;
806 using ::testing::Return;
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());
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})));
825 ExecutionContext exe_ctx(static_cast<lldb::TargetSP>(target_sp), false);
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);
837 ASSERT_THAT_EXPECTED(result, llvm::Succeeded());
838 ASSERT_EQ(result->GetValueType(), Value::ValueType::HostAddress);
839 ASSERT_THAT(result->GetBuffer().GetData(), ElementsAre(0x11, 0x22));