1 //===-- DWARFIndexCachingTest.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 "Plugins/SymbolFile/DWARF/DIERef.h"
10 #include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
11 #include "Plugins/SymbolFile/DWARF/ManualDWARFIndex.h"
12 #include "Plugins/SymbolFile/DWARF/NameToDIE.h"
13 #include "TestingSupport/Symbol/YAMLModuleTester.h"
14 #include "lldb/Core/DataFileCache.h"
15 #include "lldb/Core/ModuleList.h"
16 #include "lldb/Utility/DataEncoder.h"
17 #include "lldb/Utility/DataExtractor.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21 
22 using namespace lldb;
23 using namespace lldb_private;
24 
EncodeDecode(const DIERef & object,ByteOrder byte_order)25 static void EncodeDecode(const DIERef &object, ByteOrder byte_order) {
26   const uint8_t addr_size = 8;
27   DataEncoder encoder(byte_order, addr_size);
28   object.Encode(encoder);
29   llvm::ArrayRef<uint8_t> bytes = encoder.GetData();
30   DataExtractor data(bytes.data(), bytes.size(), byte_order, addr_size);
31   offset_t data_offset = 0;
32   EXPECT_EQ(object, DIERef::Decode(data, &data_offset));
33 }
34 
EncodeDecode(const DIERef & object)35 static void EncodeDecode(const DIERef &object) {
36   EncodeDecode(object, eByteOrderLittle);
37   EncodeDecode(object, eByteOrderBig);
38 }
39 
TEST(DWARFIndexCachingTest,DIERefEncodeDecode)40 TEST(DWARFIndexCachingTest, DIERefEncodeDecode) {
41   // Tests DIERef::Encode(...) and DIERef::Decode(...)
42   EncodeDecode(DIERef(llvm::None, DIERef::Section::DebugInfo, 0x11223344));
43   EncodeDecode(DIERef(llvm::None, DIERef::Section::DebugTypes, 0x11223344));
44   EncodeDecode(DIERef(100, DIERef::Section::DebugInfo, 0x11223344));
45   EncodeDecode(DIERef(200, DIERef::Section::DebugTypes, 0x11223344));
46 }
47 
EncodeDecode(const NameToDIE & object,ByteOrder byte_order)48 static void EncodeDecode(const NameToDIE &object, ByteOrder byte_order) {
49   const uint8_t addr_size = 8;
50   DataEncoder encoder(byte_order, addr_size);
51   DataEncoder strtab_encoder(byte_order, addr_size);
52   ConstStringTable const_strtab;
53 
54   object.Encode(encoder, const_strtab);
55 
56   llvm::ArrayRef<uint8_t> bytes = encoder.GetData();
57   DataExtractor data(bytes.data(), bytes.size(), byte_order, addr_size);
58 
59   const_strtab.Encode(strtab_encoder);
60   llvm::ArrayRef<uint8_t> strtab_bytes = strtab_encoder.GetData();
61   DataExtractor strtab_data(strtab_bytes.data(), strtab_bytes.size(),
62                             byte_order, addr_size);
63   StringTableReader strtab_reader;
64   offset_t strtab_data_offset = 0;
65   ASSERT_EQ(strtab_reader.Decode(strtab_data, &strtab_data_offset), true);
66 
67   NameToDIE decoded_object;
68   offset_t data_offset = 0;
69   decoded_object.Decode(data, &data_offset, strtab_reader);
70   EXPECT_EQ(object, decoded_object);
71 }
72 
EncodeDecode(const NameToDIE & object)73 static void EncodeDecode(const NameToDIE &object) {
74   EncodeDecode(object, eByteOrderLittle);
75   EncodeDecode(object, eByteOrderBig);
76 }
77 
TEST(DWARFIndexCachingTest,NameToDIEEncodeDecode)78 TEST(DWARFIndexCachingTest, NameToDIEEncodeDecode) {
79   NameToDIE map;
80   // Make sure an empty NameToDIE map encodes and decodes correctly.
81   EncodeDecode(map);
82   map.Insert(ConstString("hello"),
83              DIERef(llvm::None, DIERef::Section::DebugInfo, 0x11223344));
84   map.Insert(ConstString("workd"),
85              DIERef(100, DIERef::Section::DebugInfo, 0x11223344));
86   map.Finalize();
87   // Make sure a valid NameToDIE map encodes and decodes correctly.
88   EncodeDecode(map);
89 }
90 
EncodeDecode(const ManualDWARFIndex::IndexSet & object,ByteOrder byte_order)91 static void EncodeDecode(const ManualDWARFIndex::IndexSet &object,
92                          ByteOrder byte_order) {
93   const uint8_t addr_size = 8;
94   DataEncoder encoder(byte_order, addr_size);
95   DataEncoder strtab_encoder(byte_order, addr_size);
96   object.Encode(encoder);
97   llvm::ArrayRef<uint8_t> bytes = encoder.GetData();
98   DataExtractor data(bytes.data(), bytes.size(), byte_order, addr_size);
99   ManualDWARFIndex::IndexSet decoded_object;
100   offset_t data_offset = 0;
101   decoded_object.Decode(data, &data_offset);
102   EXPECT_TRUE(object == decoded_object);
103 }
104 
EncodeDecode(const ManualDWARFIndex::IndexSet & object)105 static void EncodeDecode(const ManualDWARFIndex::IndexSet &object) {
106   EncodeDecode(object, eByteOrderLittle);
107   EncodeDecode(object, eByteOrderBig);
108 }
109 
TEST(DWARFIndexCachingTest,ManualDWARFIndexIndexSetEncodeDecode)110 TEST(DWARFIndexCachingTest, ManualDWARFIndexIndexSetEncodeDecode) {
111   ManualDWARFIndex::IndexSet set;
112   // Make sure empty IndexSet can be encoded and decoded correctly
113   EncodeDecode(set);
114 
115   dw_offset_t die_offset = 0;
116   // Make sure an IndexSet with only items in IndexSet::function_basenames can
117   // be encoded and decoded correctly.
118   set.function_basenames.Insert(
119       ConstString("a"),
120       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
121   EncodeDecode(set);
122   set.function_basenames.Clear();
123   // Make sure an IndexSet with only items in IndexSet::function_fullnames can
124   // be encoded and decoded correctly.
125   set.function_fullnames.Insert(
126       ConstString("a"),
127       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
128   EncodeDecode(set);
129   set.function_fullnames.Clear();
130   // Make sure an IndexSet with only items in IndexSet::function_methods can
131   // be encoded and decoded correctly.
132   set.function_methods.Insert(
133       ConstString("a"),
134       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
135   EncodeDecode(set);
136   set.function_methods.Clear();
137   // Make sure an IndexSet with only items in IndexSet::function_selectors can
138   // be encoded and decoded correctly.
139   set.function_selectors.Insert(
140       ConstString("a"),
141       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
142   EncodeDecode(set);
143   set.function_selectors.Clear();
144   // Make sure an IndexSet with only items in IndexSet::objc_class_selectors can
145   // be encoded and decoded correctly.
146   set.objc_class_selectors.Insert(
147       ConstString("a"),
148       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
149   EncodeDecode(set);
150   set.objc_class_selectors.Clear();
151   // Make sure an IndexSet with only items in IndexSet::globals can
152   // be encoded and decoded correctly.
153   set.globals.Insert(
154       ConstString("a"),
155       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
156   EncodeDecode(set);
157   set.globals.Clear();
158   // Make sure an IndexSet with only items in IndexSet::types can
159   // be encoded and decoded correctly.
160   set.types.Insert(
161       ConstString("a"),
162       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
163   EncodeDecode(set);
164   set.types.Clear();
165   // Make sure an IndexSet with only items in IndexSet::namespaces can
166   // be encoded and decoded correctly.
167   set.namespaces.Insert(
168       ConstString("a"),
169       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
170   EncodeDecode(set);
171   set.namespaces.Clear();
172   // Make sure that an IndexSet with item in all NameToDIE maps can be
173   // be encoded and decoded correctly.
174   set.function_basenames.Insert(
175       ConstString("a"),
176       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
177   set.function_fullnames.Insert(
178       ConstString("b"),
179       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
180   set.function_methods.Insert(
181       ConstString("c"),
182       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
183   set.function_selectors.Insert(
184       ConstString("d"),
185       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
186   set.objc_class_selectors.Insert(
187       ConstString("e"),
188       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
189   set.globals.Insert(
190       ConstString("f"),
191       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
192   set.types.Insert(
193       ConstString("g"),
194       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
195   set.namespaces.Insert(
196       ConstString("h"),
197       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
198   EncodeDecode(set);
199 }
200 
EncodeDecode(const CacheSignature & object,ByteOrder byte_order,bool encode_result)201 static void EncodeDecode(const CacheSignature &object, ByteOrder byte_order,
202                          bool encode_result) {
203   const uint8_t addr_size = 8;
204   DataEncoder encoder(byte_order, addr_size);
205   EXPECT_EQ(encode_result, object.Encode(encoder));
206   if (!encode_result)
207     return;
208   llvm::ArrayRef<uint8_t> bytes = encoder.GetData();
209   DataExtractor data(bytes.data(), bytes.size(), byte_order, addr_size);
210   offset_t data_offset = 0;
211   CacheSignature decoded_object;
212   EXPECT_TRUE(decoded_object.Decode(data, &data_offset));
213   EXPECT_EQ(object, decoded_object);
214 }
215 
EncodeDecode(const CacheSignature & object,bool encode_result)216 static void EncodeDecode(const CacheSignature &object, bool encode_result) {
217   EncodeDecode(object, eByteOrderLittle, encode_result);
218   EncodeDecode(object, eByteOrderBig, encode_result);
219 }
220 
TEST(DWARFIndexCachingTest,CacheSignatureTests)221 TEST(DWARFIndexCachingTest, CacheSignatureTests) {
222   CacheSignature sig;
223   // A cache signature is only considered valid if it has a UUID.
224   sig.m_mod_time = 0x12345678;
225   EXPECT_FALSE(sig.IsValid());
226   EncodeDecode(sig, /*encode_result=*/false);
227   sig.Clear();
228 
229   sig.m_obj_mod_time = 0x12345678;
230   EXPECT_FALSE(sig.IsValid());
231   EncodeDecode(sig, /*encode_result=*/false);
232   sig.Clear();
233 
234   sig.m_uuid = UUID::fromData("@\x00\x11\x22\x33\x44\x55\x66\x77", 8);
235   EXPECT_TRUE(sig.IsValid());
236   EncodeDecode(sig, /*encode_result=*/true);
237   sig.m_mod_time = 0x12345678;
238   EXPECT_TRUE(sig.IsValid());
239   EncodeDecode(sig, /*encode_result=*/true);
240   sig.m_obj_mod_time = 0x456789ab;
241   EXPECT_TRUE(sig.IsValid());
242   EncodeDecode(sig, /*encode_result=*/true);
243   sig.m_mod_time = llvm::None;
244   EXPECT_TRUE(sig.IsValid());
245   EncodeDecode(sig, /*encode_result=*/true);
246 
247   // Recent changes do not allow cache signatures with only a modification time
248   // or object modification time, so make sure if we try to decode such a cache
249   // file that we fail. This verifies that if we try to load an previously
250   // valid cache file where the signature is insufficient, that we will fail to
251   // decode and load these cache files.
252   DataEncoder encoder(eByteOrderLittle, /*addr_size=*/8);
253   encoder.AppendU8(2); // eSignatureModTime
254   encoder.AppendU32(0x12345678);
255   encoder.AppendU8(255); // eSignatureEnd
256 
257   llvm::ArrayRef<uint8_t> bytes = encoder.GetData();
258   DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle,
259                      /*addr_size=*/8);
260   offset_t data_offset = 0;
261 
262   // Make sure we fail to decode a CacheSignature with only a mod time
263   EXPECT_FALSE(sig.Decode(data, &data_offset));
264 
265   // Change the signature data to contain only a eSignatureObjectModTime and
266   // make sure decoding fails as well.
267   encoder.PutU8(/*offset=*/0, 3); // eSignatureObjectModTime
268   data_offset = 0;
269   EXPECT_FALSE(sig.Decode(data, &data_offset));
270 
271 }
272