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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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