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
;
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
));
35 static void EncodeDecode(const DIERef
&object
) {
36 EncodeDecode(object
, eByteOrderLittle
);
37 EncodeDecode(object
, eByteOrderBig
);
40 TEST(DWARFIndexCachingTest
, DIERefEncodeDecode
) {
41 // Tests DIERef::Encode(...) and DIERef::Decode(...)
42 EncodeDecode(DIERef(std::nullopt
, DIERef::Section::DebugInfo
, 0x11223344));
43 EncodeDecode(DIERef(std::nullopt
, DIERef::Section::DebugTypes
, 0x11223344));
44 EncodeDecode(DIERef(100, DIERef::Section::DebugInfo
, 0x11223344));
45 EncodeDecode(DIERef(200, DIERef::Section::DebugTypes
, 0x11223344));
48 TEST(DWARFIndexCachingTest
, DIERefEncodeDecodeMax
) {
49 // Tests DIERef::Encode(...) and DIERef::Decode(...)
50 EncodeDecode(DIERef(std::nullopt
, DIERef::Section::DebugInfo
,
51 DIERef::k_die_offset_mask
- 1));
52 EncodeDecode(DIERef(std::nullopt
, DIERef::Section::DebugTypes
,
53 DIERef::k_die_offset_mask
- 1));
55 DIERef(100, DIERef::Section::DebugInfo
, DIERef::k_die_offset_mask
- 1));
57 DIERef(200, DIERef::Section::DebugTypes
, DIERef::k_die_offset_mask
- 1));
58 EncodeDecode(DIERef(DIERef::k_file_index_mask
, DIERef::Section::DebugInfo
,
59 DIERef::k_file_index_mask
));
60 EncodeDecode(DIERef(DIERef::k_file_index_mask
, DIERef::Section::DebugTypes
,
61 DIERef::k_file_index_mask
));
62 EncodeDecode(DIERef(DIERef::k_file_index_mask
, DIERef::Section::DebugInfo
,
64 EncodeDecode(DIERef(DIERef::k_file_index_mask
, DIERef::Section::DebugTypes
,
68 static void EncodeDecode(const NameToDIE
&object
, ByteOrder byte_order
) {
69 const uint8_t addr_size
= 8;
70 DataEncoder
encoder(byte_order
, addr_size
);
71 DataEncoder
strtab_encoder(byte_order
, addr_size
);
72 ConstStringTable const_strtab
;
74 object
.Encode(encoder
, const_strtab
);
76 llvm::ArrayRef
<uint8_t> bytes
= encoder
.GetData();
77 DataExtractor
data(bytes
.data(), bytes
.size(), byte_order
, addr_size
);
79 const_strtab
.Encode(strtab_encoder
);
80 llvm::ArrayRef
<uint8_t> strtab_bytes
= strtab_encoder
.GetData();
81 DataExtractor
strtab_data(strtab_bytes
.data(), strtab_bytes
.size(),
82 byte_order
, addr_size
);
83 StringTableReader strtab_reader
;
84 offset_t strtab_data_offset
= 0;
85 ASSERT_EQ(strtab_reader
.Decode(strtab_data
, &strtab_data_offset
), true);
87 NameToDIE decoded_object
;
88 offset_t data_offset
= 0;
89 decoded_object
.Decode(data
, &data_offset
, strtab_reader
);
90 EXPECT_EQ(object
, decoded_object
);
93 static void EncodeDecode(const NameToDIE
&object
) {
94 EncodeDecode(object
, eByteOrderLittle
);
95 EncodeDecode(object
, eByteOrderBig
);
98 TEST(DWARFIndexCachingTest
, NameToDIEEncodeDecode
) {
100 // Make sure an empty NameToDIE map encodes and decodes correctly.
102 map
.Insert(ConstString("hello"),
103 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, 0x11223344));
104 map
.Insert(ConstString("workd"),
105 DIERef(100, DIERef::Section::DebugInfo
, 0x11223344));
107 // Make sure a valid NameToDIE map encodes and decodes correctly.
111 static void EncodeDecode(const ManualDWARFIndex::IndexSet
&object
,
112 ByteOrder byte_order
) {
113 const uint8_t addr_size
= 8;
114 DataEncoder
encoder(byte_order
, addr_size
);
115 DataEncoder
strtab_encoder(byte_order
, addr_size
);
116 object
.Encode(encoder
);
117 llvm::ArrayRef
<uint8_t> bytes
= encoder
.GetData();
118 DataExtractor
data(bytes
.data(), bytes
.size(), byte_order
, addr_size
);
119 ManualDWARFIndex::IndexSet decoded_object
;
120 offset_t data_offset
= 0;
121 decoded_object
.Decode(data
, &data_offset
);
122 EXPECT_TRUE(object
== decoded_object
);
125 static void EncodeDecode(const ManualDWARFIndex::IndexSet
&object
) {
126 EncodeDecode(object
, eByteOrderLittle
);
127 EncodeDecode(object
, eByteOrderBig
);
130 TEST(DWARFIndexCachingTest
, ManualDWARFIndexIndexSetEncodeDecode
) {
131 ManualDWARFIndex::IndexSet set
;
132 // Make sure empty IndexSet can be encoded and decoded correctly
135 dw_offset_t die_offset
= 0;
136 // Make sure an IndexSet with only items in IndexSet::function_basenames can
137 // be encoded and decoded correctly.
138 set
.function_basenames
.Insert(
140 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
142 set
.function_basenames
.Clear();
143 // Make sure an IndexSet with only items in IndexSet::function_fullnames can
144 // be encoded and decoded correctly.
145 set
.function_fullnames
.Insert(
147 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
149 set
.function_fullnames
.Clear();
150 // Make sure an IndexSet with only items in IndexSet::function_methods can
151 // be encoded and decoded correctly.
152 set
.function_methods
.Insert(
154 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
156 set
.function_methods
.Clear();
157 // Make sure an IndexSet with only items in IndexSet::function_selectors can
158 // be encoded and decoded correctly.
159 set
.function_selectors
.Insert(
161 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
163 set
.function_selectors
.Clear();
164 // Make sure an IndexSet with only items in IndexSet::objc_class_selectors can
165 // be encoded and decoded correctly.
166 set
.objc_class_selectors
.Insert(
168 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
170 set
.objc_class_selectors
.Clear();
171 // Make sure an IndexSet with only items in IndexSet::globals can
172 // be encoded and decoded correctly.
175 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
178 // Make sure an IndexSet with only items in IndexSet::types can
179 // be encoded and decoded correctly.
182 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
185 // Make sure an IndexSet with only items in IndexSet::namespaces can
186 // be encoded and decoded correctly.
187 set
.namespaces
.Insert(
189 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
191 set
.namespaces
.Clear();
192 // Make sure that an IndexSet with item in all NameToDIE maps can be
193 // be encoded and decoded correctly.
194 set
.function_basenames
.Insert(
196 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
197 set
.function_fullnames
.Insert(
199 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
200 set
.function_methods
.Insert(
202 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
203 set
.function_selectors
.Insert(
205 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
206 set
.objc_class_selectors
.Insert(
208 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
211 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
214 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
215 set
.namespaces
.Insert(
217 DIERef(std::nullopt
, DIERef::Section::DebugInfo
, ++die_offset
));
221 static void EncodeDecode(const CacheSignature
&object
, ByteOrder byte_order
,
222 bool encode_result
) {
223 const uint8_t addr_size
= 8;
224 DataEncoder
encoder(byte_order
, addr_size
);
225 EXPECT_EQ(encode_result
, object
.Encode(encoder
));
228 llvm::ArrayRef
<uint8_t> bytes
= encoder
.GetData();
229 DataExtractor
data(bytes
.data(), bytes
.size(), byte_order
, addr_size
);
230 offset_t data_offset
= 0;
231 CacheSignature decoded_object
;
232 EXPECT_TRUE(decoded_object
.Decode(data
, &data_offset
));
233 EXPECT_EQ(object
, decoded_object
);
236 static void EncodeDecode(const CacheSignature
&object
, bool encode_result
) {
237 EncodeDecode(object
, eByteOrderLittle
, encode_result
);
238 EncodeDecode(object
, eByteOrderBig
, encode_result
);
241 TEST(DWARFIndexCachingTest
, CacheSignatureTests
) {
243 // A cache signature is only considered valid if it has a UUID.
244 sig
.m_mod_time
= 0x12345678;
245 EXPECT_FALSE(sig
.IsValid());
246 EncodeDecode(sig
, /*encode_result=*/false);
249 sig
.m_obj_mod_time
= 0x12345678;
250 EXPECT_FALSE(sig
.IsValid());
251 EncodeDecode(sig
, /*encode_result=*/false);
254 sig
.m_uuid
= UUID("@\x00\x11\x22\x33\x44\x55\x66\x77", 8);
255 EXPECT_TRUE(sig
.IsValid());
256 EncodeDecode(sig
, /*encode_result=*/true);
257 sig
.m_mod_time
= 0x12345678;
258 EXPECT_TRUE(sig
.IsValid());
259 EncodeDecode(sig
, /*encode_result=*/true);
260 sig
.m_obj_mod_time
= 0x456789ab;
261 EXPECT_TRUE(sig
.IsValid());
262 EncodeDecode(sig
, /*encode_result=*/true);
263 sig
.m_mod_time
= std::nullopt
;
264 EXPECT_TRUE(sig
.IsValid());
265 EncodeDecode(sig
, /*encode_result=*/true);
267 // Recent changes do not allow cache signatures with only a modification time
268 // or object modification time, so make sure if we try to decode such a cache
269 // file that we fail. This verifies that if we try to load an previously
270 // valid cache file where the signature is insufficient, that we will fail to
271 // decode and load these cache files.
272 DataEncoder
encoder(eByteOrderLittle
, /*addr_size=*/8);
273 encoder
.AppendU8(2); // eSignatureModTime
274 encoder
.AppendU32(0x12345678);
275 encoder
.AppendU8(255); // eSignatureEnd
277 llvm::ArrayRef
<uint8_t> bytes
= encoder
.GetData();
278 DataExtractor
data(bytes
.data(), bytes
.size(), eByteOrderLittle
,
280 offset_t data_offset
= 0;
282 // Make sure we fail to decode a CacheSignature with only a mod time
283 EXPECT_FALSE(sig
.Decode(data
, &data_offset
));
285 // Change the signature data to contain only a eSignatureObjectModTime and
286 // make sure decoding fails as well.
287 encoder
.PutU8(/*offset=*/0, 3); // eSignatureObjectModTime
289 EXPECT_FALSE(sig
.Decode(data
, &data_offset
));