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