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