[AMDGPU][AsmParser][NFC] Translate parsed MIMG instructions to MCInsts automatically.
[llvm-project.git] / lldb / unittests / Expression / DWARFExpressionTest.cpp
blob7d153d7fbed881e71f04474c28e973303824f015
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;
29 static llvm::Expected<Scalar> Evaluate(llvm::ArrayRef<uint8_t> expr,
30 lldb::ModuleSP module_sp = {},
31 DWARFUnit *unit = nullptr,
32 ExecutionContext *exe_ctx = nullptr) {
33 DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle,
34 /*addr_size*/ 4);
35 Value result;
36 Status status;
37 if (!DWARFExpression::Evaluate(exe_ctx, /*reg_ctx*/ nullptr, module_sp,
38 extractor, unit, lldb::eRegisterKindLLDB,
39 /*initial_value_ptr*/ nullptr,
40 /*object_address_ptr*/ nullptr, result,
41 &status))
42 return status.ToError();
44 switch (result.GetValueType()) {
45 case Value::ValueType::Scalar:
46 return result.GetScalar();
47 case Value::ValueType::LoadAddress:
48 return LLDB_INVALID_ADDRESS;
49 case Value::ValueType::HostAddress: {
50 // Convert small buffers to scalars to simplify the tests.
51 DataBufferHeap &buf = result.GetBuffer();
52 if (buf.GetByteSize() <= 8) {
53 uint64_t val = 0;
54 memcpy(&val, buf.GetBytes(), buf.GetByteSize());
55 return Scalar(llvm::APInt(buf.GetByteSize()*8, val, false));
58 [[fallthrough]];
59 default:
60 return status.ToError();
64 class DWARFExpressionTester : public YAMLModuleTester {
65 public:
66 DWARFExpressionTester(llvm::StringRef yaml_data, size_t cu_index) :
67 YAMLModuleTester(yaml_data, cu_index) {}
69 using YAMLModuleTester::YAMLModuleTester;
70 llvm::Expected<Scalar> Eval(llvm::ArrayRef<uint8_t> expr) {
71 return ::Evaluate(expr, m_module_sp, m_dwarf_unit);
75 /// Unfortunately Scalar's operator==() is really picky.
76 static Scalar GetScalar(unsigned bits, uint64_t value, bool sign) {
77 Scalar scalar(value);
78 scalar.TruncOrExtendTo(bits, sign);
79 return scalar;
82 /// This is needed for the tests that use a mock process.
83 class DWARFExpressionMockProcessTest : public ::testing::Test {
84 public:
85 void SetUp() override {
86 FileSystem::Initialize();
87 HostInfo::Initialize();
88 platform_linux::PlatformLinux::Initialize();
90 void TearDown() override {
91 platform_linux::PlatformLinux::Terminate();
92 HostInfo::Terminate();
93 FileSystem::Terminate();
97 TEST(DWARFExpression, DW_OP_pick) {
98 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 0}),
99 llvm::HasValue(0));
100 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 1}),
101 llvm::HasValue(1));
102 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 2}),
103 llvm::Failed());
106 TEST(DWARFExpression, DW_OP_const) {
107 // Extend to address size.
108 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1u, 0x88}), llvm::HasValue(0x88));
109 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1s, 0x88}),
110 llvm::HasValue(0xffffff88));
111 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x47, 0x88}),
112 llvm::HasValue(0x8847));
113 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2s, 0x47, 0x88}),
114 llvm::HasValue(0xffff8847));
115 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4u, 0x44, 0x42, 0x47, 0x88}),
116 llvm::HasValue(0x88474244));
117 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4s, 0x44, 0x42, 0x47, 0x88}),
118 llvm::HasValue(0x88474244));
120 // Truncate to address size.
121 EXPECT_THAT_EXPECTED(
122 Evaluate({DW_OP_const8u, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}),
123 llvm::HasValue(0x33221100));
124 EXPECT_THAT_EXPECTED(
125 Evaluate({DW_OP_const8s, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}),
126 llvm::HasValue(0x33221100));
128 // Don't truncate to address size for compatibility with clang (pr48087).
129 EXPECT_THAT_EXPECTED(
130 Evaluate({DW_OP_constu, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}),
131 llvm::HasValue(0x01010101010101));
132 EXPECT_THAT_EXPECTED(
133 Evaluate({DW_OP_consts, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}),
134 llvm::HasValue(0xffff010101010101));
137 TEST(DWARFExpression, DW_OP_skip) {
138 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1u, 0x42, DW_OP_skip, 0x02, 0x00,
139 DW_OP_const1u, 0xff}),
140 llvm::HasValue(0x42));
143 TEST(DWARFExpression, DW_OP_bra) {
144 EXPECT_THAT_EXPECTED(
145 // clang-format off
146 Evaluate({
147 DW_OP_const1u, 0x42, // push 0x42
148 DW_OP_const1u, 0x1, // push 0x1
149 DW_OP_bra, 0x02, 0x00, // if 0x1 > 0, then skip 0x0002 opcodes
150 DW_OP_const1u, 0xff, // push 0xff
152 // clang-format on
153 llvm::HasValue(0x42));
156 TEST(DWARFExpression, DW_OP_convert) {
157 /// Auxiliary debug info.
158 const char *yamldata = R"(
159 --- !ELF
160 FileHeader:
161 Class: ELFCLASS64
162 Data: ELFDATA2LSB
163 Type: ET_EXEC
164 Machine: EM_386
165 DWARF:
166 debug_abbrev:
167 - Table:
168 - Code: 0x00000001
169 Tag: DW_TAG_compile_unit
170 Children: DW_CHILDREN_yes
171 Attributes:
172 - Attribute: DW_AT_language
173 Form: DW_FORM_data2
174 - Code: 0x00000002
175 Tag: DW_TAG_base_type
176 Children: DW_CHILDREN_no
177 Attributes:
178 - Attribute: DW_AT_encoding
179 Form: DW_FORM_data1
180 - Attribute: DW_AT_byte_size
181 Form: DW_FORM_data1
182 debug_info:
183 - Version: 4
184 AddrSize: 8
185 AbbrevTableID: 0
186 AbbrOffset: 0x0
187 Entries:
188 - AbbrCode: 0x00000001
189 Values:
190 - Value: 0x000000000000000C
191 - AbbrCode: 0x00000000
192 - Version: 4
193 AddrSize: 8
194 AbbrevTableID: 0
195 AbbrOffset: 0x0
196 Entries:
197 - AbbrCode: 0x00000001
198 Values:
199 - Value: 0x000000000000000C
200 # 0x0000000e:
201 - AbbrCode: 0x00000002
202 Values:
203 - Value: 0x0000000000000007 # DW_ATE_unsigned
204 - Value: 0x0000000000000004
205 # 0x00000011:
206 - AbbrCode: 0x00000002
207 Values:
208 - Value: 0x0000000000000007 # DW_ATE_unsigned
209 - Value: 0x0000000000000008
210 # 0x00000014:
211 - AbbrCode: 0x00000002
212 Values:
213 - Value: 0x0000000000000005 # DW_ATE_signed
214 - Value: 0x0000000000000008
215 # 0x00000017:
216 - AbbrCode: 0x00000002
217 Values:
218 - Value: 0x0000000000000008 # DW_ATE_unsigned_char
219 - Value: 0x0000000000000001
220 # 0x0000001a:
221 - AbbrCode: 0x00000002
222 Values:
223 - Value: 0x0000000000000006 # DW_ATE_signed_char
224 - Value: 0x0000000000000001
225 # 0x0000001d:
226 - AbbrCode: 0x00000002
227 Values:
228 - Value: 0x000000000000000b # DW_ATE_numeric_string
229 - Value: 0x0000000000000001
230 - AbbrCode: 0x00000000
233 // Compile unit relative offsets to each DW_TAG_base_type
234 uint8_t offs_uint32_t = 0x0000000e;
235 uint8_t offs_uint64_t = 0x00000011;
236 uint8_t offs_sint64_t = 0x00000014;
237 uint8_t offs_uchar = 0x00000017;
238 uint8_t offs_schar = 0x0000001a;
240 DWARFExpressionTester t(yamldata, /*cu_index=*/1);
241 ASSERT_TRUE((bool)t.GetDwarfUnit());
243 // Constant is given as little-endian.
244 bool is_signed = true;
245 bool not_signed = false;
248 // Positive tests.
251 // Leave as is.
252 EXPECT_THAT_EXPECTED(
253 t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //
254 DW_OP_convert, offs_uint32_t, DW_OP_stack_value}),
255 llvm::HasValue(GetScalar(64, 0x44332211, not_signed)));
257 // Zero-extend to 64 bits.
258 EXPECT_THAT_EXPECTED(
259 t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //
260 DW_OP_convert, offs_uint64_t, DW_OP_stack_value}),
261 llvm::HasValue(GetScalar(64, 0x44332211, not_signed)));
263 // Sign-extend to 64 bits.
264 EXPECT_THAT_EXPECTED(
265 t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
266 DW_OP_convert, offs_sint64_t, DW_OP_stack_value}),
267 llvm::HasValue(GetScalar(64, 0xffffffffffeeddcc, is_signed)));
269 // Sign-extend, then truncate.
270 EXPECT_THAT_EXPECTED(
271 t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
272 DW_OP_convert, offs_sint64_t, //
273 DW_OP_convert, offs_uint32_t, DW_OP_stack_value}),
274 llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed)));
276 // Truncate to default unspecified (pointer-sized) type.
277 EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
278 DW_OP_convert, offs_sint64_t, //
279 DW_OP_convert, 0x00, DW_OP_stack_value}),
280 llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed)));
282 // Truncate to 8 bits.
283 EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert,
284 offs_uchar, DW_OP_stack_value}),
285 llvm::HasValue(GetScalar(8, 'A', not_signed)));
287 // Also truncate to 8 bits.
288 EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert,
289 offs_schar, DW_OP_stack_value}),
290 llvm::HasValue(GetScalar(8, 'A', is_signed)));
293 // Errors.
296 // No Module.
297 EXPECT_THAT_ERROR(Evaluate({DW_OP_const1s, 'X', DW_OP_convert, 0x00}, nullptr,
298 t.GetDwarfUnit())
299 .takeError(),
300 llvm::Failed());
302 // No DIE.
303 EXPECT_THAT_ERROR(
304 t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x01}).takeError(),
305 llvm::Failed());
307 // Unsupported.
308 EXPECT_THAT_ERROR(
309 t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x1d}).takeError(),
310 llvm::Failed());
313 TEST(DWARFExpression, DW_OP_stack_value) {
314 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed());
317 TEST(DWARFExpression, DW_OP_piece) {
318 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x11, 0x22, DW_OP_piece, 2,
319 DW_OP_const2u, 0x33, 0x44, DW_OP_piece, 2}),
320 llvm::HasValue(GetScalar(32, 0x44332211, true)));
321 EXPECT_THAT_EXPECTED(
322 Evaluate({DW_OP_piece, 1, DW_OP_const1u, 0xff, DW_OP_piece, 1}),
323 // Note that the "00" should really be "undef", but we can't
324 // represent that yet.
325 llvm::HasValue(GetScalar(16, 0xff00, true)));
328 TEST(DWARFExpression, DW_OP_implicit_value) {
329 unsigned char bytes = 4;
331 EXPECT_THAT_EXPECTED(
332 Evaluate({DW_OP_implicit_value, bytes, 0x11, 0x22, 0x33, 0x44}),
333 llvm::HasValue(GetScalar(8 * bytes, 0x44332211, true)));
336 TEST(DWARFExpression, DW_OP_unknown) {
337 EXPECT_THAT_EXPECTED(
338 Evaluate({0xff}),
339 llvm::FailedWithMessage(
340 "Unhandled opcode DW_OP_unknown_ff in DWARFExpression"));
343 TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) {
344 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_deref}), llvm::Failed());
346 struct MockProcess : Process {
347 MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
348 : Process(target_sp, listener_sp) {}
350 llvm::StringRef GetPluginName() override { return "mock process"; }
351 bool CanDebug(lldb::TargetSP target,
352 bool plugin_specified_by_name) override {
353 return false;
355 Status DoDestroy() override { return {}; }
356 void RefreshStateAfterStop() override {}
357 bool DoUpdateThreadList(ThreadList &old_thread_list,
358 ThreadList &new_thread_list) override {
359 return false;
361 size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
362 Status &error) override {
363 for (size_t i = 0; i < size; ++i)
364 ((char *)buf)[i] = (vm_addr + i) & 0xff;
365 error.Clear();
366 return size;
370 // Set up a mock process.
371 ArchSpec arch("i386-pc-linux");
372 Platform::SetHostPlatform(
373 platform_linux::PlatformLinux::CreateInstance(true, &arch));
374 lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
375 ASSERT_TRUE(debugger_sp);
376 lldb::TargetSP target_sp;
377 lldb::PlatformSP platform_sp;
378 debugger_sp->GetTargetList().CreateTarget(
379 *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
380 ASSERT_TRUE(target_sp);
381 ASSERT_TRUE(target_sp->GetArchitecture().IsValid());
382 ASSERT_TRUE(platform_sp);
383 lldb::ListenerSP listener_sp(Listener::MakeListener("dummy"));
384 lldb::ProcessSP process_sp =
385 std::make_shared<MockProcess>(target_sp, listener_sp);
386 ASSERT_TRUE(process_sp);
388 ExecutionContext exe_ctx(process_sp);
389 // Implicit location: *0x4.
390 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value},
391 {}, {}, &exe_ctx),
392 llvm::HasValue(GetScalar(32, 0x07060504, false)));
393 // Memory location: *(*0x4).
394 // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
395 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref}, {}, {}, &exe_ctx),
396 llvm::HasValue(Scalar(LLDB_INVALID_ADDRESS)));
397 // Memory location: *0x4.
398 // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
399 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4}, {}, {}, &exe_ctx),
400 llvm::HasValue(Scalar(4)));
401 // Implicit location: *0x4.
402 // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
403 EXPECT_THAT_EXPECTED(
404 Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value}, {}, {}, &exe_ctx),
405 llvm::HasValue(GetScalar(32, 0x07060504, false)));
408 TEST_F(DWARFExpressionMockProcessTest, WASM_DW_OP_addr) {
409 // Set up a wasm target
410 ArchSpec arch("wasm32-unknown-unknown-wasm");
411 lldb::PlatformSP host_platform_sp =
412 platform_linux::PlatformLinux::CreateInstance(true, &arch);
413 ASSERT_TRUE(host_platform_sp);
414 Platform::SetHostPlatform(host_platform_sp);
415 lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
416 ASSERT_TRUE(debugger_sp);
417 lldb::TargetSP target_sp;
418 lldb::PlatformSP platform_sp;
419 debugger_sp->GetTargetList().CreateTarget(*debugger_sp, "", arch,
420 lldb_private::eLoadDependentsNo,
421 platform_sp, target_sp);
423 ExecutionContext exe_ctx(target_sp, false);
424 // DW_OP_addr takes a single operand of address size width:
425 uint8_t expr[] = {DW_OP_addr, 0x40, 0x0, 0x0, 0x0};
426 DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle,
427 /*addr_size*/ 4);
428 Value result;
429 Status status;
430 ASSERT_TRUE(DWARFExpression::Evaluate(
431 &exe_ctx, /*reg_ctx*/ nullptr, /*module_sp*/ {}, extractor,
432 /*unit*/ nullptr, lldb::eRegisterKindLLDB,
433 /*initial_value_ptr*/ nullptr,
434 /*object_address_ptr*/ nullptr, result, &status))
435 << status.ToError();
437 ASSERT_EQ(result.GetValueType(), Value::ValueType::LoadAddress);
440 TEST_F(DWARFExpressionMockProcessTest, WASM_DW_OP_addr_index) {
441 const char *yamldata = R"(
442 --- !ELF
443 FileHeader:
444 Class: ELFCLASS64
445 Data: ELFDATA2LSB
446 Type: ET_EXEC
447 Machine: EM_386
448 DWARF:
449 debug_abbrev:
450 - Table:
451 - Code: 0x00000001
452 Tag: DW_TAG_compile_unit
453 Children: DW_CHILDREN_no
454 Attributes:
455 - Attribute: DW_AT_addr_base
456 Form: DW_FORM_sec_offset
458 debug_info:
459 - Version: 5
460 AddrSize: 4
461 UnitType: DW_UT_compile
462 Entries:
463 - AbbrCode: 0x00000001
464 Values:
465 - Value: 0x8 # Offset of the first Address past the header
466 - AbbrCode: 0x0
468 debug_addr:
469 - Version: 5
470 AddressSize: 4
471 Entries:
472 - Address: 0x1234
473 - Address: 0x5678
476 // Can't use DWARFExpressionTester from above because subsystems overlap with
477 // the fixture.
478 SubsystemRAII<ObjectFileELF, SymbolFileDWARF> subsystems;
479 llvm::Expected<TestFile> file = TestFile::fromYaml(yamldata);
480 EXPECT_THAT_EXPECTED(file, llvm::Succeeded());
481 auto module_sp = std::make_shared<Module>(file->moduleSpec());
482 auto *dwarf_cu = llvm::cast<SymbolFileDWARF>(module_sp->GetSymbolFile())
483 ->DebugInfo()
484 .GetUnitAtIndex(0);
485 ASSERT_TRUE(dwarf_cu);
486 dwarf_cu->ExtractDIEsIfNeeded();
488 // Set up a wasm target
489 ArchSpec arch("wasm32-unknown-unknown-wasm");
490 lldb::PlatformSP host_platform_sp =
491 platform_linux::PlatformLinux::CreateInstance(true, &arch);
492 ASSERT_TRUE(host_platform_sp);
493 Platform::SetHostPlatform(host_platform_sp);
494 lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
495 ASSERT_TRUE(debugger_sp);
496 lldb::TargetSP target_sp;
497 lldb::PlatformSP platform_sp;
498 debugger_sp->GetTargetList().CreateTarget(*debugger_sp, "", arch,
499 lldb_private::eLoadDependentsNo,
500 platform_sp, target_sp);
502 ExecutionContext exe_ctx(target_sp, false);
503 // DW_OP_addrx takes a single leb128 operand, the index in the addr table:
504 uint8_t expr[] = {DW_OP_addrx, 0x01};
505 DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle,
506 /*addr_size*/ 4);
507 Value result;
508 Status status;
509 ASSERT_TRUE(DWARFExpression::Evaluate(
510 &exe_ctx, /*reg_ctx*/ nullptr, /*module_sp*/ {}, extractor, dwarf_cu,
511 lldb::eRegisterKindLLDB,
512 /*initial_value_ptr*/ nullptr,
513 /*object_address_ptr*/ nullptr, result, &status))
514 << status.ToError();
516 ASSERT_EQ(result.GetValueType(), Value::ValueType::LoadAddress);
517 ASSERT_EQ(result.GetScalar().UInt(), 0x5678u);
520 class CustomSymbolFileDWARF : public SymbolFileDWARF {
521 static char ID;
523 public:
524 using SymbolFileDWARF::SymbolFileDWARF;
526 bool isA(const void *ClassID) const override {
527 return ClassID == &ID || SymbolFile::isA(ClassID);
529 static bool classof(const SymbolFile *obj) { return obj->isA(&ID); }
531 static llvm::StringRef GetPluginNameStatic() { return "custom_dwarf"; }
533 static llvm::StringRef GetPluginDescriptionStatic() {
534 return "Symbol file reader with expression extensions.";
537 static void Initialize() {
538 PluginManager::RegisterPlugin(GetPluginNameStatic(),
539 GetPluginDescriptionStatic(), CreateInstance,
540 SymbolFileDWARF::DebuggerInitialize);
543 static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance); }
545 static lldb_private::SymbolFile *
546 CreateInstance(lldb::ObjectFileSP objfile_sp) {
547 return new CustomSymbolFileDWARF(std::move(objfile_sp),
548 /*dwo_section_list*/ nullptr);
551 lldb::offset_t
552 GetVendorDWARFOpcodeSize(const lldb_private::DataExtractor &data,
553 const lldb::offset_t data_offset,
554 const uint8_t op) const final {
555 auto offset = data_offset;
556 if (op != DW_OP_WASM_location) {
557 return LLDB_INVALID_OFFSET;
560 // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32
561 // Called with "arguments" 0x03 and 0x04
562 // Location type:
563 if (data.GetU8(&offset) != /* global */ 0x03) {
564 return LLDB_INVALID_OFFSET;
567 // Index
568 if (data.GetU32(&offset) != 0x04) {
569 return LLDB_INVALID_OFFSET;
572 // Report the skipped distance:
573 return offset - data_offset;
576 bool
577 ParseVendorDWARFOpcode(uint8_t op, const lldb_private::DataExtractor &opcodes,
578 lldb::offset_t &offset,
579 std::vector<lldb_private::Value> &stack) const final {
580 if (op != DW_OP_WASM_location) {
581 return false;
584 // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32
585 // Called with "arguments" 0x03 and 0x04
586 // Location type:
587 if (opcodes.GetU8(&offset) != /* global */ 0x03) {
588 return false;
591 // Index:
592 if (opcodes.GetU32(&offset) != 0x04) {
593 return false;
596 // Return some value:
597 stack.push_back({GetScalar(32, 42, false)});
598 return true;
602 char CustomSymbolFileDWARF::ID;
604 static auto testExpressionVendorExtensions(lldb::ModuleSP module_sp,
605 DWARFUnit &dwarf_unit) {
606 // Test that expression extensions can be evaluated, for example
607 // DW_OP_WASM_location which is not currently handled by DWARFExpression:
608 EXPECT_THAT_EXPECTED(Evaluate({DW_OP_WASM_location, 0x03, // WASM_GLOBAL:0x03
609 0x04, 0x00, 0x00, // index:u32
610 0x00, DW_OP_stack_value},
611 module_sp, &dwarf_unit),
612 llvm::HasValue(GetScalar(32, 42, false)));
614 // Test that searches for opcodes work in the presence of extensions:
615 uint8_t expr[] = {DW_OP_WASM_location, 0x03, 0x04, 0x00, 0x00, 0x00,
616 DW_OP_form_tls_address};
617 DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle,
618 /*addr_size*/ 4);
619 DWARFExpression dwarf_expr(extractor);
620 ASSERT_TRUE(dwarf_expr.ContainsThreadLocalStorage(&dwarf_unit));
623 TEST(DWARFExpression, Extensions) {
624 const char *yamldata = R"(
625 --- !ELF
626 FileHeader:
627 Class: ELFCLASS64
628 Data: ELFDATA2LSB
629 Type: ET_EXEC
630 Machine: EM_386
631 DWARF:
632 debug_abbrev:
633 - Table:
634 - Code: 0x00000001
635 Tag: DW_TAG_compile_unit
636 Children: DW_CHILDREN_no
637 debug_info:
638 - Version: 4
639 AddrSize: 4
640 Entries:
641 - AbbrCode: 0x1
642 - AbbrCode: 0x0
645 SubsystemRAII<FileSystem, HostInfo, TypeSystemClang, ObjectFileELF,
646 CustomSymbolFileDWARF>
647 subsystems;
649 llvm::Expected<TestFile> file = TestFile::fromYaml(yamldata);
650 EXPECT_THAT_EXPECTED(file, llvm::Succeeded());
652 auto module_sp = std::make_shared<Module>(file->moduleSpec());
653 auto &symfile =
654 *llvm::cast<CustomSymbolFileDWARF>(module_sp->GetSymbolFile());
655 auto *dwarf_unit = symfile.DebugInfo().GetUnitAtIndex(0);
657 testExpressionVendorExtensions(module_sp, *dwarf_unit);
660 TEST(DWARFExpression, ExtensionsDWO) {
661 const char *skeleton_yamldata = R"(
662 --- !ELF
663 FileHeader:
664 Class: ELFCLASS64
665 Data: ELFDATA2LSB
666 Type: ET_EXEC
667 Machine: EM_386
668 DWARF:
669 debug_abbrev:
670 - Table:
671 - Code: 0x00000001
672 Tag: DW_TAG_skeleton_unit
673 Children: DW_CHILDREN_no
674 Attributes:
675 - Attribute: DW_AT_dwo_name
676 Form: DW_FORM_string
677 - Attribute: DW_AT_dwo_id
678 Form: DW_FORM_data4
679 debug_info:
680 - Version: 4
681 AddrSize: 4
682 Entries:
683 - AbbrCode: 0x1
684 Values:
685 - CStr: "dwo_unit"
686 - Value: 0x01020304
687 - AbbrCode: 0x0
690 // .dwo sections aren't currently supported by dwarfyaml. The dwo_yamldata
691 // contents where generated by roundtripping the following yaml through
692 // yaml2obj | obj2yaml and renaming the sections. This works because the
693 // structure of the .dwo and non-.dwo sections is identical.
695 // --- !ELF
696 // FileHeader:
697 // Class: ELFCLASS64
698 // Data: ELFDATA2LSB
699 // Type: ET_EXEC
700 // Machine: EM_386
701 // DWARF:
702 // debug_abbrev: #.dwo
703 // - Table:
704 // - Code: 0x00000001
705 // Tag: DW_TAG_compile_unit
706 // Children: DW_CHILDREN_no
707 // Attributes:
708 // - Attribute: DW_AT_dwo_id
709 // Form: DW_FORM_data4
710 // debug_info: #.dwo
711 // - Version: 4
712 // AddrSize: 4
713 // Entries:
714 // - AbbrCode: 0x1
715 // Values:
716 // - Value: 0x0120304
717 // - AbbrCode: 0x0
718 const char *dwo_yamldata = R"(
719 --- !ELF
720 FileHeader:
721 Class: ELFCLASS64
722 Data: ELFDATA2LSB
723 Type: ET_EXEC
724 Machine: EM_386
725 Sections:
726 - Name: .debug_abbrev.dwo
727 Type: SHT_PROGBITS
728 AddressAlign: 0x1
729 Content: '0111007506000000'
730 - Name: .debug_info.dwo
731 Type: SHT_PROGBITS
732 AddressAlign: 0x1
733 Content: 0D00000004000000000004010403020100
736 SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, CustomSymbolFileDWARF>
737 subsystems;
739 llvm::Expected<TestFile> skeleton_file =
740 TestFile::fromYaml(skeleton_yamldata);
741 EXPECT_THAT_EXPECTED(skeleton_file, llvm::Succeeded());
742 llvm::Expected<TestFile> dwo_file = TestFile::fromYaml(dwo_yamldata);
743 EXPECT_THAT_EXPECTED(dwo_file, llvm::Succeeded());
745 auto skeleton_module_sp =
746 std::make_shared<Module>(skeleton_file->moduleSpec());
747 auto &skeleton_symfile =
748 *llvm::cast<CustomSymbolFileDWARF>(skeleton_module_sp->GetSymbolFile());
750 auto dwo_module_sp = std::make_shared<Module>(dwo_file->moduleSpec());
751 SymbolFileDWARFDwo dwo_symfile(
752 skeleton_symfile, dwo_module_sp->GetObjectFile()->shared_from_this(),
753 0x0120304);
754 auto *dwo_dwarf_unit = dwo_symfile.DebugInfo().GetUnitAtIndex(0);
756 testExpressionVendorExtensions(dwo_module_sp, *dwo_dwarf_unit);