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