1 //===- PDBStringTable.cpp - PDB String Table ---------------------*- C++-*-===// 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 "llvm/DebugInfo/PDB/Native/PDBStringTable.h" 10 11 #include "llvm/ADT/ArrayRef.h" 12 #include "llvm/DebugInfo/PDB/Native/Hash.h" 13 #include "llvm/DebugInfo/PDB/Native/RawError.h" 14 #include "llvm/DebugInfo/PDB/Native/RawTypes.h" 15 #include "llvm/Support/BinaryStreamReader.h" 16 #include "llvm/Support/Endian.h" 17 18 using namespace llvm; 19 using namespace llvm::support; 20 using namespace llvm::pdb; 21 22 uint32_t PDBStringTable::getByteSize() const { return Header->ByteSize; } 23 uint32_t PDBStringTable::getNameCount() const { return NameCount; } 24 uint32_t PDBStringTable::getHashVersion() const { return Header->HashVersion; } 25 uint32_t PDBStringTable::getSignature() const { return Header->Signature; } 26 27 Error PDBStringTable::readHeader(BinaryStreamReader &Reader) { 28 if (auto EC = Reader.readObject(Header)) 29 return EC; 30 31 if (Header->Signature != PDBStringTableSignature) 32 return make_error<RawError>(raw_error_code::corrupt_file, 33 "Invalid hash table signature"); 34 if (Header->HashVersion != 1 && Header->HashVersion != 2) 35 return make_error<RawError>(raw_error_code::corrupt_file, 36 "Unsupported hash version"); 37 38 assert(Reader.bytesRemaining() == 0); 39 return Error::success(); 40 } 41 42 Error PDBStringTable::readStrings(BinaryStreamReader &Reader) { 43 BinaryStreamRef Stream; 44 if (auto EC = Reader.readStreamRef(Stream)) 45 return EC; 46 47 if (auto EC = Strings.initialize(Stream)) { 48 return joinErrors(std::move(EC), 49 make_error<RawError>(raw_error_code::corrupt_file, 50 "Invalid hash table byte length")); 51 } 52 53 assert(Reader.bytesRemaining() == 0); 54 return Error::success(); 55 } 56 57 const codeview::DebugStringTableSubsectionRef & 58 PDBStringTable::getStringTable() const { 59 return Strings; 60 } 61 62 Error PDBStringTable::readHashTable(BinaryStreamReader &Reader) { 63 const support::ulittle32_t *HashCount; 64 if (auto EC = Reader.readObject(HashCount)) 65 return EC; 66 67 if (auto EC = Reader.readArray(IDs, *HashCount)) { 68 return joinErrors(std::move(EC), 69 make_error<RawError>(raw_error_code::corrupt_file, 70 "Could not read bucket array")); 71 } 72 73 return Error::success(); 74 } 75 76 Error PDBStringTable::readEpilogue(BinaryStreamReader &Reader) { 77 if (auto EC = Reader.readInteger(NameCount)) 78 return EC; 79 80 assert(Reader.bytesRemaining() == 0); 81 return Error::success(); 82 } 83 84 Error PDBStringTable::reload(BinaryStreamReader &Reader) { 85 86 BinaryStreamReader SectionReader; 87 88 std::tie(SectionReader, Reader) = Reader.split(sizeof(PDBStringTableHeader)); 89 if (auto EC = readHeader(SectionReader)) 90 return EC; 91 92 std::tie(SectionReader, Reader) = Reader.split(Header->ByteSize); 93 if (auto EC = readStrings(SectionReader)) 94 return EC; 95 96 // We don't know how long the hash table is until we parse it, so let the 97 // function responsible for doing that figure it out. 98 if (auto EC = readHashTable(Reader)) 99 return EC; 100 101 std::tie(SectionReader, Reader) = Reader.split(sizeof(uint32_t)); 102 if (auto EC = readEpilogue(SectionReader)) 103 return EC; 104 105 assert(Reader.bytesRemaining() == 0); 106 return Error::success(); 107 } 108 109 Expected<StringRef> PDBStringTable::getStringForID(uint32_t ID) const { 110 return Strings.getString(ID); 111 } 112 113 Expected<uint32_t> PDBStringTable::getIDForString(StringRef Str) const { 114 uint32_t Hash = 115 (Header->HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str); 116 size_t Count = IDs.size(); 117 uint32_t Start = Hash % Count; 118 for (size_t I = 0; I < Count; ++I) { 119 // The hash is just a starting point for the search, but if it 120 // doesn't work we should find the string no matter what, because 121 // we iterate the entire array. 122 uint32_t Index = (Start + I) % Count; 123 124 // If we find 0, it means the item isn't in the hash table. 125 uint32_t ID = IDs[Index]; 126 if (ID == 0) 127 return make_error<RawError>(raw_error_code::no_entry); 128 auto ExpectedStr = getStringForID(ID); 129 if (!ExpectedStr) 130 return ExpectedStr.takeError(); 131 132 if (*ExpectedStr == Str) 133 return ID; 134 } 135 return make_error<RawError>(raw_error_code::no_entry); 136 } 137 138 FixedStreamArray<support::ulittle32_t> PDBStringTable::name_ids() const { 139 return IDs; 140 } 141