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 
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 
35 static void EncodeDecode(const DIERef &object) {
36   EncodeDecode(object, eByteOrderLittle);
37   EncodeDecode(object, eByteOrderBig);
38 }
39 
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 
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_TRUE(object == decoded_object);
71 }
72 
73 static void EncodeDecode(const NameToDIE &object) {
74   EncodeDecode(object, eByteOrderLittle);
75   EncodeDecode(object, eByteOrderBig);
76 }
77 
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   // Make sure a valid NameToDIE map encodes and decodes correctly.
87   EncodeDecode(map);
88 }
89 
90 static void EncodeDecode(const ManualDWARFIndex::IndexSet &object,
91                          ByteOrder byte_order) {
92   const uint8_t addr_size = 8;
93   DataEncoder encoder(byte_order, addr_size);
94   DataEncoder strtab_encoder(byte_order, addr_size);
95   object.Encode(encoder);
96   llvm::ArrayRef<uint8_t> bytes = encoder.GetData();
97   DataExtractor data(bytes.data(), bytes.size(), byte_order, addr_size);
98   ManualDWARFIndex::IndexSet decoded_object;
99   offset_t data_offset = 0;
100   decoded_object.Decode(data, &data_offset);
101   EXPECT_TRUE(object == decoded_object);
102 }
103 
104 static void EncodeDecode(const ManualDWARFIndex::IndexSet &object) {
105   EncodeDecode(object, eByteOrderLittle);
106   EncodeDecode(object, eByteOrderBig);
107 }
108 
109 TEST(DWARFIndexCachingTest, ManualDWARFIndexIndexSetEncodeDecode) {
110   ManualDWARFIndex::IndexSet set;
111   // Make sure empty IndexSet can be encoded and decoded correctly
112   EncodeDecode(set);
113 
114   dw_offset_t die_offset = 0;
115   // Make sure an IndexSet with only items in IndexSet::function_basenames can
116   // be encoded and decoded correctly.
117   set.function_basenames.Insert(
118       ConstString("a"),
119       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
120   EncodeDecode(set);
121   set.function_basenames.Clear();
122   // Make sure an IndexSet with only items in IndexSet::function_fullnames can
123   // be encoded and decoded correctly.
124   set.function_fullnames.Insert(
125       ConstString("a"),
126       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
127   EncodeDecode(set);
128   set.function_fullnames.Clear();
129   // Make sure an IndexSet with only items in IndexSet::function_methods can
130   // be encoded and decoded correctly.
131   set.function_methods.Insert(
132       ConstString("a"),
133       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
134   EncodeDecode(set);
135   set.function_methods.Clear();
136   // Make sure an IndexSet with only items in IndexSet::function_selectors can
137   // be encoded and decoded correctly.
138   set.function_selectors.Insert(
139       ConstString("a"),
140       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
141   EncodeDecode(set);
142   set.function_selectors.Clear();
143   // Make sure an IndexSet with only items in IndexSet::objc_class_selectors can
144   // be encoded and decoded correctly.
145   set.objc_class_selectors.Insert(
146       ConstString("a"),
147       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
148   EncodeDecode(set);
149   set.objc_class_selectors.Clear();
150   // Make sure an IndexSet with only items in IndexSet::globals can
151   // be encoded and decoded correctly.
152   set.globals.Insert(
153       ConstString("a"),
154       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
155   EncodeDecode(set);
156   set.globals.Clear();
157   // Make sure an IndexSet with only items in IndexSet::types can
158   // be encoded and decoded correctly.
159   set.types.Insert(
160       ConstString("a"),
161       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
162   EncodeDecode(set);
163   set.types.Clear();
164   // Make sure an IndexSet with only items in IndexSet::namespaces can
165   // be encoded and decoded correctly.
166   set.namespaces.Insert(
167       ConstString("a"),
168       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
169   EncodeDecode(set);
170   set.namespaces.Clear();
171   // Make sure that an IndexSet with item in all NameToDIE maps can be
172   // be encoded and decoded correctly.
173   set.function_basenames.Insert(
174       ConstString("a"),
175       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
176   set.function_fullnames.Insert(
177       ConstString("b"),
178       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
179   set.function_methods.Insert(
180       ConstString("c"),
181       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
182   set.function_selectors.Insert(
183       ConstString("d"),
184       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
185   set.objc_class_selectors.Insert(
186       ConstString("e"),
187       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
188   set.globals.Insert(
189       ConstString("f"),
190       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
191   set.types.Insert(
192       ConstString("g"),
193       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
194   set.namespaces.Insert(
195       ConstString("h"),
196       DIERef(llvm::None, DIERef::Section::DebugInfo, ++die_offset));
197   EncodeDecode(set);
198 }
199 
200 static void EncodeDecode(const CacheSignature &object, ByteOrder byte_order,
201                          bool encode_result) {
202   const uint8_t addr_size = 8;
203   DataEncoder encoder(byte_order, addr_size);
204   EXPECT_EQ(encode_result, object.Encode(encoder));
205   if (!encode_result)
206     return;
207   llvm::ArrayRef<uint8_t> bytes = encoder.GetData();
208   DataExtractor data(bytes.data(), bytes.size(), byte_order, addr_size);
209   offset_t data_offset = 0;
210   CacheSignature decoded_object;
211   EXPECT_TRUE(decoded_object.Decode(data, &data_offset));
212   EXPECT_EQ(object, decoded_object);
213 }
214 
215 static void EncodeDecode(const CacheSignature &object, bool encode_result) {
216   EncodeDecode(object, eByteOrderLittle, encode_result);
217   EncodeDecode(object, eByteOrderBig, encode_result);
218 }
219 
220 TEST(DWARFIndexCachingTest, CacheSignatureTests) {
221   CacheSignature sig;
222   // A cache signature is only considered valid if it has a UUID.
223   sig.m_mod_time = 0x12345678;
224   EXPECT_FALSE(sig.IsValid());
225   EncodeDecode(sig, /*encode_result=*/false);
226   sig.Clear();
227 
228   sig.m_obj_mod_time = 0x12345678;
229   EXPECT_FALSE(sig.IsValid());
230   EncodeDecode(sig, /*encode_result=*/false);
231   sig.Clear();
232 
233   sig.m_uuid = UUID::fromData("@\x00\x11\x22\x33\x44\x55\x66\x77", 8);
234   EXPECT_TRUE(sig.IsValid());
235   EncodeDecode(sig, /*encode_result=*/true);
236   sig.m_mod_time = 0x12345678;
237   EXPECT_TRUE(sig.IsValid());
238   EncodeDecode(sig, /*encode_result=*/true);
239   sig.m_obj_mod_time = 0x456789ab;
240   EXPECT_TRUE(sig.IsValid());
241   EncodeDecode(sig, /*encode_result=*/true);
242   sig.m_mod_time = llvm::None;
243   EXPECT_TRUE(sig.IsValid());
244   EncodeDecode(sig, /*encode_result=*/true);
245 
246   // Recent changes do not allow cache signatures with only a modification time
247   // or object modification time, so make sure if we try to decode such a cache
248   // file that we fail. This verifies that if we try to load an previously
249   // valid cache file where the signature is insufficient, that we will fail to
250   // decode and load these cache files.
251   DataEncoder encoder(eByteOrderLittle, /*addr_size=*/8);
252   encoder.AppendU8(2); // eSignatureModTime
253   encoder.AppendU32(0x12345678);
254   encoder.AppendU8(255); // eSignatureEnd
255 
256   llvm::ArrayRef<uint8_t> bytes = encoder.GetData();
257   DataExtractor data(bytes.data(), bytes.size(), eByteOrderLittle,
258                      /*addr_size=*/8);
259   offset_t data_offset = 0;
260 
261   // Make sure we fail to decode a CacheSignature with only a mod time
262   EXPECT_FALSE(sig.Decode(data, &data_offset));
263 
264   // Change the signature data to contain only a eSignatureObjectModTime and
265   // make sure decoding fails as well.
266   encoder.PutU8(/*offset=*/0, 3); // eSignatureObjectModTime
267   data_offset = 0;
268   EXPECT_FALSE(sig.Decode(data, &data_offset));
269 
270 }
271