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