1 //===- PDBStringTable.cpp - PDB String Table -----------------------*- C++ 2 //-*-===// 3 // 4 // The LLVM Compiler Infrastructure 5 // 6 // This file is distributed under the University of Illinois Open Source 7 // License. See LICENSE.TXT for details. 8 // 9 //===----------------------------------------------------------------------===// 10 11 #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" 12 13 #include "llvm/ADT/ArrayRef.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 PDBStringTable::PDBStringTable() {} 25 26 Error PDBStringTable::load(BinaryStreamReader &Stream) { 27 ByteSize = Stream.getLength(); 28 29 const PDBStringTableHeader *H; 30 if (auto EC = Stream.readObject(H)) 31 return EC; 32 33 if (H->Signature != PDBStringTableSignature) 34 return make_error<RawError>(raw_error_code::corrupt_file, 35 "Invalid hash table signature"); 36 if (H->HashVersion != 1 && H->HashVersion != 2) 37 return make_error<RawError>(raw_error_code::corrupt_file, 38 "Unsupported hash version"); 39 40 Signature = H->Signature; 41 HashVersion = H->HashVersion; 42 if (auto EC = Stream.readStreamRef(NamesBuffer, H->ByteSize)) 43 return joinErrors(std::move(EC), 44 make_error<RawError>(raw_error_code::corrupt_file, 45 "Invalid hash table byte length")); 46 47 const support::ulittle32_t *HashCount; 48 if (auto EC = Stream.readObject(HashCount)) 49 return EC; 50 51 if (auto EC = Stream.readArray(IDs, *HashCount)) 52 return joinErrors(std::move(EC), 53 make_error<RawError>(raw_error_code::corrupt_file, 54 "Could not read bucket array")); 55 56 if (Stream.bytesRemaining() < sizeof(support::ulittle32_t)) 57 return make_error<RawError>(raw_error_code::corrupt_file, 58 "Missing name count"); 59 60 if (auto EC = Stream.readInteger(NameCount)) 61 return EC; 62 63 if (Stream.bytesRemaining() > 0) 64 return make_error<RawError>(raw_error_code::stream_too_long, 65 "Unexpected bytes found in string table"); 66 67 return Error::success(); 68 } 69 70 uint32_t PDBStringTable::getByteSize() const { return ByteSize; } 71 72 StringRef PDBStringTable::getStringForID(uint32_t ID) const { 73 if (ID == IDs[0]) 74 return StringRef(); 75 76 // NamesBuffer is a buffer of null terminated strings back to back. ID is 77 // the starting offset of the string we're looking for. So just seek into 78 // the desired offset and a read a null terminated stream from that offset. 79 StringRef Result; 80 BinaryStreamReader NameReader(NamesBuffer); 81 NameReader.setOffset(ID); 82 if (auto EC = NameReader.readCString(Result)) 83 consumeError(std::move(EC)); 84 return Result; 85 } 86 87 uint32_t PDBStringTable::getIDForString(StringRef Str) const { 88 uint32_t Hash = (HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str); 89 size_t Count = IDs.size(); 90 uint32_t Start = Hash % Count; 91 for (size_t I = 0; I < Count; ++I) { 92 // The hash is just a starting point for the search, but if it 93 // doesn't work we should find the string no matter what, because 94 // we iterate the entire array. 95 uint32_t Index = (Start + I) % Count; 96 97 uint32_t ID = IDs[Index]; 98 StringRef S = getStringForID(ID); 99 if (S == Str) 100 return ID; 101 } 102 // IDs[0] contains the ID of the "invalid" entry. 103 return IDs[0]; 104 } 105 106 FixedStreamArray<support::ulittle32_t> PDBStringTable::name_ids() const { 107 return IDs; 108 } 109