291 lines · cpp
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-exception6//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, eByteOrderLittle);38 EncodeDecode(object, eByteOrderBig);39}40 41TEST(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));47}48 49TEST(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));55 EncodeDecode(56 DIERef(100, DIERef::Section::DebugInfo, DIERef::k_die_offset_mask - 1));57 EncodeDecode(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,64 0x11223344));65 EncodeDecode(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, 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(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, &data_offset, strtab_reader);91 EXPECT_EQ(object, decoded_object);92}93 94static void EncodeDecode(const NameToDIE &object) {95 EncodeDecode(object, eByteOrderLittle);96 EncodeDecode(object, eByteOrderBig);97}98 99TEST(DWARFIndexCachingTest, NameToDIEEncodeDecode) {100 NameToDIE map;101 // Make sure an empty NameToDIE map encodes and decodes correctly.102 EncodeDecode(map);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));107 map.Finalize();108 // Make sure a valid NameToDIE map encodes and decodes correctly.109 EncodeDecode(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(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, eByteOrderLittle);126 EncodeDecode(object, eByteOrderBig);127}128 129TEST(DWARFIndexCachingTest, ManualDWARFIndexIndexSetEncodeDecode) {130 IndexSet<NameToDIE> set;131 // Make sure empty IndexSet can be encoded and decoded correctly132 EncodeDecode(set);133 134 dw_offset_t die_offset = 0;135 // Make sure an IndexSet with only items in IndexSet::function_basenames can136 // be encoded and decoded correctly.137 set.function_basenames.Insert(138 ConstString("a"),139 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));140 EncodeDecode(set);141 set.function_basenames.Clear();142 // Make sure an IndexSet with only items in IndexSet::function_fullnames can143 // be encoded and decoded correctly.144 set.function_fullnames.Insert(145 ConstString("a"),146 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));147 EncodeDecode(set);148 set.function_fullnames.Clear();149 // Make sure an IndexSet with only items in IndexSet::function_methods can150 // be encoded and decoded correctly.151 set.function_methods.Insert(152 ConstString("a"),153 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));154 EncodeDecode(set);155 set.function_methods.Clear();156 // Make sure an IndexSet with only items in IndexSet::function_selectors can157 // be encoded and decoded correctly.158 set.function_selectors.Insert(159 ConstString("a"),160 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));161 EncodeDecode(set);162 set.function_selectors.Clear();163 // Make sure an IndexSet with only items in IndexSet::objc_class_selectors can164 // be encoded and decoded correctly.165 set.objc_class_selectors.Insert(166 ConstString("a"),167 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));168 EncodeDecode(set);169 set.objc_class_selectors.Clear();170 // Make sure an IndexSet with only items in IndexSet::globals can171 // be encoded and decoded correctly.172 set.globals.Insert(173 ConstString("a"),174 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));175 EncodeDecode(set);176 set.globals.Clear();177 // Make sure an IndexSet with only items in IndexSet::types can178 // be encoded and decoded correctly.179 set.types.Insert(180 ConstString("a"),181 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));182 EncodeDecode(set);183 set.types.Clear();184 // Make sure an IndexSet with only items in IndexSet::namespaces can185 // be encoded and decoded correctly.186 set.namespaces.Insert(187 ConstString("a"),188 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));189 EncodeDecode(set);190 set.namespaces.Clear();191 // Make sure that an IndexSet with item in all NameToDIE maps can be192 // be encoded and decoded correctly.193 set.function_basenames.Insert(194 ConstString("a"),195 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));196 set.function_fullnames.Insert(197 ConstString("b"),198 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));199 set.function_methods.Insert(200 ConstString("c"),201 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));202 set.function_selectors.Insert(203 ConstString("d"),204 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));205 set.objc_class_selectors.Insert(206 ConstString("e"),207 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));208 set.globals.Insert(209 ConstString("f"),210 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));211 set.types.Insert(212 ConstString("g"),213 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));214 set.namespaces.Insert(215 ConstString("h"),216 DIERef(std::nullopt, DIERef::Section::DebugInfo, ++die_offset));217 EncodeDecode(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, eByteOrderLittle, encode_result);237 EncodeDecode(object, 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(sig, /*encode_result=*/false);246 sig.Clear();247 248 sig.m_obj_mod_time = 0x12345678;249 EXPECT_FALSE(sig.IsValid());250 EncodeDecode(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(sig, /*encode_result=*/true);256 sig.m_mod_time = 0x12345678;257 EXPECT_TRUE(sig.IsValid());258 EncodeDecode(sig, /*encode_result=*/true);259 sig.m_obj_mod_time = 0x456789ab;260 EXPECT_TRUE(sig.IsValid());261 EncodeDecode(sig, /*encode_result=*/true);262 sig.m_mod_time = std::nullopt;263 EXPECT_TRUE(sig.IsValid());264 EncodeDecode(sig, /*encode_result=*/true);265 266 // Recent changes do not allow cache signatures with only a modification time267 // or object modification time, so make sure if we try to decode such a cache268 // file that we fail. This verifies that if we try to load an previously269 // valid cache file where the signature is insufficient, that we will fail to270 // decode and load these cache files.271 DataEncoder encoder(eByteOrderLittle, /*addr_size=*/8);272 encoder.AppendU8(2); // eSignatureModTime273 encoder.AppendU32(0x12345678);274 encoder.AppendU8(255); // eSignatureEnd275 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 time282 EXPECT_FALSE(sig.Decode(data, &data_offset));283 284 // Change the signature data to contain only a eSignatureObjectModTime and285 // make sure decoding fails as well.286 encoder.PutU8(/*offset=*/0, 3); // eSignatureObjectModTime287 data_offset = 0;288 EXPECT_FALSE(sig.Decode(data, &data_offset));289 290}291