xref: /llvm-project/lldb/unittests/Expression/DWARFExpressionTest.cpp (revision 75b37c3191254d0c418058cb94c3a7922b7ba71e)
180814287SRaphael Isemann //===-- DWARFExpressionTest.cpp -------------------------------------------===//
2b07a7997SPavel Labath //
3b07a7997SPavel Labath // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b07a7997SPavel Labath // See https://llvm.org/LICENSE.txt for license information.
5b07a7997SPavel Labath // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b07a7997SPavel Labath //
7b07a7997SPavel Labath //===----------------------------------------------------------------------===//
8b07a7997SPavel Labath 
9b07a7997SPavel Labath #include "lldb/Expression/DWARFExpression.h"
10188b0747SAdrian Prantl #include "Plugins/Platform/Linux/PlatformLinux.h"
11d839f654SPhilip Pfaffe #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
12c08d3b08SPhilip Pfaffe #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
13c21b71c1SJonas Devlieghere #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
14f37b62ecSJonas Devlieghere #include "TestingSupport/Symbol/YAMLModuleTester.h"
15188b0747SAdrian Prantl #include "lldb/Core/Debugger.h"
16c08d3b08SPhilip Pfaffe #include "lldb/Core/PluginManager.h"
1770599d70SJonas Devlieghere #include "lldb/Core/Value.h"
18b07a7997SPavel Labath #include "lldb/Core/dwarf.h"
19188b0747SAdrian Prantl #include "lldb/Host/HostInfo.h"
209b23df63SAdrian Prantl #include "lldb/Symbol/ObjectFile.h"
21b07a7997SPavel Labath #include "lldb/Utility/StreamString.h"
22b07a7997SPavel Labath #include "llvm/ADT/StringExtras.h"
23b07a7997SPavel Labath #include "llvm/Testing/Support/Error.h"
24b07a7997SPavel Labath #include "gtest/gtest.h"
25b07a7997SPavel Labath 
26b07a7997SPavel Labath using namespace lldb_private;
27ae869d44SShafik Yaghmour using namespace lldb_private::dwarf;
28a669a237Swalter erquinigo using namespace lldb_private::plugin::dwarf;
29b07a7997SPavel Labath 
30667c2eb0SAdrian Prantl static llvm::Expected<Scalar> Evaluate(llvm::ArrayRef<uint8_t> expr,
31667c2eb0SAdrian Prantl                                        lldb::ModuleSP module_sp = {},
32188b0747SAdrian Prantl                                        DWARFUnit *unit = nullptr,
33188b0747SAdrian Prantl                                        ExecutionContext *exe_ctx = nullptr) {
34667c2eb0SAdrian Prantl   DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle,
35667c2eb0SAdrian Prantl                           /*addr_size*/ 4);
36539b72f2SJonas Devlieghere 
37539b72f2SJonas Devlieghere   llvm::Expected<Value> result =
38539b72f2SJonas Devlieghere       DWARFExpression::Evaluate(exe_ctx, /*reg_ctx*/ nullptr, module_sp,
39188b0747SAdrian Prantl                                 extractor, unit, lldb::eRegisterKindLLDB,
40667c2eb0SAdrian Prantl                                 /*initial_value_ptr*/ nullptr,
41539b72f2SJonas Devlieghere                                 /*object_address_ptr*/ nullptr);
42539b72f2SJonas Devlieghere   if (!result)
43539b72f2SJonas Devlieghere     return result.takeError();
44667c2eb0SAdrian Prantl 
45539b72f2SJonas Devlieghere   switch (result->GetValueType()) {
46057efa99SAdrian Prantl   case Value::ValueType::Scalar:
47539b72f2SJonas Devlieghere     return result->GetScalar();
4814ccba26SAdrian Prantl   case Value::ValueType::LoadAddress:
4914ccba26SAdrian Prantl     return LLDB_INVALID_ADDRESS;
50057efa99SAdrian Prantl   case Value::ValueType::HostAddress: {
517b0d58e3SAdrian Prantl     // Convert small buffers to scalars to simplify the tests.
52539b72f2SJonas Devlieghere     DataBufferHeap &buf = result->GetBuffer();
537b0d58e3SAdrian Prantl     if (buf.GetByteSize() <= 8) {
547b0d58e3SAdrian Prantl       uint64_t val = 0;
557b0d58e3SAdrian Prantl       memcpy(&val, buf.GetBytes(), buf.GetByteSize());
567b0d58e3SAdrian Prantl       return Scalar(llvm::APInt(buf.GetByteSize()*8, val, false));
577b0d58e3SAdrian Prantl     }
587b0d58e3SAdrian Prantl   }
5959d2495fSFangrui Song     [[fallthrough]];
607b0d58e3SAdrian Prantl   default:
61539b72f2SJonas Devlieghere     break;
627b0d58e3SAdrian Prantl   }
63539b72f2SJonas Devlieghere   return llvm::createStringError("unsupported value type");
64667c2eb0SAdrian Prantl }
65667c2eb0SAdrian Prantl 
66f37b62ecSJonas Devlieghere class DWARFExpressionTester : public YAMLModuleTester {
679b23df63SAdrian Prantl public:
68376c7bd9SGreg Clayton   DWARFExpressionTester(llvm::StringRef yaml_data, size_t cu_index) :
69376c7bd9SGreg Clayton       YAMLModuleTester(yaml_data, cu_index) {}
70376c7bd9SGreg Clayton 
71f37b62ecSJonas Devlieghere   using YAMLModuleTester::YAMLModuleTester;
72667c2eb0SAdrian Prantl   llvm::Expected<Scalar> Eval(llvm::ArrayRef<uint8_t> expr) {
73a895a446SPavel Labath     return ::Evaluate(expr, m_module_sp, m_dwarf_unit);
74667c2eb0SAdrian Prantl   }
75667c2eb0SAdrian Prantl };
76b07a7997SPavel Labath 
779b23df63SAdrian Prantl /// Unfortunately Scalar's operator==() is really picky.
789b23df63SAdrian Prantl static Scalar GetScalar(unsigned bits, uint64_t value, bool sign) {
7916e17ca1SPavel Labath   Scalar scalar(value);
8016e17ca1SPavel Labath   scalar.TruncOrExtendTo(bits, sign);
819b23df63SAdrian Prantl   return scalar;
829b23df63SAdrian Prantl }
839b23df63SAdrian Prantl 
84188b0747SAdrian Prantl /// This is needed for the tests that use a mock process.
85188b0747SAdrian Prantl class DWARFExpressionMockProcessTest : public ::testing::Test {
86188b0747SAdrian Prantl public:
87188b0747SAdrian Prantl   void SetUp() override {
88188b0747SAdrian Prantl     FileSystem::Initialize();
89188b0747SAdrian Prantl     HostInfo::Initialize();
90188b0747SAdrian Prantl     platform_linux::PlatformLinux::Initialize();
91188b0747SAdrian Prantl   }
92188b0747SAdrian Prantl   void TearDown() override {
93188b0747SAdrian Prantl     platform_linux::PlatformLinux::Terminate();
94188b0747SAdrian Prantl     HostInfo::Terminate();
95188b0747SAdrian Prantl     FileSystem::Terminate();
96188b0747SAdrian Prantl   }
97188b0747SAdrian Prantl };
98188b0747SAdrian Prantl 
997dc84e22SJonas Devlieghere // NB: This class doesn't use the override keyword to avoid
1007dc84e22SJonas Devlieghere // -Winconsistent-missing-override warnings from the compiler. The
1017dc84e22SJonas Devlieghere // inconsistency comes from the overriding definitions in the MOCK_*** macros.
1027dc84e22SJonas Devlieghere class MockTarget : public Target {
1037dc84e22SJonas Devlieghere public:
1047dc84e22SJonas Devlieghere   MockTarget(Debugger &debugger, const ArchSpec &target_arch,
1057dc84e22SJonas Devlieghere              const lldb::PlatformSP &platform_sp)
1067dc84e22SJonas Devlieghere       : Target(debugger, target_arch, platform_sp, true) {}
1077dc84e22SJonas Devlieghere 
1087dc84e22SJonas Devlieghere   MOCK_METHOD2(ReadMemory,
1097dc84e22SJonas Devlieghere                llvm::Expected<std::vector<uint8_t>>(lldb::addr_t addr,
1107dc84e22SJonas Devlieghere                                                     size_t size));
1117dc84e22SJonas Devlieghere 
1127dc84e22SJonas Devlieghere   size_t ReadMemory(const Address &addr, void *dst, size_t dst_len,
1137dc84e22SJonas Devlieghere                     Status &error, bool force_live_memory = false,
1147dc84e22SJonas Devlieghere                     lldb::addr_t *load_addr_ptr = nullptr) /*override*/ {
1157dc84e22SJonas Devlieghere     auto expected_memory = this->ReadMemory(addr.GetOffset(), dst_len);
1167dc84e22SJonas Devlieghere     if (!expected_memory) {
1177dc84e22SJonas Devlieghere       llvm::consumeError(expected_memory.takeError());
1187dc84e22SJonas Devlieghere       return 0;
1197dc84e22SJonas Devlieghere     }
1207dc84e22SJonas Devlieghere     const size_t bytes_read = expected_memory->size();
1217dc84e22SJonas Devlieghere     assert(bytes_read <= dst_len);
1227dc84e22SJonas Devlieghere     std::memcpy(dst, expected_memory->data(), bytes_read);
1237dc84e22SJonas Devlieghere     return bytes_read;
1247dc84e22SJonas Devlieghere   }
1257dc84e22SJonas Devlieghere };
1267dc84e22SJonas Devlieghere 
127b07a7997SPavel Labath TEST(DWARFExpression, DW_OP_pick) {
128b07a7997SPavel Labath   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 0}),
129b07a7997SPavel Labath                        llvm::HasValue(0));
130b07a7997SPavel Labath   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 1}),
131b07a7997SPavel Labath                        llvm::HasValue(1));
132b07a7997SPavel Labath   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 2}),
133b07a7997SPavel Labath                        llvm::Failed());
134b07a7997SPavel Labath }
1359b23df63SAdrian Prantl 
1364edb7e34SPavel Labath TEST(DWARFExpression, DW_OP_const) {
1374edb7e34SPavel Labath   // Extend to address size.
1384edb7e34SPavel Labath   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1u, 0x88}), llvm::HasValue(0x88));
1394edb7e34SPavel Labath   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1s, 0x88}),
1404edb7e34SPavel Labath                        llvm::HasValue(0xffffff88));
1414edb7e34SPavel Labath   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x47, 0x88}),
1424edb7e34SPavel Labath                        llvm::HasValue(0x8847));
1434edb7e34SPavel Labath   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2s, 0x47, 0x88}),
1444edb7e34SPavel Labath                        llvm::HasValue(0xffff8847));
1454edb7e34SPavel Labath   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4u, 0x44, 0x42, 0x47, 0x88}),
1464edb7e34SPavel Labath                        llvm::HasValue(0x88474244));
1474edb7e34SPavel Labath   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4s, 0x44, 0x42, 0x47, 0x88}),
1484edb7e34SPavel Labath                        llvm::HasValue(0x88474244));
1494edb7e34SPavel Labath 
1504edb7e34SPavel Labath   // Truncate to address size.
1514edb7e34SPavel Labath   EXPECT_THAT_EXPECTED(
1524edb7e34SPavel Labath       Evaluate({DW_OP_const8u, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}),
1534edb7e34SPavel Labath       llvm::HasValue(0x33221100));
1544edb7e34SPavel Labath   EXPECT_THAT_EXPECTED(
1554edb7e34SPavel Labath       Evaluate({DW_OP_const8s, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}),
1564edb7e34SPavel Labath       llvm::HasValue(0x33221100));
1574edb7e34SPavel Labath 
1584edb7e34SPavel Labath   // Don't truncate to address size for compatibility with clang (pr48087).
1594edb7e34SPavel Labath   EXPECT_THAT_EXPECTED(
1604edb7e34SPavel Labath       Evaluate({DW_OP_constu, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}),
1614edb7e34SPavel Labath       llvm::HasValue(0x01010101010101));
1624edb7e34SPavel Labath   EXPECT_THAT_EXPECTED(
1634edb7e34SPavel Labath       Evaluate({DW_OP_consts, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}),
1644edb7e34SPavel Labath       llvm::HasValue(0xffff010101010101));
1654edb7e34SPavel Labath }
1664edb7e34SPavel Labath 
1675c39c31aSAndy Yankovsky TEST(DWARFExpression, DW_OP_skip) {
1685c39c31aSAndy Yankovsky   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1u, 0x42, DW_OP_skip, 0x02, 0x00,
1695c39c31aSAndy Yankovsky                                  DW_OP_const1u, 0xff}),
1705c39c31aSAndy Yankovsky                        llvm::HasValue(0x42));
1715c39c31aSAndy Yankovsky }
1725c39c31aSAndy Yankovsky 
1735c39c31aSAndy Yankovsky TEST(DWARFExpression, DW_OP_bra) {
1745c39c31aSAndy Yankovsky   EXPECT_THAT_EXPECTED(
1755c39c31aSAndy Yankovsky       // clang-format off
1765c39c31aSAndy Yankovsky       Evaluate({
1775c39c31aSAndy Yankovsky         DW_OP_const1u, 0x42,     // push 0x42
1785c39c31aSAndy Yankovsky         DW_OP_const1u, 0x1,      // push 0x1
1795c39c31aSAndy Yankovsky         DW_OP_bra, 0x02, 0x00,   // if 0x1 > 0, then skip 0x0002 opcodes
1805c39c31aSAndy Yankovsky         DW_OP_const1u, 0xff,     // push 0xff
1815c39c31aSAndy Yankovsky       }),
1825c39c31aSAndy Yankovsky       // clang-format on
1835c39c31aSAndy Yankovsky       llvm::HasValue(0x42));
184*75b37c31SJonas Devlieghere 
185*75b37c31SJonas Devlieghere   EXPECT_THAT_ERROR(Evaluate({DW_OP_bra, 0x01, 0x00}).takeError(),
186*75b37c31SJonas Devlieghere                     llvm::Failed());
1875c39c31aSAndy Yankovsky }
1885c39c31aSAndy Yankovsky 
1899b23df63SAdrian Prantl TEST(DWARFExpression, DW_OP_convert) {
1909b23df63SAdrian Prantl   /// Auxiliary debug info.
191a895a446SPavel Labath   const char *yamldata = R"(
192a895a446SPavel Labath --- !ELF
193a895a446SPavel Labath FileHeader:
194a895a446SPavel Labath   Class:   ELFCLASS64
195a895a446SPavel Labath   Data:    ELFDATA2LSB
196a895a446SPavel Labath   Type:    ET_EXEC
197a895a446SPavel Labath   Machine: EM_386
198a895a446SPavel Labath DWARF:
199a895a446SPavel Labath   debug_abbrev:
200a895a446SPavel Labath     - Table:
201a895a446SPavel Labath         - Code:            0x00000001
202a895a446SPavel Labath           Tag:             DW_TAG_compile_unit
203a895a446SPavel Labath           Children:        DW_CHILDREN_yes
204a895a446SPavel Labath           Attributes:
205a895a446SPavel Labath             - Attribute:       DW_AT_language
206a895a446SPavel Labath               Form:            DW_FORM_data2
207a895a446SPavel Labath         - Code:            0x00000002
208a895a446SPavel Labath           Tag:             DW_TAG_base_type
209a895a446SPavel Labath           Children:        DW_CHILDREN_no
210a895a446SPavel Labath           Attributes:
211a895a446SPavel Labath             - Attribute:       DW_AT_encoding
212a895a446SPavel Labath               Form:            DW_FORM_data1
213a895a446SPavel Labath             - Attribute:       DW_AT_byte_size
214a895a446SPavel Labath               Form:            DW_FORM_data1
215a895a446SPavel Labath   debug_info:
216a895a446SPavel Labath     - Version:         4
217a895a446SPavel Labath       AddrSize:        8
218376c7bd9SGreg Clayton       AbbrevTableID:   0
219376c7bd9SGreg Clayton       AbbrOffset:      0x0
220376c7bd9SGreg Clayton       Entries:
221376c7bd9SGreg Clayton         - AbbrCode:        0x00000001
222376c7bd9SGreg Clayton           Values:
223376c7bd9SGreg Clayton             - Value:           0x000000000000000C
224376c7bd9SGreg Clayton         - AbbrCode:        0x00000000
225376c7bd9SGreg Clayton     - Version:         4
226376c7bd9SGreg Clayton       AddrSize:        8
227376c7bd9SGreg Clayton       AbbrevTableID:   0
228376c7bd9SGreg Clayton       AbbrOffset:      0x0
229a895a446SPavel Labath       Entries:
230a895a446SPavel Labath         - AbbrCode:        0x00000001
231a895a446SPavel Labath           Values:
232a895a446SPavel Labath             - Value:           0x000000000000000C
233a895a446SPavel Labath         # 0x0000000e:
234a895a446SPavel Labath         - AbbrCode:        0x00000002
235a895a446SPavel Labath           Values:
236a895a446SPavel Labath             - Value:           0x0000000000000007 # DW_ATE_unsigned
237a895a446SPavel Labath             - Value:           0x0000000000000004
238a895a446SPavel Labath         # 0x00000011:
239a895a446SPavel Labath         - AbbrCode:        0x00000002
240a895a446SPavel Labath           Values:
241a895a446SPavel Labath             - Value:           0x0000000000000007 # DW_ATE_unsigned
242a895a446SPavel Labath             - Value:           0x0000000000000008
243a895a446SPavel Labath         # 0x00000014:
244a895a446SPavel Labath         - AbbrCode:        0x00000002
245a895a446SPavel Labath           Values:
246a895a446SPavel Labath             - Value:           0x0000000000000005 # DW_ATE_signed
247a895a446SPavel Labath             - Value:           0x0000000000000008
248a895a446SPavel Labath         # 0x00000017:
249a895a446SPavel Labath         - AbbrCode:        0x00000002
250a895a446SPavel Labath           Values:
251a895a446SPavel Labath             - Value:           0x0000000000000008 # DW_ATE_unsigned_char
252a895a446SPavel Labath             - Value:           0x0000000000000001
253a895a446SPavel Labath         # 0x0000001a:
254a895a446SPavel Labath         - AbbrCode:        0x00000002
255a895a446SPavel Labath           Values:
256a895a446SPavel Labath             - Value:           0x0000000000000006 # DW_ATE_signed_char
257a895a446SPavel Labath             - Value:           0x0000000000000001
258a895a446SPavel Labath         # 0x0000001d:
259a895a446SPavel Labath         - AbbrCode:        0x00000002
260a895a446SPavel Labath           Values:
261a895a446SPavel Labath             - Value:           0x000000000000000b # DW_ATE_numeric_string
262a895a446SPavel Labath             - Value:           0x0000000000000001
263a895a446SPavel Labath         - AbbrCode:        0x00000000
264376c7bd9SGreg Clayton 
265a895a446SPavel Labath )";
266376c7bd9SGreg Clayton   // Compile unit relative offsets to each DW_TAG_base_type
2679b23df63SAdrian Prantl   uint8_t offs_uint32_t = 0x0000000e;
2689b23df63SAdrian Prantl   uint8_t offs_uint64_t = 0x00000011;
2699b23df63SAdrian Prantl   uint8_t offs_sint64_t = 0x00000014;
2709b23df63SAdrian Prantl   uint8_t offs_uchar = 0x00000017;
2719b23df63SAdrian Prantl   uint8_t offs_schar = 0x0000001a;
2729b23df63SAdrian Prantl 
273376c7bd9SGreg Clayton   DWARFExpressionTester t(yamldata, /*cu_index=*/1);
274667c2eb0SAdrian Prantl   ASSERT_TRUE((bool)t.GetDwarfUnit());
2759b23df63SAdrian Prantl 
2769b23df63SAdrian Prantl   // Constant is given as little-endian.
2779b23df63SAdrian Prantl   bool is_signed = true;
2789b23df63SAdrian Prantl   bool not_signed = false;
2799b23df63SAdrian Prantl 
280667c2eb0SAdrian Prantl   //
281667c2eb0SAdrian Prantl   // Positive tests.
282667c2eb0SAdrian Prantl   //
283667c2eb0SAdrian Prantl 
2849b23df63SAdrian Prantl   // Leave as is.
2852c6710a5SAdrian Prantl   EXPECT_THAT_EXPECTED(
2862c6710a5SAdrian Prantl       t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //
2872c6710a5SAdrian Prantl               DW_OP_convert, offs_uint32_t, DW_OP_stack_value}),
2884edb7e34SPavel Labath       llvm::HasValue(GetScalar(64, 0x44332211, not_signed)));
2894edb7e34SPavel Labath 
2904edb7e34SPavel Labath   // Zero-extend to 64 bits.
2912c6710a5SAdrian Prantl   EXPECT_THAT_EXPECTED(
2922c6710a5SAdrian Prantl       t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, //
2932c6710a5SAdrian Prantl               DW_OP_convert, offs_uint64_t, DW_OP_stack_value}),
2944edb7e34SPavel Labath       llvm::HasValue(GetScalar(64, 0x44332211, not_signed)));
2959b23df63SAdrian Prantl 
2969b23df63SAdrian Prantl   // Sign-extend to 64 bits.
2979b23df63SAdrian Prantl   EXPECT_THAT_EXPECTED(
298667c2eb0SAdrian Prantl       t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
2992c6710a5SAdrian Prantl               DW_OP_convert, offs_sint64_t, DW_OP_stack_value}),
3009b23df63SAdrian Prantl       llvm::HasValue(GetScalar(64, 0xffffffffffeeddcc, is_signed)));
3019b23df63SAdrian Prantl 
3024edb7e34SPavel Labath   // Sign-extend, then truncate.
3032c6710a5SAdrian Prantl   EXPECT_THAT_EXPECTED(
3042c6710a5SAdrian Prantl       t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
3054edb7e34SPavel Labath               DW_OP_convert, offs_sint64_t,          //
3062c6710a5SAdrian Prantl               DW_OP_convert, offs_uint32_t, DW_OP_stack_value}),
3074edb7e34SPavel Labath       llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed)));
3084edb7e34SPavel Labath 
3094edb7e34SPavel Labath   // Truncate to default unspecified (pointer-sized) type.
3104edb7e34SPavel Labath   EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, //
3114edb7e34SPavel Labath                                DW_OP_convert, offs_sint64_t,          //
3122c6710a5SAdrian Prantl                                DW_OP_convert, 0x00, DW_OP_stack_value}),
3134edb7e34SPavel Labath                        llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed)));
3144edb7e34SPavel Labath 
3159b23df63SAdrian Prantl   // Truncate to 8 bits.
3162c6710a5SAdrian Prantl   EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert,
3172c6710a5SAdrian Prantl                                offs_uchar, DW_OP_stack_value}),
3189b23df63SAdrian Prantl                        llvm::HasValue(GetScalar(8, 'A', not_signed)));
3199b23df63SAdrian Prantl 
3209b23df63SAdrian Prantl   // Also truncate to 8 bits.
3212c6710a5SAdrian Prantl   EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert,
3222c6710a5SAdrian Prantl                                offs_schar, DW_OP_stack_value}),
3239b23df63SAdrian Prantl                        llvm::HasValue(GetScalar(8, 'A', is_signed)));
3249b23df63SAdrian Prantl 
3259b23df63SAdrian Prantl   //
3269b23df63SAdrian Prantl   // Errors.
3279b23df63SAdrian Prantl   //
3289b23df63SAdrian Prantl 
3299b23df63SAdrian Prantl   // No Module.
3309b23df63SAdrian Prantl   EXPECT_THAT_ERROR(Evaluate({DW_OP_const1s, 'X', DW_OP_convert, 0x00}, nullptr,
331a895a446SPavel Labath                              t.GetDwarfUnit())
3329b23df63SAdrian Prantl                         .takeError(),
3339b23df63SAdrian Prantl                     llvm::Failed());
3349b23df63SAdrian Prantl 
3359b23df63SAdrian Prantl   // No DIE.
336667c2eb0SAdrian Prantl   EXPECT_THAT_ERROR(
337667c2eb0SAdrian Prantl       t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x01}).takeError(),
3389b23df63SAdrian Prantl       llvm::Failed());
3399b23df63SAdrian Prantl 
3409b23df63SAdrian Prantl   // Unsupported.
341667c2eb0SAdrian Prantl   EXPECT_THAT_ERROR(
342667c2eb0SAdrian Prantl       t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x1d}).takeError(),
3439b23df63SAdrian Prantl       llvm::Failed());
3449b23df63SAdrian Prantl }
3457b0d58e3SAdrian Prantl 
346f3a7d790SMed Ismail Bennani TEST(DWARFExpression, DW_OP_stack_value) {
347f3a7d790SMed Ismail Bennani   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed());
348f3a7d790SMed Ismail Bennani }
349f3a7d790SMed Ismail Bennani 
3507b0d58e3SAdrian Prantl TEST(DWARFExpression, DW_OP_piece) {
3517b0d58e3SAdrian Prantl   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x11, 0x22, DW_OP_piece, 2,
3527b0d58e3SAdrian Prantl                                  DW_OP_const2u, 0x33, 0x44, DW_OP_piece, 2}),
3537b0d58e3SAdrian Prantl                        llvm::HasValue(GetScalar(32, 0x44332211, true)));
354f55ab6f9SAdrian Prantl   EXPECT_THAT_EXPECTED(
355f55ab6f9SAdrian Prantl       Evaluate({DW_OP_piece, 1, DW_OP_const1u, 0xff, DW_OP_piece, 1}),
356f55ab6f9SAdrian Prantl       // Note that the "00" should really be "undef", but we can't
357f55ab6f9SAdrian Prantl       // represent that yet.
358f55ab6f9SAdrian Prantl       llvm::HasValue(GetScalar(16, 0xff00, true)));
3597b0d58e3SAdrian Prantl }
360731fee8bSPavel Labath 
361efe62b63SMed Ismail Bennani TEST(DWARFExpression, DW_OP_implicit_value) {
362efe62b63SMed Ismail Bennani   unsigned char bytes = 4;
363efe62b63SMed Ismail Bennani 
364efe62b63SMed Ismail Bennani   EXPECT_THAT_EXPECTED(
365efe62b63SMed Ismail Bennani       Evaluate({DW_OP_implicit_value, bytes, 0x11, 0x22, 0x33, 0x44}),
366efe62b63SMed Ismail Bennani       llvm::HasValue(GetScalar(8 * bytes, 0x44332211, true)));
367efe62b63SMed Ismail Bennani }
368efe62b63SMed Ismail Bennani 
369731fee8bSPavel Labath TEST(DWARFExpression, DW_OP_unknown) {
370731fee8bSPavel Labath   EXPECT_THAT_EXPECTED(
371731fee8bSPavel Labath       Evaluate({0xff}),
372731fee8bSPavel Labath       llvm::FailedWithMessage(
373731fee8bSPavel Labath           "Unhandled opcode DW_OP_unknown_ff in DWARFExpression"));
374731fee8bSPavel Labath }
375585e7a35SAdrian Prantl 
376188b0747SAdrian Prantl TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) {
377585e7a35SAdrian Prantl   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_deref}), llvm::Failed());
378188b0747SAdrian Prantl 
379188b0747SAdrian Prantl   struct MockProcess : Process {
3809b031d5eSMichał Górny     MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
3819b031d5eSMichał Górny         : Process(target_sp, listener_sp) {}
3829b031d5eSMichał Górny 
383a3939e15SPavel Labath     llvm::StringRef GetPluginName() override { return "mock process"; }
384188b0747SAdrian Prantl     bool CanDebug(lldb::TargetSP target,
385188b0747SAdrian Prantl                   bool plugin_specified_by_name) override {
386188b0747SAdrian Prantl       return false;
387188b0747SAdrian Prantl     };
388188b0747SAdrian Prantl     Status DoDestroy() override { return {}; }
389188b0747SAdrian Prantl     void RefreshStateAfterStop() override {}
390188b0747SAdrian Prantl     bool DoUpdateThreadList(ThreadList &old_thread_list,
391188b0747SAdrian Prantl                             ThreadList &new_thread_list) override {
392188b0747SAdrian Prantl       return false;
393188b0747SAdrian Prantl     };
394188b0747SAdrian Prantl     size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
395188b0747SAdrian Prantl                         Status &error) override {
396188b0747SAdrian Prantl       for (size_t i = 0; i < size; ++i)
397188b0747SAdrian Prantl         ((char *)buf)[i] = (vm_addr + i) & 0xff;
398188b0747SAdrian Prantl       error.Clear();
399188b0747SAdrian Prantl       return size;
400188b0747SAdrian Prantl     }
401188b0747SAdrian Prantl   };
402188b0747SAdrian Prantl 
403188b0747SAdrian Prantl   // Set up a mock process.
404188b0747SAdrian Prantl   ArchSpec arch("i386-pc-linux");
405d6678404SMed Ismail Bennani   Platform::SetHostPlatform(
406d6678404SMed Ismail Bennani       platform_linux::PlatformLinux::CreateInstance(true, &arch));
407188b0747SAdrian Prantl   lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
408188b0747SAdrian Prantl   ASSERT_TRUE(debugger_sp);
409188b0747SAdrian Prantl   lldb::TargetSP target_sp;
410188b0747SAdrian Prantl   lldb::PlatformSP platform_sp;
411188b0747SAdrian Prantl   debugger_sp->GetTargetList().CreateTarget(
412188b0747SAdrian Prantl       *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp);
413188b0747SAdrian Prantl   ASSERT_TRUE(target_sp);
414188b0747SAdrian Prantl   ASSERT_TRUE(target_sp->GetArchitecture().IsValid());
415188b0747SAdrian Prantl   ASSERT_TRUE(platform_sp);
416188b0747SAdrian Prantl   lldb::ListenerSP listener_sp(Listener::MakeListener("dummy"));
417188b0747SAdrian Prantl   lldb::ProcessSP process_sp =
418188b0747SAdrian Prantl       std::make_shared<MockProcess>(target_sp, listener_sp);
419188b0747SAdrian Prantl   ASSERT_TRUE(process_sp);
420188b0747SAdrian Prantl 
421188b0747SAdrian Prantl   ExecutionContext exe_ctx(process_sp);
42214ccba26SAdrian Prantl   // Implicit location: *0x4.
42314ccba26SAdrian Prantl   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value},
42414ccba26SAdrian Prantl                                 {}, {}, &exe_ctx),
425188b0747SAdrian Prantl                        llvm::HasValue(GetScalar(32, 0x07060504, false)));
42614ccba26SAdrian Prantl   // Memory location: *(*0x4).
42714ccba26SAdrian Prantl   // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
42814ccba26SAdrian Prantl   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref}, {}, {}, &exe_ctx),
42914ccba26SAdrian Prantl                        llvm::HasValue(Scalar(LLDB_INVALID_ADDRESS)));
4302c6710a5SAdrian Prantl   // Memory location: *0x4.
4312c6710a5SAdrian Prantl   // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
4322c6710a5SAdrian Prantl   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4}, {}, {}, &exe_ctx),
4332c6710a5SAdrian Prantl                        llvm::HasValue(Scalar(4)));
4342c6710a5SAdrian Prantl   // Implicit location: *0x4.
4352c6710a5SAdrian Prantl   // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses.
4362c6710a5SAdrian Prantl   EXPECT_THAT_EXPECTED(
4372c6710a5SAdrian Prantl       Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value}, {}, {}, &exe_ctx),
4382c6710a5SAdrian Prantl       llvm::HasValue(GetScalar(32, 0x07060504, false)));
439585e7a35SAdrian Prantl }
440d839f654SPhilip Pfaffe 
441d839f654SPhilip Pfaffe TEST_F(DWARFExpressionMockProcessTest, WASM_DW_OP_addr) {
442d839f654SPhilip Pfaffe   // Set up a wasm target
443d839f654SPhilip Pfaffe   ArchSpec arch("wasm32-unknown-unknown-wasm");
444d839f654SPhilip Pfaffe   lldb::PlatformSP host_platform_sp =
445d6678404SMed Ismail Bennani       platform_linux::PlatformLinux::CreateInstance(true, &arch);
446d839f654SPhilip Pfaffe   ASSERT_TRUE(host_platform_sp);
447d839f654SPhilip Pfaffe   Platform::SetHostPlatform(host_platform_sp);
448d839f654SPhilip Pfaffe   lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
449d839f654SPhilip Pfaffe   ASSERT_TRUE(debugger_sp);
450d839f654SPhilip Pfaffe   lldb::TargetSP target_sp;
451d839f654SPhilip Pfaffe   lldb::PlatformSP platform_sp;
452d839f654SPhilip Pfaffe   debugger_sp->GetTargetList().CreateTarget(*debugger_sp, "", arch,
453d839f654SPhilip Pfaffe                                             lldb_private::eLoadDependentsNo,
454d839f654SPhilip Pfaffe                                             platform_sp, target_sp);
455d839f654SPhilip Pfaffe 
456d839f654SPhilip Pfaffe   ExecutionContext exe_ctx(target_sp, false);
457d839f654SPhilip Pfaffe   // DW_OP_addr takes a single operand of address size width:
458d839f654SPhilip Pfaffe   uint8_t expr[] = {DW_OP_addr, 0x40, 0x0, 0x0, 0x0};
459d839f654SPhilip Pfaffe   DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle,
460d839f654SPhilip Pfaffe                           /*addr_size*/ 4);
461539b72f2SJonas Devlieghere 
462539b72f2SJonas Devlieghere   llvm::Expected<Value> result = DWARFExpression::Evaluate(
463d839f654SPhilip Pfaffe       &exe_ctx, /*reg_ctx*/ nullptr, /*module_sp*/ {}, extractor,
464d839f654SPhilip Pfaffe       /*unit*/ nullptr, lldb::eRegisterKindLLDB,
465d839f654SPhilip Pfaffe       /*initial_value_ptr*/ nullptr,
466539b72f2SJonas Devlieghere       /*object_address_ptr*/ nullptr);
467d839f654SPhilip Pfaffe 
468539b72f2SJonas Devlieghere   ASSERT_THAT_EXPECTED(result, llvm::Succeeded());
469539b72f2SJonas Devlieghere   ASSERT_EQ(result->GetValueType(), Value::ValueType::LoadAddress);
470d839f654SPhilip Pfaffe }
471d839f654SPhilip Pfaffe 
472d839f654SPhilip Pfaffe TEST_F(DWARFExpressionMockProcessTest, WASM_DW_OP_addr_index) {
473d839f654SPhilip Pfaffe   const char *yamldata = R"(
474d839f654SPhilip Pfaffe --- !ELF
475d839f654SPhilip Pfaffe FileHeader:
476d839f654SPhilip Pfaffe   Class:   ELFCLASS64
477d839f654SPhilip Pfaffe   Data:    ELFDATA2LSB
478d839f654SPhilip Pfaffe   Type:    ET_EXEC
479d839f654SPhilip Pfaffe   Machine: EM_386
480d839f654SPhilip Pfaffe DWARF:
481d839f654SPhilip Pfaffe   debug_abbrev:
482d839f654SPhilip Pfaffe     - Table:
483d839f654SPhilip Pfaffe         - Code:            0x00000001
484d839f654SPhilip Pfaffe           Tag:             DW_TAG_compile_unit
485d839f654SPhilip Pfaffe           Children:        DW_CHILDREN_no
486d839f654SPhilip Pfaffe           Attributes:
487d839f654SPhilip Pfaffe             - Attribute:       DW_AT_addr_base
488d839f654SPhilip Pfaffe               Form:            DW_FORM_sec_offset
489d839f654SPhilip Pfaffe 
490d839f654SPhilip Pfaffe   debug_info:
491d839f654SPhilip Pfaffe     - Version:         5
492d839f654SPhilip Pfaffe       AddrSize:        4
493d839f654SPhilip Pfaffe       UnitType:        DW_UT_compile
494d839f654SPhilip Pfaffe       Entries:
495d839f654SPhilip Pfaffe         - AbbrCode:        0x00000001
496d839f654SPhilip Pfaffe           Values:
497d839f654SPhilip Pfaffe             - Value:           0x8 # Offset of the first Address past the header
498d839f654SPhilip Pfaffe         - AbbrCode:        0x0
499d839f654SPhilip Pfaffe 
500d839f654SPhilip Pfaffe   debug_addr:
501d839f654SPhilip Pfaffe     - Version: 5
502d839f654SPhilip Pfaffe       AddressSize: 4
503d839f654SPhilip Pfaffe       Entries:
504d839f654SPhilip Pfaffe         - Address: 0x1234
505d839f654SPhilip Pfaffe         - Address: 0x5678
506d839f654SPhilip Pfaffe )";
507d839f654SPhilip Pfaffe 
508d839f654SPhilip Pfaffe   // Can't use DWARFExpressionTester from above because subsystems overlap with
509d839f654SPhilip Pfaffe   // the fixture.
510d839f654SPhilip Pfaffe   SubsystemRAII<ObjectFileELF, SymbolFileDWARF> subsystems;
511d839f654SPhilip Pfaffe   llvm::Expected<TestFile> file = TestFile::fromYaml(yamldata);
512d839f654SPhilip Pfaffe   EXPECT_THAT_EXPECTED(file, llvm::Succeeded());
513d839f654SPhilip Pfaffe   auto module_sp = std::make_shared<Module>(file->moduleSpec());
514d839f654SPhilip Pfaffe   auto *dwarf_cu = llvm::cast<SymbolFileDWARF>(module_sp->GetSymbolFile())
515d839f654SPhilip Pfaffe                        ->DebugInfo()
516d839f654SPhilip Pfaffe                        .GetUnitAtIndex(0);
517d839f654SPhilip Pfaffe   ASSERT_TRUE(dwarf_cu);
518d839f654SPhilip Pfaffe   dwarf_cu->ExtractDIEsIfNeeded();
519d839f654SPhilip Pfaffe 
520d839f654SPhilip Pfaffe   // Set up a wasm target
521d839f654SPhilip Pfaffe   ArchSpec arch("wasm32-unknown-unknown-wasm");
522d839f654SPhilip Pfaffe   lldb::PlatformSP host_platform_sp =
523d6678404SMed Ismail Bennani       platform_linux::PlatformLinux::CreateInstance(true, &arch);
524d839f654SPhilip Pfaffe   ASSERT_TRUE(host_platform_sp);
525d839f654SPhilip Pfaffe   Platform::SetHostPlatform(host_platform_sp);
526d839f654SPhilip Pfaffe   lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
527d839f654SPhilip Pfaffe   ASSERT_TRUE(debugger_sp);
528d839f654SPhilip Pfaffe   lldb::TargetSP target_sp;
529d839f654SPhilip Pfaffe   lldb::PlatformSP platform_sp;
530d839f654SPhilip Pfaffe   debugger_sp->GetTargetList().CreateTarget(*debugger_sp, "", arch,
531d839f654SPhilip Pfaffe                                             lldb_private::eLoadDependentsNo,
532d839f654SPhilip Pfaffe                                             platform_sp, target_sp);
533d839f654SPhilip Pfaffe 
534d839f654SPhilip Pfaffe   ExecutionContext exe_ctx(target_sp, false);
53500c60496SFelipe de Azevedo Piovezan 
536539b72f2SJonas Devlieghere   auto evaluate = [&](DWARFExpression &expr) -> llvm::Expected<Value> {
53700c60496SFelipe de Azevedo Piovezan     DataExtractor extractor;
53800c60496SFelipe de Azevedo Piovezan     expr.GetExpressionData(extractor);
539539b72f2SJonas Devlieghere     return DWARFExpression::Evaluate(&exe_ctx, /*reg_ctx*/ nullptr,
540539b72f2SJonas Devlieghere                                      /*module_sp*/ {}, extractor, dwarf_cu,
541d839f654SPhilip Pfaffe                                      lldb::eRegisterKindLLDB,
542d839f654SPhilip Pfaffe                                      /*initial_value_ptr*/ nullptr,
543539b72f2SJonas Devlieghere                                      /*object_address_ptr*/ nullptr);
54400c60496SFelipe de Azevedo Piovezan   };
545d839f654SPhilip Pfaffe 
54600c60496SFelipe de Azevedo Piovezan   // DW_OP_addrx takes a single leb128 operand, the index in the addr table:
54700c60496SFelipe de Azevedo Piovezan   uint8_t expr_data[] = {DW_OP_addrx, 0x01};
54800c60496SFelipe de Azevedo Piovezan   DataExtractor extractor(expr_data, sizeof(expr_data), lldb::eByteOrderLittle,
54900c60496SFelipe de Azevedo Piovezan                           /*addr_size*/ 4);
55000c60496SFelipe de Azevedo Piovezan   DWARFExpression expr(extractor);
55100c60496SFelipe de Azevedo Piovezan 
552539b72f2SJonas Devlieghere   llvm::Expected<Value> result = evaluate(expr);
553539b72f2SJonas Devlieghere   ASSERT_THAT_EXPECTED(result, llvm::Succeeded());
554539b72f2SJonas Devlieghere   ASSERT_EQ(result->GetValueType(), Value::ValueType::LoadAddress);
555539b72f2SJonas Devlieghere   ASSERT_EQ(result->GetScalar().UInt(), 0x5678u);
556f09f0a6bSFelipe de Azevedo Piovezan 
557f09f0a6bSFelipe de Azevedo Piovezan   ASSERT_TRUE(expr.Update_DW_OP_addr(dwarf_cu, 0xdeadbeef));
558539b72f2SJonas Devlieghere   result = evaluate(expr);
559539b72f2SJonas Devlieghere   ASSERT_THAT_EXPECTED(result, llvm::Succeeded());
560539b72f2SJonas Devlieghere   ASSERT_EQ(result->GetValueType(), Value::ValueType::LoadAddress);
561539b72f2SJonas Devlieghere   ASSERT_EQ(result->GetScalar().UInt(), 0xdeadbeefu);
562d839f654SPhilip Pfaffe }
563c08d3b08SPhilip Pfaffe 
564c08d3b08SPhilip Pfaffe class CustomSymbolFileDWARF : public SymbolFileDWARF {
565c08d3b08SPhilip Pfaffe   static char ID;
566c08d3b08SPhilip Pfaffe 
567c08d3b08SPhilip Pfaffe public:
568c08d3b08SPhilip Pfaffe   using SymbolFileDWARF::SymbolFileDWARF;
569c08d3b08SPhilip Pfaffe 
570c08d3b08SPhilip Pfaffe   bool isA(const void *ClassID) const override {
571c08d3b08SPhilip Pfaffe     return ClassID == &ID || SymbolFile::isA(ClassID);
572c08d3b08SPhilip Pfaffe   }
573c08d3b08SPhilip Pfaffe   static bool classof(const SymbolFile *obj) { return obj->isA(&ID); }
574c08d3b08SPhilip Pfaffe 
575c08d3b08SPhilip Pfaffe   static llvm::StringRef GetPluginNameStatic() { return "custom_dwarf"; }
576c08d3b08SPhilip Pfaffe 
577c08d3b08SPhilip Pfaffe   static llvm::StringRef GetPluginDescriptionStatic() {
578c08d3b08SPhilip Pfaffe     return "Symbol file reader with expression extensions.";
579c08d3b08SPhilip Pfaffe   }
580c08d3b08SPhilip Pfaffe 
581c08d3b08SPhilip Pfaffe   static void Initialize() {
582c08d3b08SPhilip Pfaffe     PluginManager::RegisterPlugin(GetPluginNameStatic(),
583c08d3b08SPhilip Pfaffe                                   GetPluginDescriptionStatic(), CreateInstance,
584c08d3b08SPhilip Pfaffe                                   SymbolFileDWARF::DebuggerInitialize);
585c08d3b08SPhilip Pfaffe   }
586c08d3b08SPhilip Pfaffe 
587c08d3b08SPhilip Pfaffe   static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance); }
588c08d3b08SPhilip Pfaffe 
589c08d3b08SPhilip Pfaffe   static lldb_private::SymbolFile *
590c08d3b08SPhilip Pfaffe   CreateInstance(lldb::ObjectFileSP objfile_sp) {
591c08d3b08SPhilip Pfaffe     return new CustomSymbolFileDWARF(std::move(objfile_sp),
592c08d3b08SPhilip Pfaffe                                      /*dwo_section_list*/ nullptr);
593c08d3b08SPhilip Pfaffe   }
594c08d3b08SPhilip Pfaffe 
595c08d3b08SPhilip Pfaffe   lldb::offset_t
596c08d3b08SPhilip Pfaffe   GetVendorDWARFOpcodeSize(const lldb_private::DataExtractor &data,
597c08d3b08SPhilip Pfaffe                            const lldb::offset_t data_offset,
598c08d3b08SPhilip Pfaffe                            const uint8_t op) const final {
599c08d3b08SPhilip Pfaffe     auto offset = data_offset;
600c08d3b08SPhilip Pfaffe     if (op != DW_OP_WASM_location) {
601c08d3b08SPhilip Pfaffe       return LLDB_INVALID_OFFSET;
602c08d3b08SPhilip Pfaffe     }
603c08d3b08SPhilip Pfaffe 
604c08d3b08SPhilip Pfaffe     // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32
605c08d3b08SPhilip Pfaffe     // Called with "arguments" 0x03 and 0x04
606c08d3b08SPhilip Pfaffe     // Location type:
607c08d3b08SPhilip Pfaffe     if (data.GetU8(&offset) != /* global */ 0x03) {
608c08d3b08SPhilip Pfaffe       return LLDB_INVALID_OFFSET;
609c08d3b08SPhilip Pfaffe     }
610c08d3b08SPhilip Pfaffe 
611c08d3b08SPhilip Pfaffe     // Index
612c08d3b08SPhilip Pfaffe     if (data.GetU32(&offset) != 0x04) {
613c08d3b08SPhilip Pfaffe       return LLDB_INVALID_OFFSET;
614c08d3b08SPhilip Pfaffe     }
615c08d3b08SPhilip Pfaffe 
616c08d3b08SPhilip Pfaffe     // Report the skipped distance:
617c08d3b08SPhilip Pfaffe     return offset - data_offset;
618c08d3b08SPhilip Pfaffe   }
619c08d3b08SPhilip Pfaffe 
620c08d3b08SPhilip Pfaffe   bool
621c08d3b08SPhilip Pfaffe   ParseVendorDWARFOpcode(uint8_t op, const lldb_private::DataExtractor &opcodes,
622c08d3b08SPhilip Pfaffe                          lldb::offset_t &offset,
623c08d3b08SPhilip Pfaffe                          std::vector<lldb_private::Value> &stack) const final {
624c08d3b08SPhilip Pfaffe     if (op != DW_OP_WASM_location) {
625c08d3b08SPhilip Pfaffe       return false;
626c08d3b08SPhilip Pfaffe     }
627c08d3b08SPhilip Pfaffe 
628c08d3b08SPhilip Pfaffe     // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32
629c08d3b08SPhilip Pfaffe     // Called with "arguments" 0x03 and  0x04
630c08d3b08SPhilip Pfaffe     // Location type:
631c08d3b08SPhilip Pfaffe     if (opcodes.GetU8(&offset) != /* global */ 0x03) {
632c08d3b08SPhilip Pfaffe       return false;
633c08d3b08SPhilip Pfaffe     }
634c08d3b08SPhilip Pfaffe 
635c08d3b08SPhilip Pfaffe     // Index:
636c08d3b08SPhilip Pfaffe     if (opcodes.GetU32(&offset) != 0x04) {
637c08d3b08SPhilip Pfaffe       return false;
638c08d3b08SPhilip Pfaffe     }
639c08d3b08SPhilip Pfaffe 
640c08d3b08SPhilip Pfaffe     // Return some value:
641c08d3b08SPhilip Pfaffe     stack.push_back({GetScalar(32, 42, false)});
642c08d3b08SPhilip Pfaffe     return true;
643c08d3b08SPhilip Pfaffe   }
644c08d3b08SPhilip Pfaffe };
645c08d3b08SPhilip Pfaffe 
646c08d3b08SPhilip Pfaffe char CustomSymbolFileDWARF::ID;
647c08d3b08SPhilip Pfaffe 
648c08d3b08SPhilip Pfaffe static auto testExpressionVendorExtensions(lldb::ModuleSP module_sp,
649c08d3b08SPhilip Pfaffe                                            DWARFUnit &dwarf_unit) {
650c08d3b08SPhilip Pfaffe   // Test that expression extensions can be evaluated, for example
651c08d3b08SPhilip Pfaffe   // DW_OP_WASM_location which is not currently handled by DWARFExpression:
652c08d3b08SPhilip Pfaffe   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_WASM_location, 0x03, // WASM_GLOBAL:0x03
653c08d3b08SPhilip Pfaffe                                  0x04, 0x00, 0x00,          // index:u32
654c08d3b08SPhilip Pfaffe                                  0x00, DW_OP_stack_value},
655c08d3b08SPhilip Pfaffe                                 module_sp, &dwarf_unit),
656c08d3b08SPhilip Pfaffe                        llvm::HasValue(GetScalar(32, 42, false)));
657c08d3b08SPhilip Pfaffe 
658c08d3b08SPhilip Pfaffe   // Test that searches for opcodes work in the presence of extensions:
659c08d3b08SPhilip Pfaffe   uint8_t expr[] = {DW_OP_WASM_location,   0x03, 0x04, 0x00, 0x00, 0x00,
660c08d3b08SPhilip Pfaffe                     DW_OP_form_tls_address};
661c08d3b08SPhilip Pfaffe   DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle,
662c08d3b08SPhilip Pfaffe                           /*addr_size*/ 4);
663c08d3b08SPhilip Pfaffe   DWARFExpression dwarf_expr(extractor);
664c08d3b08SPhilip Pfaffe   ASSERT_TRUE(dwarf_expr.ContainsThreadLocalStorage(&dwarf_unit));
665c08d3b08SPhilip Pfaffe }
666c08d3b08SPhilip Pfaffe 
667c08d3b08SPhilip Pfaffe TEST(DWARFExpression, Extensions) {
668c08d3b08SPhilip Pfaffe   const char *yamldata = R"(
669c08d3b08SPhilip Pfaffe --- !ELF
670c08d3b08SPhilip Pfaffe FileHeader:
671c08d3b08SPhilip Pfaffe   Class:   ELFCLASS64
672c08d3b08SPhilip Pfaffe   Data:    ELFDATA2LSB
673c08d3b08SPhilip Pfaffe   Type:    ET_EXEC
674c08d3b08SPhilip Pfaffe   Machine: EM_386
675c08d3b08SPhilip Pfaffe DWARF:
676c08d3b08SPhilip Pfaffe   debug_abbrev:
677c08d3b08SPhilip Pfaffe     - Table:
678c08d3b08SPhilip Pfaffe         - Code:            0x00000001
679c08d3b08SPhilip Pfaffe           Tag:             DW_TAG_compile_unit
680c08d3b08SPhilip Pfaffe           Children:        DW_CHILDREN_no
681c08d3b08SPhilip Pfaffe   debug_info:
682c08d3b08SPhilip Pfaffe     - Version:         4
683c08d3b08SPhilip Pfaffe       AddrSize:        4
684c08d3b08SPhilip Pfaffe       Entries:
685c08d3b08SPhilip Pfaffe         - AbbrCode:        0x1
686c08d3b08SPhilip Pfaffe         - AbbrCode:        0x0
687c08d3b08SPhilip Pfaffe )";
688c08d3b08SPhilip Pfaffe 
689c08d3b08SPhilip Pfaffe   SubsystemRAII<FileSystem, HostInfo, TypeSystemClang, ObjectFileELF,
690c08d3b08SPhilip Pfaffe                 CustomSymbolFileDWARF>
691c08d3b08SPhilip Pfaffe       subsystems;
692c08d3b08SPhilip Pfaffe 
693c08d3b08SPhilip Pfaffe   llvm::Expected<TestFile> file = TestFile::fromYaml(yamldata);
694c08d3b08SPhilip Pfaffe   EXPECT_THAT_EXPECTED(file, llvm::Succeeded());
695c08d3b08SPhilip Pfaffe 
696c08d3b08SPhilip Pfaffe   auto module_sp = std::make_shared<Module>(file->moduleSpec());
697c08d3b08SPhilip Pfaffe   auto &symfile =
698c08d3b08SPhilip Pfaffe       *llvm::cast<CustomSymbolFileDWARF>(module_sp->GetSymbolFile());
699c08d3b08SPhilip Pfaffe   auto *dwarf_unit = symfile.DebugInfo().GetUnitAtIndex(0);
700c08d3b08SPhilip Pfaffe 
701c08d3b08SPhilip Pfaffe   testExpressionVendorExtensions(module_sp, *dwarf_unit);
702c08d3b08SPhilip Pfaffe }
703c08d3b08SPhilip Pfaffe 
704c08d3b08SPhilip Pfaffe TEST(DWARFExpression, ExtensionsDWO) {
705c08d3b08SPhilip Pfaffe   const char *skeleton_yamldata = R"(
706c08d3b08SPhilip Pfaffe --- !ELF
707c08d3b08SPhilip Pfaffe FileHeader:
708c08d3b08SPhilip Pfaffe   Class:   ELFCLASS64
709c08d3b08SPhilip Pfaffe   Data:    ELFDATA2LSB
710c08d3b08SPhilip Pfaffe   Type:    ET_EXEC
711c08d3b08SPhilip Pfaffe   Machine: EM_386
712c08d3b08SPhilip Pfaffe DWARF:
713c08d3b08SPhilip Pfaffe   debug_abbrev:
714c08d3b08SPhilip Pfaffe     - Table:
715c08d3b08SPhilip Pfaffe         - Code:            0x00000001
716c08d3b08SPhilip Pfaffe           Tag:             DW_TAG_skeleton_unit
717c08d3b08SPhilip Pfaffe           Children:        DW_CHILDREN_no
718c08d3b08SPhilip Pfaffe           Attributes:
719c08d3b08SPhilip Pfaffe             - Attribute:       DW_AT_dwo_name
720c08d3b08SPhilip Pfaffe               Form:            DW_FORM_string
721c08d3b08SPhilip Pfaffe             - Attribute:       DW_AT_dwo_id
722c08d3b08SPhilip Pfaffe               Form:            DW_FORM_data4
723c08d3b08SPhilip Pfaffe   debug_info:
724c08d3b08SPhilip Pfaffe     - Version:         4
725c08d3b08SPhilip Pfaffe       AddrSize:        4
726c08d3b08SPhilip Pfaffe       Entries:
727c08d3b08SPhilip Pfaffe         - AbbrCode:        0x1
728c08d3b08SPhilip Pfaffe           Values:
729c08d3b08SPhilip Pfaffe             - CStr:           "dwo_unit"
730c08d3b08SPhilip Pfaffe             - Value:           0x01020304
731c08d3b08SPhilip Pfaffe         - AbbrCode:        0x0
732c08d3b08SPhilip Pfaffe )";
733c08d3b08SPhilip Pfaffe 
734c08d3b08SPhilip Pfaffe   // .dwo sections aren't currently supported by dwarfyaml. The dwo_yamldata
735c08d3b08SPhilip Pfaffe   // contents where generated by roundtripping the following yaml through
736c08d3b08SPhilip Pfaffe   // yaml2obj | obj2yaml and renaming the sections. This works because the
737c08d3b08SPhilip Pfaffe   // structure of the .dwo and non-.dwo sections is identical.
738c08d3b08SPhilip Pfaffe   //
739c08d3b08SPhilip Pfaffe   // --- !ELF
740c08d3b08SPhilip Pfaffe   // FileHeader:
741c08d3b08SPhilip Pfaffe   //   Class:   ELFCLASS64
742c08d3b08SPhilip Pfaffe   //   Data:    ELFDATA2LSB
743c08d3b08SPhilip Pfaffe   //   Type:    ET_EXEC
744c08d3b08SPhilip Pfaffe   //   Machine: EM_386
745c08d3b08SPhilip Pfaffe   // DWARF:
746c08d3b08SPhilip Pfaffe   //   debug_abbrev: #.dwo
747c08d3b08SPhilip Pfaffe   //     - Table:
748c08d3b08SPhilip Pfaffe   //         - Code:            0x00000001
749c08d3b08SPhilip Pfaffe   //           Tag:             DW_TAG_compile_unit
750c08d3b08SPhilip Pfaffe   //           Children:        DW_CHILDREN_no
751c08d3b08SPhilip Pfaffe   //           Attributes:
752c08d3b08SPhilip Pfaffe   //             - Attribute:       DW_AT_dwo_id
753c08d3b08SPhilip Pfaffe   //               Form:            DW_FORM_data4
754c08d3b08SPhilip Pfaffe   //   debug_info: #.dwo
755c08d3b08SPhilip Pfaffe   //     - Version:         4
756c08d3b08SPhilip Pfaffe   //       AddrSize:        4
757c08d3b08SPhilip Pfaffe   //       Entries:
758c08d3b08SPhilip Pfaffe   //         - AbbrCode:        0x1
759c08d3b08SPhilip Pfaffe   //           Values:
76034a8e6eeSAlexander Yermolovich   //             - Value:           0x0120304
761c08d3b08SPhilip Pfaffe   //         - AbbrCode:        0x0
762c08d3b08SPhilip Pfaffe   const char *dwo_yamldata = R"(
763c08d3b08SPhilip Pfaffe --- !ELF
764c08d3b08SPhilip Pfaffe FileHeader:
765c08d3b08SPhilip Pfaffe   Class:           ELFCLASS64
766c08d3b08SPhilip Pfaffe   Data:            ELFDATA2LSB
767c08d3b08SPhilip Pfaffe   Type:            ET_EXEC
768c08d3b08SPhilip Pfaffe   Machine:         EM_386
769c08d3b08SPhilip Pfaffe Sections:
770c08d3b08SPhilip Pfaffe   - Name:            .debug_abbrev.dwo
771c08d3b08SPhilip Pfaffe     Type:            SHT_PROGBITS
772c08d3b08SPhilip Pfaffe     AddressAlign:    0x1
773c08d3b08SPhilip Pfaffe     Content:         '0111007506000000'
774c08d3b08SPhilip Pfaffe   - Name:            .debug_info.dwo
775c08d3b08SPhilip Pfaffe     Type:            SHT_PROGBITS
776c08d3b08SPhilip Pfaffe     AddressAlign:    0x1
777c08d3b08SPhilip Pfaffe     Content:         0D00000004000000000004010403020100
778c08d3b08SPhilip Pfaffe )";
779c08d3b08SPhilip Pfaffe 
780c08d3b08SPhilip Pfaffe   SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, CustomSymbolFileDWARF>
781c08d3b08SPhilip Pfaffe       subsystems;
782c08d3b08SPhilip Pfaffe 
783c08d3b08SPhilip Pfaffe   llvm::Expected<TestFile> skeleton_file =
784c08d3b08SPhilip Pfaffe       TestFile::fromYaml(skeleton_yamldata);
785c08d3b08SPhilip Pfaffe   EXPECT_THAT_EXPECTED(skeleton_file, llvm::Succeeded());
786c08d3b08SPhilip Pfaffe   llvm::Expected<TestFile> dwo_file = TestFile::fromYaml(dwo_yamldata);
787c08d3b08SPhilip Pfaffe   EXPECT_THAT_EXPECTED(dwo_file, llvm::Succeeded());
788c08d3b08SPhilip Pfaffe 
789c08d3b08SPhilip Pfaffe   auto skeleton_module_sp =
790c08d3b08SPhilip Pfaffe       std::make_shared<Module>(skeleton_file->moduleSpec());
791c08d3b08SPhilip Pfaffe   auto &skeleton_symfile =
792c08d3b08SPhilip Pfaffe       *llvm::cast<CustomSymbolFileDWARF>(skeleton_module_sp->GetSymbolFile());
793c08d3b08SPhilip Pfaffe 
794c08d3b08SPhilip Pfaffe   auto dwo_module_sp = std::make_shared<Module>(dwo_file->moduleSpec());
795c08d3b08SPhilip Pfaffe   SymbolFileDWARFDwo dwo_symfile(
796c08d3b08SPhilip Pfaffe       skeleton_symfile, dwo_module_sp->GetObjectFile()->shared_from_this(),
79734a8e6eeSAlexander Yermolovich       0x0120304);
798c08d3b08SPhilip Pfaffe   auto *dwo_dwarf_unit = dwo_symfile.DebugInfo().GetUnitAtIndex(0);
799c08d3b08SPhilip Pfaffe 
800c08d3b08SPhilip Pfaffe   testExpressionVendorExtensions(dwo_module_sp, *dwo_dwarf_unit);
801c08d3b08SPhilip Pfaffe }
8027dc84e22SJonas Devlieghere 
8037dc84e22SJonas Devlieghere TEST_F(DWARFExpressionMockProcessTest, DW_OP_piece_file_addr) {
8047dc84e22SJonas Devlieghere   using ::testing::ByMove;
8057dc84e22SJonas Devlieghere   using ::testing::ElementsAre;
8067dc84e22SJonas Devlieghere   using ::testing::Return;
8077dc84e22SJonas Devlieghere 
8087dc84e22SJonas Devlieghere   // Set up a mock process.
8097dc84e22SJonas Devlieghere   ArchSpec arch("i386-pc-linux");
8107dc84e22SJonas Devlieghere   Platform::SetHostPlatform(
8117dc84e22SJonas Devlieghere       platform_linux::PlatformLinux::CreateInstance(true, &arch));
8127dc84e22SJonas Devlieghere   lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
8137dc84e22SJonas Devlieghere   ASSERT_TRUE(debugger_sp);
8147dc84e22SJonas Devlieghere   lldb::PlatformSP platform_sp;
8157dc84e22SJonas Devlieghere   auto target_sp =
8167dc84e22SJonas Devlieghere       std::make_shared<MockTarget>(*debugger_sp, arch, platform_sp);
8177dc84e22SJonas Devlieghere   ASSERT_TRUE(target_sp);
8187dc84e22SJonas Devlieghere   ASSERT_TRUE(target_sp->GetArchitecture().IsValid());
8197dc84e22SJonas Devlieghere 
8207dc84e22SJonas Devlieghere   EXPECT_CALL(*target_sp, ReadMemory(0x40, 1))
8217dc84e22SJonas Devlieghere       .WillOnce(Return(ByMove(std::vector<uint8_t>{0x11})));
8227dc84e22SJonas Devlieghere   EXPECT_CALL(*target_sp, ReadMemory(0x50, 1))
8237dc84e22SJonas Devlieghere       .WillOnce(Return(ByMove(std::vector<uint8_t>{0x22})));
8247dc84e22SJonas Devlieghere 
8257dc84e22SJonas Devlieghere   ExecutionContext exe_ctx(static_cast<lldb::TargetSP>(target_sp), false);
8267dc84e22SJonas Devlieghere 
8277dc84e22SJonas Devlieghere   uint8_t expr[] = {DW_OP_addr, 0x40, 0x0, 0x0, 0x0, DW_OP_piece, 1,
8287dc84e22SJonas Devlieghere                     DW_OP_addr, 0x50, 0x0, 0x0, 0x0, DW_OP_piece, 1};
8297dc84e22SJonas Devlieghere   DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle,
8307dc84e22SJonas Devlieghere                           /*addr_size*/ 4);
831539b72f2SJonas Devlieghere   llvm::Expected<Value> result = DWARFExpression::Evaluate(
8327dc84e22SJonas Devlieghere       &exe_ctx, /*reg_ctx*/ nullptr, /*module_sp*/ {}, extractor,
8337dc84e22SJonas Devlieghere       /*unit*/ nullptr, lldb::eRegisterKindLLDB,
8347dc84e22SJonas Devlieghere       /*initial_value_ptr*/ nullptr,
835539b72f2SJonas Devlieghere       /*object_address_ptr*/ nullptr);
8367dc84e22SJonas Devlieghere 
837539b72f2SJonas Devlieghere   ASSERT_THAT_EXPECTED(result, llvm::Succeeded());
838539b72f2SJonas Devlieghere   ASSERT_EQ(result->GetValueType(), Value::ValueType::HostAddress);
839539b72f2SJonas Devlieghere   ASSERT_THAT(result->GetBuffer().GetData(), ElementsAre(0x11, 0x22));
8407dc84e22SJonas Devlieghere }
841