Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp
35293 views
//===- PDBStringTableBuilder.cpp - PDB String Table -------------*- 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//===----------------------------------------------------------------------===//78#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"910#include "llvm/ADT/ArrayRef.h"11#include "llvm/DebugInfo/PDB/Native/Hash.h"12#include "llvm/DebugInfo/PDB/Native/RawTypes.h"13#include "llvm/Support/BinaryStreamWriter.h"14#include "llvm/Support/Endian.h"15#include "llvm/Support/TimeProfiler.h"1617#include <map>1819using namespace llvm;20using namespace llvm::msf;21using namespace llvm::support;22using namespace llvm::support::endian;23using namespace llvm::pdb;2425StringTableHashTraits::StringTableHashTraits(PDBStringTableBuilder &Table)26: Table(&Table) {}2728uint32_t StringTableHashTraits::hashLookupKey(StringRef S) const {29// The reference implementation doesn't include code for /src/headerblock30// handling, but it can only read natvis entries lld's PDB files if31// this hash function truncates the hash to 16 bit.32// PDB/include/misc.h in the reference implementation has a hashSz() function33// that returns an unsigned short, that seems what's being used for34// /src/headerblock.35return static_cast<uint16_t>(Table->getIdForString(S));36}3738StringRef StringTableHashTraits::storageKeyToLookupKey(uint32_t Offset) const {39return Table->getStringForId(Offset);40}4142uint32_t StringTableHashTraits::lookupKeyToStorageKey(StringRef S) {43return Table->insert(S);44}4546uint32_t PDBStringTableBuilder::insert(StringRef S) {47return Strings.insert(S);48}4950uint32_t PDBStringTableBuilder::getIdForString(StringRef S) const {51return Strings.getIdForString(S);52}5354StringRef PDBStringTableBuilder::getStringForId(uint32_t Id) const {55return Strings.getStringForId(Id);56}5758static uint32_t computeBucketCount(uint32_t NumStrings) {59// This is a precomputed list of Buckets given the specified number of60// strings. Matching the reference algorithm exactly is not strictly61// necessary for correctness, but it helps when comparing LLD's PDBs with62// Microsoft's PDBs so as to eliminate superfluous differences.63// The reference implementation does (in nmt.h, NMT::grow()):64// unsigned StringCount = 0;65// unsigned BucketCount = 1;66// fn insert() {67// ++StringCount;68// if (BucketCount * 3 / 4 < StringCount)69// BucketCount = BucketCount * 3 / 2 + 1;70// }71// This list contains all StringCount, BucketCount pairs where BucketCount was72// just incremented. It ends before the first BucketCount entry where73// BucketCount * 3 would overflow a 32-bit unsigned int.74static const std::pair<uint32_t, uint32_t> StringsToBuckets[] = {75{0, 1},76{1, 2},77{2, 4},78{4, 7},79{6, 11},80{9, 17},81{13, 26},82{20, 40},83{31, 61},84{46, 92},85{70, 139},86{105, 209},87{157, 314},88{236, 472},89{355, 709},90{532, 1064},91{799, 1597},92{1198, 2396},93{1798, 3595},94{2697, 5393},95{4045, 8090},96{6068, 12136},97{9103, 18205},98{13654, 27308},99{20482, 40963},100{30723, 61445},101{46084, 92168},102{69127, 138253},103{103690, 207380},104{155536, 311071},105{233304, 466607},106{349956, 699911},107{524934, 1049867},108{787401, 1574801},109{1181101, 2362202},110{1771652, 3543304},111{2657479, 5314957},112{3986218, 7972436},113{5979328, 11958655},114{8968992, 17937983},115{13453488, 26906975},116{20180232, 40360463},117{30270348, 60540695},118{45405522, 90811043},119{68108283, 136216565},120{102162424, 204324848},121{153243637, 306487273},122{229865455, 459730910},123{344798183, 689596366},124{517197275, 1034394550},125{775795913, 1551591826},126{1163693870, 2327387740}};127const auto *Entry = llvm::lower_bound(128StringsToBuckets, std::make_pair(NumStrings, 0U), llvm::less_first());129assert(Entry != std::end(StringsToBuckets));130return Entry->second;131}132133uint32_t PDBStringTableBuilder::calculateHashTableSize() const {134uint32_t Size = sizeof(uint32_t); // Hash table begins with 4-byte size field.135Size += sizeof(uint32_t) * computeBucketCount(Strings.size());136137return Size;138}139140uint32_t PDBStringTableBuilder::calculateSerializedSize() const {141uint32_t Size = 0;142Size += sizeof(PDBStringTableHeader);143Size += Strings.calculateSerializedSize();144Size += calculateHashTableSize();145Size += sizeof(uint32_t); // The /names stream ends with the string count.146return Size;147}148149void PDBStringTableBuilder::setStrings(150const codeview::DebugStringTableSubsection &Strings) {151this->Strings = Strings;152}153154Error PDBStringTableBuilder::writeHeader(BinaryStreamWriter &Writer) const {155// Write a header156PDBStringTableHeader H;157H.Signature = PDBStringTableSignature;158H.HashVersion = 1;159H.ByteSize = Strings.calculateSerializedSize();160if (auto EC = Writer.writeObject(H))161return EC;162assert(Writer.bytesRemaining() == 0);163return Error::success();164}165166Error PDBStringTableBuilder::writeStrings(BinaryStreamWriter &Writer) const {167if (auto EC = Strings.commit(Writer))168return EC;169170assert(Writer.bytesRemaining() == 0);171return Error::success();172}173174Error PDBStringTableBuilder::writeHashTable(BinaryStreamWriter &Writer) const {175// Write a hash table.176uint32_t BucketCount = computeBucketCount(Strings.size());177if (auto EC = Writer.writeInteger(BucketCount))178return EC;179std::vector<ulittle32_t> Buckets(BucketCount);180181for (const auto &Pair : Strings) {182StringRef S = Pair.getKey();183uint32_t Offset = Pair.getValue();184uint32_t Hash = hashStringV1(S);185186for (uint32_t I = 0; I != BucketCount; ++I) {187uint32_t Slot = (Hash + I) % BucketCount;188if (Buckets[Slot] != 0)189continue;190Buckets[Slot] = Offset;191break;192}193}194195if (auto EC = Writer.writeArray(ArrayRef<ulittle32_t>(Buckets)))196return EC;197198assert(Writer.bytesRemaining() == 0);199return Error::success();200}201202Error PDBStringTableBuilder::writeEpilogue(BinaryStreamWriter &Writer) const {203if (auto EC = Writer.writeInteger<uint32_t>(Strings.size()))204return EC;205assert(Writer.bytesRemaining() == 0);206return Error::success();207}208209Error PDBStringTableBuilder::commit(BinaryStreamWriter &Writer) const {210llvm::TimeTraceScope timeScope("Commit strings table");211BinaryStreamWriter SectionWriter;212213std::tie(SectionWriter, Writer) = Writer.split(sizeof(PDBStringTableHeader));214if (auto EC = writeHeader(SectionWriter))215return EC;216217std::tie(SectionWriter, Writer) =218Writer.split(Strings.calculateSerializedSize());219if (auto EC = writeStrings(SectionWriter))220return EC;221222std::tie(SectionWriter, Writer) = Writer.split(calculateHashTableSize());223if (auto EC = writeHashTable(SectionWriter))224return EC;225226std::tie(SectionWriter, Writer) = Writer.split(sizeof(uint32_t));227if (auto EC = writeEpilogue(SectionWriter))228return EC;229230return Error::success();231}232233234