Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/PDB/Native/GlobalsStream.cpp
35293 views
//===- GlobalsStream.cpp - PDB Index of Symbols by Name ---------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// The on-disk structores used in this file are based on the reference9// implementation which is available at10// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h11//12// When you are reading the reference source code, you'd find the13// information below useful.14//15// - ppdb1->m_fMinimalDbgInfo seems to be always true.16// - SMALLBUCKETS macro is defined.17//18//===----------------------------------------------------------------------===//1920#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"2122#include "llvm/DebugInfo/CodeView/RecordName.h"23#include "llvm/DebugInfo/MSF/MappedBlockStream.h"24#include "llvm/DebugInfo/PDB/Native/Hash.h"25#include "llvm/DebugInfo/PDB/Native/RawError.h"26#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"27#include "llvm/Support/BinaryStreamReader.h"28#include "llvm/Support/Error.h"29#include <algorithm>3031using namespace llvm;32using namespace llvm::msf;33using namespace llvm::pdb;3435GlobalsStream::GlobalsStream(std::unique_ptr<MappedBlockStream> Stream)36: Stream(std::move(Stream)) {}3738GlobalsStream::~GlobalsStream() = default;3940Error GlobalsStream::reload() {41BinaryStreamReader Reader(*Stream);42if (auto E = GlobalsTable.read(Reader))43return E;44return Error::success();45}4647std::vector<std::pair<uint32_t, codeview::CVSymbol>>48GlobalsStream::findRecordsByName(StringRef Name,49const SymbolStream &Symbols) const {50std::vector<std::pair<uint32_t, codeview::CVSymbol>> Result;5152// Hash the name to figure out which bucket this goes into.53size_t ExpandedBucketIndex = hashStringV1(Name) % IPHR_HASH;54int32_t CompressedBucketIndex = GlobalsTable.BucketMap[ExpandedBucketIndex];55if (CompressedBucketIndex == -1)56return Result;5758uint32_t LastBucketIndex = GlobalsTable.HashBuckets.size() - 1;59uint32_t StartRecordIndex =60GlobalsTable.HashBuckets[CompressedBucketIndex] / 12;61uint32_t EndRecordIndex = 0;62if (LLVM_LIKELY(uint32_t(CompressedBucketIndex) < LastBucketIndex)) {63EndRecordIndex = GlobalsTable.HashBuckets[CompressedBucketIndex + 1];64} else {65// If this is the last bucket, it consists of all hash records until the end66// of the HashRecords array.67EndRecordIndex = GlobalsTable.HashRecords.size() * 12;68}6970EndRecordIndex /= 12;7172assert(EndRecordIndex <= GlobalsTable.HashRecords.size());73while (StartRecordIndex < EndRecordIndex) {74PSHashRecord PSH = GlobalsTable.HashRecords[StartRecordIndex];75uint32_t Off = PSH.Off - 1;76codeview::CVSymbol Record = Symbols.readRecord(Off);77if (codeview::getSymbolName(Record) == Name)78Result.push_back(std::make_pair(Off, std::move(Record)));79++StartRecordIndex;80}81return Result;82}8384static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) {85if (HashHdr->VerHdr != GSIHashHeader::HdrVersion)86return make_error<RawError>(87raw_error_code::feature_unsupported,88"Encountered unsupported globals stream version.");8990return Error::success();91}9293static Error readGSIHashHeader(const GSIHashHeader *&HashHdr,94BinaryStreamReader &Reader) {95if (Reader.readObject(HashHdr))96return make_error<RawError>(raw_error_code::corrupt_file,97"Stream does not contain a GSIHashHeader.");9899if (HashHdr->VerSignature != GSIHashHeader::HdrSignature)100return make_error<RawError>(101raw_error_code::feature_unsupported,102"GSIHashHeader signature (0xffffffff) not found.");103104return Error::success();105}106107static Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords,108const GSIHashHeader *HashHdr,109BinaryStreamReader &Reader) {110if (auto EC = checkHashHdrVersion(HashHdr))111return EC;112113// HashHdr->HrSize specifies the number of bytes of PSHashRecords we have.114// Verify that we can read them all.115if (HashHdr->HrSize % sizeof(PSHashRecord))116return make_error<RawError>(raw_error_code::corrupt_file,117"Invalid HR array size.");118uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord);119if (auto EC = Reader.readArray(HashRecords, NumHashRecords))120return joinErrors(std::move(EC),121make_error<RawError>(raw_error_code::corrupt_file,122"Error reading hash records."));123124return Error::success();125}126127static Error128readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets,129FixedStreamArray<support::ulittle32_t> &HashBitmap,130const GSIHashHeader *HashHdr,131MutableArrayRef<int32_t> BucketMap,132BinaryStreamReader &Reader) {133if (auto EC = checkHashHdrVersion(HashHdr))134return EC;135136// Before the actual hash buckets, there is a bitmap of length determined by137// IPHR_HASH.138size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32);139uint32_t NumBitmapEntries = BitmapSizeInBits / 32;140if (auto EC = Reader.readArray(HashBitmap, NumBitmapEntries))141return joinErrors(std::move(EC),142make_error<RawError>(raw_error_code::corrupt_file,143"Could not read a bitmap."));144uint32_t CompressedBucketIdx = 0;145for (uint32_t I = 0; I <= IPHR_HASH; ++I) {146uint8_t WordIdx = I / 32;147uint8_t BitIdx = I % 32;148bool IsSet = HashBitmap[WordIdx] & (1U << BitIdx);149if (IsSet) {150BucketMap[I] = CompressedBucketIdx++;151} else {152BucketMap[I] = -1;153}154}155156uint32_t NumBuckets = 0;157for (uint32_t B : HashBitmap)158NumBuckets += llvm::popcount(B);159160// Hash buckets follow.161if (auto EC = Reader.readArray(HashBuckets, NumBuckets))162return joinErrors(std::move(EC),163make_error<RawError>(raw_error_code::corrupt_file,164"Hash buckets corrupted."));165166return Error::success();167}168169Error GSIHashTable::read(BinaryStreamReader &Reader) {170if (auto EC = readGSIHashHeader(HashHdr, Reader))171return EC;172if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader))173return EC;174if (HashHdr->HrSize > 0)175if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr,176BucketMap, Reader))177return EC;178return Error::success();179}180181182