1317760Sdim//===- PDBStringTable.cpp - PDB String Table ---------------------*- C++-*-===// 2317760Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6317760Sdim// 7317760Sdim//===----------------------------------------------------------------------===// 8317760Sdim 9317760Sdim#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" 10317760Sdim 11317760Sdim#include "llvm/ADT/ArrayRef.h" 12317760Sdim#include "llvm/DebugInfo/PDB/Native/Hash.h" 13317760Sdim#include "llvm/DebugInfo/PDB/Native/RawError.h" 14317760Sdim#include "llvm/DebugInfo/PDB/Native/RawTypes.h" 15317760Sdim#include "llvm/Support/BinaryStreamReader.h" 16317760Sdim#include "llvm/Support/Endian.h" 17317760Sdim 18317760Sdimusing namespace llvm; 19317760Sdimusing namespace llvm::support; 20317760Sdimusing namespace llvm::pdb; 21317760Sdim 22320970Sdimuint32_t PDBStringTable::getByteSize() const { return Header->ByteSize; } 23317760Sdimuint32_t PDBStringTable::getNameCount() const { return NameCount; } 24317760Sdimuint32_t PDBStringTable::getHashVersion() const { return Header->HashVersion; } 25317760Sdimuint32_t PDBStringTable::getSignature() const { return Header->Signature; } 26317760Sdim 27317760SdimError PDBStringTable::readHeader(BinaryStreamReader &Reader) { 28317760Sdim if (auto EC = Reader.readObject(Header)) 29317760Sdim return EC; 30317760Sdim 31317760Sdim if (Header->Signature != PDBStringTableSignature) 32317760Sdim return make_error<RawError>(raw_error_code::corrupt_file, 33317760Sdim "Invalid hash table signature"); 34317760Sdim if (Header->HashVersion != 1 && Header->HashVersion != 2) 35317760Sdim return make_error<RawError>(raw_error_code::corrupt_file, 36317760Sdim "Unsupported hash version"); 37317760Sdim 38317760Sdim assert(Reader.bytesRemaining() == 0); 39317760Sdim return Error::success(); 40317760Sdim} 41317760Sdim 42317760SdimError PDBStringTable::readStrings(BinaryStreamReader &Reader) { 43317760Sdim BinaryStreamRef Stream; 44317760Sdim if (auto EC = Reader.readStreamRef(Stream)) 45317760Sdim return EC; 46317760Sdim 47317760Sdim if (auto EC = Strings.initialize(Stream)) { 48317760Sdim return joinErrors(std::move(EC), 49317760Sdim make_error<RawError>(raw_error_code::corrupt_file, 50317760Sdim "Invalid hash table byte length")); 51317760Sdim } 52317760Sdim 53317760Sdim assert(Reader.bytesRemaining() == 0); 54317760Sdim return Error::success(); 55317760Sdim} 56317760Sdim 57320041Sdimconst codeview::DebugStringTableSubsectionRef & 58320041SdimPDBStringTable::getStringTable() const { 59319547Sdim return Strings; 60319547Sdim} 61319547Sdim 62317760SdimError PDBStringTable::readHashTable(BinaryStreamReader &Reader) { 63317760Sdim const support::ulittle32_t *HashCount; 64317760Sdim if (auto EC = Reader.readObject(HashCount)) 65317760Sdim return EC; 66317760Sdim 67317760Sdim if (auto EC = Reader.readArray(IDs, *HashCount)) { 68317760Sdim return joinErrors(std::move(EC), 69317760Sdim make_error<RawError>(raw_error_code::corrupt_file, 70317760Sdim "Could not read bucket array")); 71317760Sdim } 72317760Sdim 73317760Sdim return Error::success(); 74317760Sdim} 75317760Sdim 76317760SdimError PDBStringTable::readEpilogue(BinaryStreamReader &Reader) { 77317760Sdim if (auto EC = Reader.readInteger(NameCount)) 78317760Sdim return EC; 79317760Sdim 80317760Sdim assert(Reader.bytesRemaining() == 0); 81317760Sdim return Error::success(); 82317760Sdim} 83317760Sdim 84317760SdimError PDBStringTable::reload(BinaryStreamReader &Reader) { 85317760Sdim 86317760Sdim BinaryStreamReader SectionReader; 87317760Sdim 88317760Sdim std::tie(SectionReader, Reader) = Reader.split(sizeof(PDBStringTableHeader)); 89317760Sdim if (auto EC = readHeader(SectionReader)) 90317760Sdim return EC; 91317760Sdim 92317760Sdim std::tie(SectionReader, Reader) = Reader.split(Header->ByteSize); 93317760Sdim if (auto EC = readStrings(SectionReader)) 94317760Sdim return EC; 95317760Sdim 96317760Sdim // We don't know how long the hash table is until we parse it, so let the 97317760Sdim // function responsible for doing that figure it out. 98317760Sdim if (auto EC = readHashTable(Reader)) 99317760Sdim return EC; 100317760Sdim 101317760Sdim std::tie(SectionReader, Reader) = Reader.split(sizeof(uint32_t)); 102317760Sdim if (auto EC = readEpilogue(SectionReader)) 103317760Sdim return EC; 104317760Sdim 105317760Sdim assert(Reader.bytesRemaining() == 0); 106317760Sdim return Error::success(); 107317760Sdim} 108317760Sdim 109317760SdimExpected<StringRef> PDBStringTable::getStringForID(uint32_t ID) const { 110317760Sdim return Strings.getString(ID); 111317760Sdim} 112317760Sdim 113317760SdimExpected<uint32_t> PDBStringTable::getIDForString(StringRef Str) const { 114317760Sdim uint32_t Hash = 115317760Sdim (Header->HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str); 116317760Sdim size_t Count = IDs.size(); 117317760Sdim uint32_t Start = Hash % Count; 118317760Sdim for (size_t I = 0; I < Count; ++I) { 119317760Sdim // The hash is just a starting point for the search, but if it 120317760Sdim // doesn't work we should find the string no matter what, because 121317760Sdim // we iterate the entire array. 122317760Sdim uint32_t Index = (Start + I) % Count; 123317760Sdim 124341825Sdim // If we find 0, it means the item isn't in the hash table. 125317760Sdim uint32_t ID = IDs[Index]; 126341825Sdim if (ID == 0) 127341825Sdim return make_error<RawError>(raw_error_code::no_entry); 128317760Sdim auto ExpectedStr = getStringForID(ID); 129317760Sdim if (!ExpectedStr) 130317760Sdim return ExpectedStr.takeError(); 131317760Sdim 132317760Sdim if (*ExpectedStr == Str) 133317760Sdim return ID; 134317760Sdim } 135317760Sdim return make_error<RawError>(raw_error_code::no_entry); 136317760Sdim} 137317760Sdim 138317760SdimFixedStreamArray<support::ulittle32_t> PDBStringTable::name_ids() const { 139317760Sdim return IDs; 140317760Sdim} 141