1 //===- NameHashTable.cpp - PDB Name Hash 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/Raw/NameHashTable.h" 11 12 #include "llvm/ADT/ArrayRef.h" 13 #include "llvm/DebugInfo/CodeView/StreamReader.h" 14 #include "llvm/DebugInfo/PDB/Raw/Hash.h" 15 #include "llvm/DebugInfo/PDB/Raw/RawError.h" 16 #include "llvm/Support/Endian.h" 17 18 using namespace llvm; 19 using namespace llvm::support; 20 using namespace llvm::pdb; 21 22 NameHashTable::NameHashTable() : Signature(0), HashVersion(0), NameCount(0) {} 23 24 Error NameHashTable::load(codeview::StreamReader &Stream) { 25 struct Header { 26 support::ulittle32_t Signature; 27 support::ulittle32_t HashVersion; 28 support::ulittle32_t ByteSize; 29 }; 30 31 const Header *H; 32 if (auto EC = Stream.readObject(H)) 33 return EC; 34 35 if (H->Signature != 0xEFFEEFFE) 36 return make_error<RawError>(raw_error_code::corrupt_file, 37 "Invalid hash table signature"); 38 if (H->HashVersion != 1 && H->HashVersion != 2) 39 return make_error<RawError>(raw_error_code::corrupt_file, 40 "Unsupported hash version"); 41 42 Signature = H->Signature; 43 HashVersion = H->HashVersion; 44 if (auto EC = Stream.readStreamRef(NamesBuffer, H->ByteSize)) 45 return joinErrors(std::move(EC), 46 make_error<RawError>(raw_error_code::corrupt_file, 47 "Invalid hash table byte length")); 48 49 const support::ulittle32_t *HashCount; 50 if (auto EC = Stream.readObject(HashCount)) 51 return EC; 52 53 if (auto EC = Stream.readArray(IDs, *HashCount)) 54 return joinErrors(std::move(EC), 55 make_error<RawError>(raw_error_code::corrupt_file, 56 "Could not read bucket array")); 57 58 if (Stream.bytesRemaining() < sizeof(support::ulittle32_t)) 59 return make_error<RawError>(raw_error_code::corrupt_file, 60 "Missing name count"); 61 62 if (auto EC = Stream.readInteger(NameCount)) 63 return EC; 64 return Error::success(); 65 } 66 67 StringRef NameHashTable::getStringForID(uint32_t ID) const { 68 if (ID == IDs[0]) 69 return StringRef(); 70 71 // NamesBuffer is a buffer of null terminated strings back to back. ID is 72 // the starting offset of the string we're looking for. So just seek into 73 // the desired offset and a read a null terminated stream from that offset. 74 StringRef Result; 75 codeview::StreamReader NameReader(NamesBuffer); 76 NameReader.setOffset(ID); 77 if (auto EC = NameReader.readZeroString(Result)) 78 consumeError(std::move(EC)); 79 return Result; 80 } 81 82 uint32_t NameHashTable::getIDForString(StringRef Str) const { 83 uint32_t Hash = (HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str); 84 size_t Count = IDs.size(); 85 uint32_t Start = Hash % Count; 86 for (size_t I = 0; I < Count; ++I) { 87 // The hash is just a starting point for the search, but if it 88 // doesn't work we should find the string no matter what, because 89 // we iterate the entire array. 90 uint32_t Index = (Start + I) % Count; 91 92 uint32_t ID = IDs[Index]; 93 StringRef S = getStringForID(ID); 94 if (S == Str) 95 return ID; 96 } 97 // IDs[0] contains the ID of the "invalid" entry. 98 return IDs[0]; 99 } 100 101 codeview::FixedStreamArray<support::ulittle32_t> 102 NameHashTable::name_ids() const { 103 return IDs; 104 } 105