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
22using namespace lldb;
23using namespace lldb_private;
24using namespace lldb_private::plugin::dwarf;
25
26static 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
36static void EncodeDecode(const DIERef &object) {
37 EncodeDecode(object, byte_order: eByteOrderLittle);
38 EncodeDecode(object, byte_order: eByteOrderBig);
39}
40
41TEST(DWARFIndexCachingTest, DIERefEncodeDecode) {
42 // Tests DIERef::Encode(...) and DIERef::Decode(...)
43 EncodeDecode(object: DIERef(std::nullopt, DIERef::Section::DebugInfo, 0x11223344));
44 EncodeDecode(object: DIERef(std::nullopt, DIERef::Section::DebugTypes, 0x11223344));
45 EncodeDecode(object: DIERef(100, DIERef::Section::DebugInfo, 0x11223344));
46 EncodeDecode(object: DIERef(200, DIERef::Section::DebugTypes, 0x11223344));
47}
48
49TEST(DWARFIndexCachingTest, DIERefEncodeDecodeMax) {
50 // Tests DIERef::Encode(...) and DIERef::Decode(...)
51 EncodeDecode(object: DIERef(std::nullopt, DIERef::Section::DebugInfo,
52 DIERef::k_die_offset_mask - 1));
53 EncodeDecode(object: DIERef(std::nullopt, DIERef::Section::DebugTypes,
54 DIERef::k_die_offset_mask - 1));
55 EncodeDecode(
56 object: DIERef(100, DIERef::Section::DebugInfo, DIERef::k_die_offset_mask - 1));
57 EncodeDecode(
58 object: DIERef(200, DIERef::Section::DebugTypes, DIERef::k_die_offset_mask - 1));
59 EncodeDecode(object: DIERef(DIERef::k_file_index_mask, DIERef::Section::DebugInfo,
60 DIERef::k_file_index_mask));
61 EncodeDecode(object: DIERef(DIERef::k_file_index_mask, DIERef::Section::DebugTypes,
62 DIERef::k_file_index_mask));
63 EncodeDecode(object: DIERef(DIERef::k_file_index_mask, DIERef::Section::DebugInfo,
64 0x11223344));
65 EncodeDecode(object: DIERef(DIERef::k_file_index_mask, DIERef::Section::DebugTypes,
66 0x11223344));
67}
68
69static 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, strtab&: 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(encoder&: 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, offset_ptr: &data_offset, strtab: strtab_reader);
91 EXPECT_EQ(object, decoded_object);
92}
93
94static void EncodeDecode(const NameToDIE &object) {
95 EncodeDecode(object, byte_order: eByteOrderLittle);
96 EncodeDecode(object, byte_order: eByteOrderBig);
97}
98
99TEST(DWARFIndexCachingTest, NameToDIEEncodeDecode) {
100 NameToDIE map;
101 // Make sure an empty NameToDIE map encodes and decodes correctly.
102 EncodeDecode(object: map);
103 map.Insert(name: ConstString("hello"),
104 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, 0x11223344));
105 map.Insert(name: ConstString("workd"),
106 die_ref: DIERef(100, DIERef::Section::DebugInfo, 0x11223344));
107 map.Finalize();
108 // Make sure a valid NameToDIE map encodes and decodes correctly.
109 EncodeDecode(object: map);
110}
111
112static 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, offset_ptr: &data_offset);
123 EXPECT_TRUE(object == decoded_object);
124}
125
126static void EncodeDecode(const ManualDWARFIndex::IndexSet &object) {
127 EncodeDecode(object, byte_order: eByteOrderLittle);
128 EncodeDecode(object, byte_order: eByteOrderBig);
129}
130
131TEST(DWARFIndexCachingTest, ManualDWARFIndexIndexSetEncodeDecode) {
132 ManualDWARFIndex::IndexSet set;
133 // Make sure empty IndexSet can be encoded and decoded correctly
134 EncodeDecode(object: 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 name: ConstString("a"),
141 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
142 EncodeDecode(object: 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 name: ConstString("a"),
148 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
149 EncodeDecode(object: 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 name: ConstString("a"),
155 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
156 EncodeDecode(object: 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 name: ConstString("a"),
162 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
163 EncodeDecode(object: 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 name: ConstString("a"),
169 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
170 EncodeDecode(object: 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 name: ConstString("a"),
176 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
177 EncodeDecode(object: 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 name: ConstString("a"),
183 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
184 EncodeDecode(object: 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 name: ConstString("a"),
190 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
191 EncodeDecode(object: 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 name: ConstString("a"),
197 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
198 set.function_fullnames.Insert(
199 name: ConstString("b"),
200 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
201 set.function_methods.Insert(
202 name: ConstString("c"),
203 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
204 set.function_selectors.Insert(
205 name: ConstString("d"),
206 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
207 set.objc_class_selectors.Insert(
208 name: ConstString("e"),
209 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
210 set.globals.Insert(
211 name: ConstString("f"),
212 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
213 set.types.Insert(
214 name: ConstString("g"),
215 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
216 set.namespaces.Insert(
217 name: ConstString("h"),
218 die_ref: DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));
219 EncodeDecode(object: set);
220}
221
222static 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
237static void EncodeDecode(const CacheSignature &object, bool encode_result) {
238 EncodeDecode(object, byte_order: eByteOrderLittle, encode_result);
239 EncodeDecode(object, byte_order: eByteOrderBig, encode_result);
240}
241
242TEST(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(object: sig, /*encode_result=*/false);
248 sig.Clear();
249
250 sig.m_obj_mod_time = 0x12345678;
251 EXPECT_FALSE(sig.IsValid());
252 EncodeDecode(object: 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(object: sig, /*encode_result=*/true);
258 sig.m_mod_time = 0x12345678;
259 EXPECT_TRUE(sig.IsValid());
260 EncodeDecode(object: sig, /*encode_result=*/true);
261 sig.m_obj_mod_time = 0x456789ab;
262 EXPECT_TRUE(sig.IsValid());
263 EncodeDecode(object: sig, /*encode_result=*/true);
264 sig.m_mod_time = std::nullopt;
265 EXPECT_TRUE(sig.IsValid());
266 EncodeDecode(object: 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(value: 2); // eSignatureModTime
275 encoder.AppendU32(value: 0x12345678);
276 encoder.AppendU8(value: 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, value: 3); // eSignatureObjectModTime
289 data_offset = 0;
290 EXPECT_FALSE(sig.Decode(data, &data_offset));
291
292}
293

source code of lldb/unittests/SymbolFile/DWARF/DWARFIndexCachingTest.cpp