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