xref: /llvm-project/lldb/unittests/Expression/DWARFExpressionTest.cpp (revision 75b37c3191254d0c418058cb94c3a7922b7ba71e)
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