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 if (auto EC = Strings.initialize(Reader)) { 46 return joinErrors(std::move(EC), 47 make_error<RawError>(raw_error_code::corrupt_file, 48 "Invalid hash table byte length")); 49 } 50 51 assert(Reader.bytesRemaining() == 0); 52 return Error::success(); 53 } 54 55 Error PDBStringTable::readHashTable(BinaryStreamReader &Reader) { 56 const support::ulittle32_t *HashCount; 57 if (auto EC = Reader.readObject(HashCount)) 58 return EC; 59 60 if (auto EC = Reader.readArray(IDs, *HashCount)) { 61 return joinErrors(std::move(EC), 62 make_error<RawError>(raw_error_code::corrupt_file, 63 "Could not read bucket array")); 64 } 65 66 return Error::success(); 67 } 68 69 Error PDBStringTable::readEpilogue(BinaryStreamReader &Reader) { 70 if (auto EC = Reader.readInteger(NameCount)) 71 return EC; 72 73 assert(Reader.bytesRemaining() == 0); 74 return Error::success(); 75 } 76 77 Error PDBStringTable::reload(BinaryStreamReader &Reader) { 78 79 BinaryStreamReader SectionReader; 80 81 std::tie(SectionReader, Reader) = Reader.split(sizeof(PDBStringTableHeader)); 82 if (auto EC = readHeader(SectionReader)) 83 return EC; 84 85 std::tie(SectionReader, Reader) = Reader.split(Header->ByteSize); 86 if (auto EC = readStrings(SectionReader)) 87 return EC; 88 89 // We don't know how long the hash table is until we parse it, so let the 90 // function responsible for doing that figure it out. 91 if (auto EC = readHashTable(Reader)) 92 return EC; 93 94 std::tie(SectionReader, Reader) = Reader.split(sizeof(uint32_t)); 95 if (auto EC = readEpilogue(SectionReader)) 96 return EC; 97 98 assert(Reader.bytesRemaining() == 0); 99 return Error::success(); 100 } 101 102 StringRef PDBStringTable::getStringForID(uint32_t ID) const { 103 return Strings.getString(ID); 104 } 105 106 uint32_t PDBStringTable::getIDForString(StringRef Str) const { 107 uint32_t Hash = 108 (Header->HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str); 109 size_t Count = IDs.size(); 110 uint32_t Start = Hash % Count; 111 for (size_t I = 0; I < Count; ++I) { 112 // The hash is just a starting point for the search, but if it 113 // doesn't work we should find the string no matter what, because 114 // we iterate the entire array. 115 uint32_t Index = (Start + I) % Count; 116 117 uint32_t ID = IDs[Index]; 118 StringRef S = getStringForID(ID); 119 if (S == Str) 120 return ID; 121 } 122 // IDs[0] contains the ID of the "invalid" entry. 123 return IDs[0]; 124 } 125 126 FixedStreamArray<support::ulittle32_t> PDBStringTable::name_ids() const { 127 return IDs; 128 } 129