1 //===-- DWARFExpressionTest.cpp -------------------------------------------===//
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
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
,
38 if (!DWARFExpression::Evaluate(exe_ctx
, /*reg_ctx*/ nullptr, module_sp
,
39 extractor
, unit
, lldb::eRegisterKindLLDB
,
40 /*initial_value_ptr*/ nullptr,
41 /*object_address_ptr*/ nullptr, result
,
43 return status
.ToError();
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) {
55 memcpy(&val
, buf
.GetBytes(), buf
.GetByteSize());
56 return Scalar(llvm::APInt(buf
.GetByteSize()*8, val
, false));
61 return status
.ToError();
65 class DWARFExpressionTester
: public YAMLModuleTester
{
67 DWARFExpressionTester(llvm::StringRef yaml_data
, size_t cu_index
) :
68 YAMLModuleTester(yaml_data
, cu_index
) {}
70 using YAMLModuleTester::YAMLModuleTester
;
71 llvm::Expected
<Scalar
> Eval(llvm::ArrayRef
<uint8_t> expr
) {
72 return ::Evaluate(expr
, m_module_sp
, m_dwarf_unit
);
76 /// Unfortunately Scalar's operator==() is really picky.
77 static Scalar
GetScalar(unsigned bits
, uint64_t value
, bool sign
) {
79 scalar
.TruncOrExtendTo(bits
, sign
);
83 /// This is needed for the tests that use a mock process.
84 class DWARFExpressionMockProcessTest
: public ::testing::Test
{
86 void SetUp() override
{
87 FileSystem::Initialize();
88 HostInfo::Initialize();
89 platform_linux::PlatformLinux::Initialize();
91 void TearDown() override
{
92 platform_linux::PlatformLinux::Terminate();
93 HostInfo::Terminate();
94 FileSystem::Terminate();
98 TEST(DWARFExpression
, DW_OP_pick
) {
99 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1
, DW_OP_lit0
, DW_OP_pick
, 0}),
101 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1
, DW_OP_lit0
, DW_OP_pick
, 1}),
103 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1
, DW_OP_lit0
, DW_OP_pick
, 2}),
107 TEST(DWARFExpression
, DW_OP_const
) {
108 // Extend to address size.
109 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1u
, 0x88}), llvm::HasValue(0x88));
110 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1s
, 0x88}),
111 llvm::HasValue(0xffffff88));
112 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u
, 0x47, 0x88}),
113 llvm::HasValue(0x8847));
114 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2s
, 0x47, 0x88}),
115 llvm::HasValue(0xffff8847));
116 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4u
, 0x44, 0x42, 0x47, 0x88}),
117 llvm::HasValue(0x88474244));
118 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4s
, 0x44, 0x42, 0x47, 0x88}),
119 llvm::HasValue(0x88474244));
121 // Truncate to address size.
122 EXPECT_THAT_EXPECTED(
123 Evaluate({DW_OP_const8u
, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}),
124 llvm::HasValue(0x33221100));
125 EXPECT_THAT_EXPECTED(
126 Evaluate({DW_OP_const8s
, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}),
127 llvm::HasValue(0x33221100));
129 // Don't truncate to address size for compatibility with clang (pr48087).
130 EXPECT_THAT_EXPECTED(
131 Evaluate({DW_OP_constu
, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}),
132 llvm::HasValue(0x01010101010101));
133 EXPECT_THAT_EXPECTED(
134 Evaluate({DW_OP_consts
, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}),
135 llvm::HasValue(0xffff010101010101));
138 TEST(DWARFExpression
, DW_OP_skip
) {
139 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1u
, 0x42, DW_OP_skip
, 0x02, 0x00,
140 DW_OP_const1u
, 0xff}),
141 llvm::HasValue(0x42));
144 TEST(DWARFExpression
, DW_OP_bra
) {
145 EXPECT_THAT_EXPECTED(
148 DW_OP_const1u
, 0x42, // push 0x42
149 DW_OP_const1u
, 0x1, // push 0x1
150 DW_OP_bra
, 0x02, 0x00, // if 0x1 > 0, then skip 0x0002 opcodes
151 DW_OP_const1u
, 0xff, // push 0xff
154 llvm::HasValue(0x42));
157 TEST(DWARFExpression
, DW_OP_convert
) {
158 /// Auxiliary debug info.
159 const char *yamldata
= R
"(
170 Tag: DW_TAG_compile_unit
171 Children: DW_CHILDREN_yes
173 - Attribute: DW_AT_language
176 Tag: DW_TAG_base_type
177 Children: DW_CHILDREN_no
179 - Attribute: DW_AT_encoding
181 - Attribute: DW_AT_byte_size
189 - AbbrCode: 0x00000001
191 - Value: 0x000000000000000C
192 - AbbrCode: 0x00000000
198 - AbbrCode: 0x00000001
200 - Value: 0x000000000000000C
202 - AbbrCode: 0x00000002
204 - Value: 0x0000000000000007 # DW_ATE_unsigned
205 - Value: 0x0000000000000004
207 - AbbrCode: 0x00000002
209 - Value: 0x0000000000000007 # DW_ATE_unsigned
210 - Value: 0x0000000000000008
212 - AbbrCode: 0x00000002
214 - Value: 0x0000000000000005 # DW_ATE_signed
215 - Value: 0x0000000000000008
217 - AbbrCode: 0x00000002
219 - Value: 0x0000000000000008 # DW_ATE_unsigned_char
220 - Value: 0x0000000000000001
222 - AbbrCode: 0x00000002
224 - Value: 0x0000000000000006 # DW_ATE_signed_char
225 - Value: 0x0000000000000001
227 - AbbrCode: 0x00000002
229 - Value: 0x000000000000000b # DW_ATE_numeric_string
230 - Value: 0x0000000000000001
231 - AbbrCode: 0x00000000
234 // Compile unit relative offsets to each DW_TAG_base_type
235 uint8_t offs_uint32_t
= 0x0000000e;
236 uint8_t offs_uint64_t
= 0x00000011;
237 uint8_t offs_sint64_t
= 0x00000014;
238 uint8_t offs_uchar
= 0x00000017;
239 uint8_t offs_schar
= 0x0000001a;
241 DWARFExpressionTester
t(yamldata
, /*cu_index=*/1);
242 ASSERT_TRUE((bool)t
.GetDwarfUnit());
244 // Constant is given as little-endian.
245 bool is_signed
= true;
246 bool not_signed
= false;
253 EXPECT_THAT_EXPECTED(
254 t
.Eval({DW_OP_const4u
, 0x11, 0x22, 0x33, 0x44, //
255 DW_OP_convert
, offs_uint32_t
, DW_OP_stack_value
}),
256 llvm::HasValue(GetScalar(64, 0x44332211, not_signed
)));
258 // Zero-extend to 64 bits.
259 EXPECT_THAT_EXPECTED(
260 t
.Eval({DW_OP_const4u
, 0x11, 0x22, 0x33, 0x44, //
261 DW_OP_convert
, offs_uint64_t
, DW_OP_stack_value
}),
262 llvm::HasValue(GetScalar(64, 0x44332211, not_signed
)));
264 // Sign-extend to 64 bits.
265 EXPECT_THAT_EXPECTED(
266 t
.Eval({DW_OP_const4s
, 0xcc, 0xdd, 0xee, 0xff, //
267 DW_OP_convert
, offs_sint64_t
, DW_OP_stack_value
}),
268 llvm::HasValue(GetScalar(64, 0xffffffffffeeddcc, is_signed
)));
270 // Sign-extend, then truncate.
271 EXPECT_THAT_EXPECTED(
272 t
.Eval({DW_OP_const4s
, 0xcc, 0xdd, 0xee, 0xff, //
273 DW_OP_convert
, offs_sint64_t
, //
274 DW_OP_convert
, offs_uint32_t
, DW_OP_stack_value
}),
275 llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed
)));
277 // Truncate to default unspecified (pointer-sized) type.
278 EXPECT_THAT_EXPECTED(t
.Eval({DW_OP_const4s
, 0xcc, 0xdd, 0xee, 0xff, //
279 DW_OP_convert
, offs_sint64_t
, //
280 DW_OP_convert
, 0x00, DW_OP_stack_value
}),
281 llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed
)));
283 // Truncate to 8 bits.
284 EXPECT_THAT_EXPECTED(t
.Eval({DW_OP_const4s
, 'A', 'B', 'C', 'D', DW_OP_convert
,
285 offs_uchar
, DW_OP_stack_value
}),
286 llvm::HasValue(GetScalar(8, 'A', not_signed
)));
288 // Also truncate to 8 bits.
289 EXPECT_THAT_EXPECTED(t
.Eval({DW_OP_const4s
, 'A', 'B', 'C', 'D', DW_OP_convert
,
290 offs_schar
, DW_OP_stack_value
}),
291 llvm::HasValue(GetScalar(8, 'A', is_signed
)));
298 EXPECT_THAT_ERROR(Evaluate({DW_OP_const1s
, 'X', DW_OP_convert
, 0x00}, nullptr,
305 t
.Eval({DW_OP_const1s
, 'X', DW_OP_convert
, 0x01}).takeError(),
310 t
.Eval({DW_OP_const1s
, 'X', DW_OP_convert
, 0x1d}).takeError(),
314 TEST(DWARFExpression
, DW_OP_stack_value
) {
315 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value
}), llvm::Failed());
318 TEST(DWARFExpression
, DW_OP_piece
) {
319 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u
, 0x11, 0x22, DW_OP_piece
, 2,
320 DW_OP_const2u
, 0x33, 0x44, DW_OP_piece
, 2}),
321 llvm::HasValue(GetScalar(32, 0x44332211, true)));
322 EXPECT_THAT_EXPECTED(
323 Evaluate({DW_OP_piece
, 1, DW_OP_const1u
, 0xff, DW_OP_piece
, 1}),
324 // Note that the "00" should really be "undef", but we can't
325 // represent that yet.
326 llvm::HasValue(GetScalar(16, 0xff00, true)));
329 TEST(DWARFExpression
, DW_OP_implicit_value
) {
330 unsigned char bytes
= 4;
332 EXPECT_THAT_EXPECTED(
333 Evaluate({DW_OP_implicit_value
, bytes
, 0x11, 0x22, 0x33, 0x44}),
334 llvm::HasValue(GetScalar(8 * bytes
, 0x44332211, true)));
337 TEST(DWARFExpression
, DW_OP_unknown
) {
338 EXPECT_THAT_EXPECTED(
340 llvm::FailedWithMessage(
341 "Unhandled opcode DW_OP_unknown_ff in DWARFExpression"));
344 TEST_F(DWARFExpressionMockProcessTest
, DW_OP_deref
) {
345 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0
, DW_OP_deref
}), llvm::Failed());
347 struct MockProcess
: Process
{
348 MockProcess(lldb::TargetSP target_sp
, lldb::ListenerSP listener_sp
)
349 : Process(target_sp
, listener_sp
) {}
351 llvm::StringRef
GetPluginName() override
{ return "mock process"; }
352 bool CanDebug(lldb::TargetSP target
,
353 bool plugin_specified_by_name
) override
{
356 Status
DoDestroy() override
{ return {}; }
357 void RefreshStateAfterStop() override
{}
358 bool DoUpdateThreadList(ThreadList
&old_thread_list
,
359 ThreadList
&new_thread_list
) override
{
362 size_t DoReadMemory(lldb::addr_t vm_addr
, void *buf
, size_t size
,
363 Status
&error
) override
{
364 for (size_t i
= 0; i
< size
; ++i
)
365 ((char *)buf
)[i
] = (vm_addr
+ i
) & 0xff;
371 // Set up a mock process.
372 ArchSpec
arch("i386-pc-linux");
373 Platform::SetHostPlatform(
374 platform_linux::PlatformLinux::CreateInstance(true, &arch
));
375 lldb::DebuggerSP debugger_sp
= Debugger::CreateInstance();
376 ASSERT_TRUE(debugger_sp
);
377 lldb::TargetSP target_sp
;
378 lldb::PlatformSP platform_sp
;
379 debugger_sp
->GetTargetList().CreateTarget(
380 *debugger_sp
, "", arch
, eLoadDependentsNo
, platform_sp
, target_sp
);
381 ASSERT_TRUE(target_sp
);
382 ASSERT_TRUE(target_sp
->GetArchitecture().IsValid());
383 ASSERT_TRUE(platform_sp
);
384 lldb::ListenerSP
listener_sp(Listener::MakeListener("dummy"));
385 lldb::ProcessSP process_sp
=
386 std::make_shared
<MockProcess
>(target_sp
, listener_sp
);
387 ASSERT_TRUE(process_sp
);
389 ExecutionContext
exe_ctx(process_sp
);
390 // Implicit location: *0x4.
391 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4
, DW_OP_deref
, DW_OP_stack_value
},
393 llvm::HasValue(GetScalar(32, 0x07060504, false)));
394 // Memory location: *(*0x4).
395 // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
396 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4
, DW_OP_deref
}, {}, {}, &exe_ctx
),
397 llvm::HasValue(Scalar(LLDB_INVALID_ADDRESS
)));
398 // Memory location: *0x4.
399 // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
400 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4
}, {}, {}, &exe_ctx
),
401 llvm::HasValue(Scalar(4)));
402 // Implicit location: *0x4.
403 // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
404 EXPECT_THAT_EXPECTED(
405 Evaluate({DW_OP_lit4
, DW_OP_deref
, DW_OP_stack_value
}, {}, {}, &exe_ctx
),
406 llvm::HasValue(GetScalar(32, 0x07060504, false)));
409 TEST_F(DWARFExpressionMockProcessTest
, WASM_DW_OP_addr
) {
410 // Set up a wasm target
411 ArchSpec
arch("wasm32-unknown-unknown-wasm");
412 lldb::PlatformSP host_platform_sp
=
413 platform_linux::PlatformLinux::CreateInstance(true, &arch
);
414 ASSERT_TRUE(host_platform_sp
);
415 Platform::SetHostPlatform(host_platform_sp
);
416 lldb::DebuggerSP debugger_sp
= Debugger::CreateInstance();
417 ASSERT_TRUE(debugger_sp
);
418 lldb::TargetSP target_sp
;
419 lldb::PlatformSP platform_sp
;
420 debugger_sp
->GetTargetList().CreateTarget(*debugger_sp
, "", arch
,
421 lldb_private::eLoadDependentsNo
,
422 platform_sp
, target_sp
);
424 ExecutionContext
exe_ctx(target_sp
, false);
425 // DW_OP_addr takes a single operand of address size width:
426 uint8_t expr
[] = {DW_OP_addr
, 0x40, 0x0, 0x0, 0x0};
427 DataExtractor
extractor(expr
, sizeof(expr
), lldb::eByteOrderLittle
,
431 ASSERT_TRUE(DWARFExpression::Evaluate(
432 &exe_ctx
, /*reg_ctx*/ nullptr, /*module_sp*/ {}, extractor
,
433 /*unit*/ nullptr, lldb::eRegisterKindLLDB
,
434 /*initial_value_ptr*/ nullptr,
435 /*object_address_ptr*/ nullptr, result
, &status
))
438 ASSERT_EQ(result
.GetValueType(), Value::ValueType::LoadAddress
);
441 TEST_F(DWARFExpressionMockProcessTest
, WASM_DW_OP_addr_index
) {
442 const char *yamldata
= R
"(
453 Tag: DW_TAG_compile_unit
454 Children: DW_CHILDREN_no
456 - Attribute: DW_AT_addr_base
457 Form: DW_FORM_sec_offset
462 UnitType: DW_UT_compile
464 - AbbrCode: 0x00000001
466 - Value: 0x8 # Offset of the first Address past the header
477 // Can't use DWARFExpressionTester from above because subsystems overlap with
479 SubsystemRAII
<ObjectFileELF
, SymbolFileDWARF
> subsystems
;
480 llvm::Expected
<TestFile
> file
= TestFile::fromYaml(yamldata
);
481 EXPECT_THAT_EXPECTED(file
, llvm::Succeeded());
482 auto module_sp
= std::make_shared
<Module
>(file
->moduleSpec());
483 auto *dwarf_cu
= llvm::cast
<SymbolFileDWARF
>(module_sp
->GetSymbolFile())
486 ASSERT_TRUE(dwarf_cu
);
487 dwarf_cu
->ExtractDIEsIfNeeded();
489 // Set up a wasm target
490 ArchSpec
arch("wasm32-unknown-unknown-wasm");
491 lldb::PlatformSP host_platform_sp
=
492 platform_linux::PlatformLinux::CreateInstance(true, &arch
);
493 ASSERT_TRUE(host_platform_sp
);
494 Platform::SetHostPlatform(host_platform_sp
);
495 lldb::DebuggerSP debugger_sp
= Debugger::CreateInstance();
496 ASSERT_TRUE(debugger_sp
);
497 lldb::TargetSP target_sp
;
498 lldb::PlatformSP platform_sp
;
499 debugger_sp
->GetTargetList().CreateTarget(*debugger_sp
, "", arch
,
500 lldb_private::eLoadDependentsNo
,
501 platform_sp
, target_sp
);
503 ExecutionContext
exe_ctx(target_sp
, false);
505 auto evaluate
= [&](DWARFExpression
&expr
, Status
&status
, Value
&result
) {
506 DataExtractor extractor
;
507 expr
.GetExpressionData(extractor
);
508 return DWARFExpression::Evaluate(
509 &exe_ctx
, /*reg_ctx*/ nullptr, /*module_sp*/ {}, extractor
, dwarf_cu
,
510 lldb::eRegisterKindLLDB
,
511 /*initial_value_ptr*/ nullptr,
512 /*object_address_ptr*/ nullptr, result
, &status
);
515 // DW_OP_addrx takes a single leb128 operand, the index in the addr table:
516 uint8_t expr_data
[] = {DW_OP_addrx
, 0x01};
517 DataExtractor
extractor(expr_data
, sizeof(expr_data
), lldb::eByteOrderLittle
,
519 DWARFExpression
expr(extractor
);
523 ASSERT_TRUE(evaluate(expr
, status
, result
)) << status
.ToError();
524 ASSERT_EQ(result
.GetValueType(), Value::ValueType::LoadAddress
);
525 ASSERT_EQ(result
.GetScalar().UInt(), 0x5678u
);
527 ASSERT_TRUE(expr
.Update_DW_OP_addr(dwarf_cu
, 0xdeadbeef));
528 ASSERT_TRUE(evaluate(expr
, status
, result
)) << status
.ToError();
529 ASSERT_EQ(result
.GetValueType(), Value::ValueType::LoadAddress
);
530 ASSERT_EQ(result
.GetScalar().UInt(), 0xdeadbeefu
);
533 class CustomSymbolFileDWARF
: public SymbolFileDWARF
{
537 using SymbolFileDWARF::SymbolFileDWARF
;
539 bool isA(const void *ClassID
) const override
{
540 return ClassID
== &ID
|| SymbolFile::isA(ClassID
);
542 static bool classof(const SymbolFile
*obj
) { return obj
->isA(&ID
); }
544 static llvm::StringRef
GetPluginNameStatic() { return "custom_dwarf"; }
546 static llvm::StringRef
GetPluginDescriptionStatic() {
547 return "Symbol file reader with expression extensions.";
550 static void Initialize() {
551 PluginManager::RegisterPlugin(GetPluginNameStatic(),
552 GetPluginDescriptionStatic(), CreateInstance
,
553 SymbolFileDWARF::DebuggerInitialize
);
556 static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance
); }
558 static lldb_private::SymbolFile
*
559 CreateInstance(lldb::ObjectFileSP objfile_sp
) {
560 return new CustomSymbolFileDWARF(std::move(objfile_sp
),
561 /*dwo_section_list*/ nullptr);
565 GetVendorDWARFOpcodeSize(const lldb_private::DataExtractor
&data
,
566 const lldb::offset_t data_offset
,
567 const uint8_t op
) const final
{
568 auto offset
= data_offset
;
569 if (op
!= DW_OP_WASM_location
) {
570 return LLDB_INVALID_OFFSET
;
573 // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32
574 // Called with "arguments" 0x03 and 0x04
576 if (data
.GetU8(&offset
) != /* global */ 0x03) {
577 return LLDB_INVALID_OFFSET
;
581 if (data
.GetU32(&offset
) != 0x04) {
582 return LLDB_INVALID_OFFSET
;
585 // Report the skipped distance:
586 return offset
- data_offset
;
590 ParseVendorDWARFOpcode(uint8_t op
, const lldb_private::DataExtractor
&opcodes
,
591 lldb::offset_t
&offset
,
592 std::vector
<lldb_private::Value
> &stack
) const final
{
593 if (op
!= DW_OP_WASM_location
) {
597 // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32
598 // Called with "arguments" 0x03 and 0x04
600 if (opcodes
.GetU8(&offset
) != /* global */ 0x03) {
605 if (opcodes
.GetU32(&offset
) != 0x04) {
609 // Return some value:
610 stack
.push_back({GetScalar(32, 42, false)});
615 char CustomSymbolFileDWARF::ID
;
617 static auto testExpressionVendorExtensions(lldb::ModuleSP module_sp
,
618 DWARFUnit
&dwarf_unit
) {
619 // Test that expression extensions can be evaluated, for example
620 // DW_OP_WASM_location which is not currently handled by DWARFExpression:
621 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_WASM_location
, 0x03, // WASM_GLOBAL:0x03
622 0x04, 0x00, 0x00, // index:u32
623 0x00, DW_OP_stack_value
},
624 module_sp
, &dwarf_unit
),
625 llvm::HasValue(GetScalar(32, 42, false)));
627 // Test that searches for opcodes work in the presence of extensions:
628 uint8_t expr
[] = {DW_OP_WASM_location
, 0x03, 0x04, 0x00, 0x00, 0x00,
629 DW_OP_form_tls_address
};
630 DataExtractor
extractor(expr
, sizeof(expr
), lldb::eByteOrderLittle
,
632 DWARFExpression
dwarf_expr(extractor
);
633 ASSERT_TRUE(dwarf_expr
.ContainsThreadLocalStorage(&dwarf_unit
));
636 TEST(DWARFExpression
, Extensions
) {
637 const char *yamldata
= R
"(
648 Tag: DW_TAG_compile_unit
649 Children: DW_CHILDREN_no
658 SubsystemRAII
<FileSystem
, HostInfo
, TypeSystemClang
, ObjectFileELF
,
659 CustomSymbolFileDWARF
>
662 llvm::Expected
<TestFile
> file
= TestFile::fromYaml(yamldata
);
663 EXPECT_THAT_EXPECTED(file
, llvm::Succeeded());
665 auto module_sp
= std::make_shared
<Module
>(file
->moduleSpec());
667 *llvm::cast
<CustomSymbolFileDWARF
>(module_sp
->GetSymbolFile());
668 auto *dwarf_unit
= symfile
.DebugInfo().GetUnitAtIndex(0);
670 testExpressionVendorExtensions(module_sp
, *dwarf_unit
);
673 TEST(DWARFExpression
, ExtensionsDWO
) {
674 const char *skeleton_yamldata
= R
"(
685 Tag: DW_TAG_skeleton_unit
686 Children: DW_CHILDREN_no
688 - Attribute: DW_AT_dwo_name
690 - Attribute: DW_AT_dwo_id
703 // .dwo sections aren't currently supported by dwarfyaml. The dwo_yamldata
704 // contents where generated by roundtripping the following yaml through
705 // yaml2obj | obj2yaml and renaming the sections. This works because the
706 // structure of the .dwo and non-.dwo sections is identical.
715 // debug_abbrev: #.dwo
717 // - Code: 0x00000001
718 // Tag: DW_TAG_compile_unit
719 // Children: DW_CHILDREN_no
721 // - Attribute: DW_AT_dwo_id
722 // Form: DW_FORM_data4
729 // - Value: 0x0120304
731 const char *dwo_yamldata
= R
"(
739 - Name: .debug_abbrev.dwo
742 Content: '0111007506000000'
743 - Name: .debug_info.dwo
746 Content: 0D00000004000000000004010403020100
749 SubsystemRAII
<FileSystem
, HostInfo
, ObjectFileELF
, CustomSymbolFileDWARF
>
752 llvm::Expected
<TestFile
> skeleton_file
=
753 TestFile::fromYaml(skeleton_yamldata
);
754 EXPECT_THAT_EXPECTED(skeleton_file
, llvm::Succeeded());
755 llvm::Expected
<TestFile
> dwo_file
= TestFile::fromYaml(dwo_yamldata
);
756 EXPECT_THAT_EXPECTED(dwo_file
, llvm::Succeeded());
758 auto skeleton_module_sp
=
759 std::make_shared
<Module
>(skeleton_file
->moduleSpec());
760 auto &skeleton_symfile
=
761 *llvm::cast
<CustomSymbolFileDWARF
>(skeleton_module_sp
->GetSymbolFile());
763 auto dwo_module_sp
= std::make_shared
<Module
>(dwo_file
->moduleSpec());
764 SymbolFileDWARFDwo
dwo_symfile(
765 skeleton_symfile
, dwo_module_sp
->GetObjectFile()->shared_from_this(),
767 auto *dwo_dwarf_unit
= dwo_symfile
.DebugInfo().GetUnitAtIndex(0);
769 testExpressionVendorExtensions(dwo_module_sp
, *dwo_dwarf_unit
);