1 //===-- DWARFIndexCachingTest.cpp -------------------------------------=---===//
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
7 //===----------------------------------------------------------------------===//
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"
23 using namespace lldb_private
;
24 using namespace lldb_private::plugin::dwarf
;
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
));
36 static void EncodeDecode(const DIERef
&object
) {
37 EncodeDecode(object
, eByteOrderLittle
);
38 EncodeDecode(object
, eByteOrderBig
);
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));
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));
56 DIERef(100, DIERef::Section::DebugInfo
, DIERef::k_die_offset_mask
- 1));
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
,
65 EncodeDecode(DIERef(DIERef::k_file_index_mask
, DIERef::Section::DebugTypes
,
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
;
75 object
.Encode(encoder
, const_strtab
);
77 llvm::ArrayRef
<uint8_t> bytes
= encoder
.GetData();
78 DataExtractor
data(bytes
.data(), bytes
.size(), byte_order
, addr_size
);
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);
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
);
94 static void EncodeDecode(const NameToDIE
&object
) {
95 EncodeDecode(object
, eByteOrderLittle
);
96 EncodeDecode(object
, eByteOrderBig
);
99 TEST(DWARFIndexCachingTest
, NameToDIEEncodeDecode
) {
101 // Make sure an empty NameToDIE map encodes and decodes correctly.
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));
108 // Make sure a valid NameToDIE map encodes and decodes correctly.
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
);
126 static void EncodeDecode(const ManualDWARFIndex::IndexSet
&object
) {
127 EncodeDecode(object
, eByteOrderLittle
);
128 EncodeDecode(object
, eByteOrderBig
);
131 TEST(DWARFIndexCachingTest
, ManualDWARFIndexIndexSetEncodeDecode
) {
132 ManualDWARFIndex::IndexSet set
;
133 // Make sure empty IndexSet can be encoded and decoded correctly
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(
141 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
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(
148 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
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(
155 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
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(
162 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
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(
169 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
171 set
.objc_class_selectors
.Clear();
172 // Make sure an IndexSet with only items in IndexSet::globals can
173 // be encoded and decoded correctly.
176 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
179 // Make sure an IndexSet with only items in IndexSet::types can
180 // be encoded and decoded correctly.
183 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
186 // Make sure an IndexSet with only items in IndexSet::namespaces can
187 // be encoded and decoded correctly.
188 set
.namespaces
.Insert(
190 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
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(
197 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
198 set
.function_fullnames
.Insert(
200 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
201 set
.function_methods
.Insert(
203 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
204 set
.function_selectors
.Insert(
206 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
207 set
.objc_class_selectors
.Insert(
209 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
212 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
215 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
216 set
.namespaces
.Insert(
218 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
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
));
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
);
237 static void EncodeDecode(const CacheSignature
&object
, bool encode_result
) {
238 EncodeDecode(object
, eByteOrderLittle
, encode_result
);
239 EncodeDecode(object
, eByteOrderBig
, encode_result
);
242 TEST(DWARFIndexCachingTest
, CacheSignatureTests
) {
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);
250 sig
.m_obj_mod_time
= 0x12345678;
251 EXPECT_FALSE(sig
.IsValid());
252 EncodeDecode(sig
, /*encode_result=*/false);
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);
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
278 llvm::ArrayRef
<uint8_t> bytes
= encoder
.GetData();
279 DataExtractor
data(bytes
.data(), bytes
.size(), eByteOrderLittle
,
281 offset_t data_offset
= 0;
283 // Make sure we fail to decode a CacheSignature with only a mod time
284 EXPECT_FALSE(sig
.Decode(data
, &data_offset
));
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
290 EXPECT_FALSE(sig
.Decode(data
, &data_offset
));