14fcfc199SEugene Zelenko //===- NamedStreamMap.cpp - PDB Named Stream Map --------------------------===//
26b6b8c4fSAdrian McCarthy //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66b6b8c4fSAdrian McCarthy //
76b6b8c4fSAdrian McCarthy //===----------------------------------------------------------------------===//
86b6b8c4fSAdrian McCarthy
96b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h"
10*ed98c1b3Sserge-sans-paille #include "llvm/ADT/SparseBitVector.h"
116b6b8c4fSAdrian McCarthy #include "llvm/ADT/StringMap.h"
126b6b8c4fSAdrian McCarthy #include "llvm/ADT/StringRef.h"
13cafd4768SZachary Turner #include "llvm/DebugInfo/PDB/Native/Hash.h"
146b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/HashTable.h"
156b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/RawError.h"
16d9dc2829SZachary Turner #include "llvm/Support/BinaryStreamReader.h"
174fcfc199SEugene Zelenko #include "llvm/Support/BinaryStreamWriter.h"
184fcfc199SEugene Zelenko #include "llvm/Support/Endian.h"
196b6b8c4fSAdrian McCarthy #include "llvm/Support/Error.h"
206b6b8c4fSAdrian McCarthy #include <algorithm>
214fcfc199SEugene Zelenko #include <cassert>
226b6b8c4fSAdrian McCarthy #include <cstdint>
236b6b8c4fSAdrian McCarthy
246b6b8c4fSAdrian McCarthy using namespace llvm;
256b6b8c4fSAdrian McCarthy using namespace llvm::pdb;
266b6b8c4fSAdrian McCarthy
NamedStreamMapTraits(NamedStreamMap & NS)27ebf03f6cSZachary Turner NamedStreamMapTraits::NamedStreamMapTraits(NamedStreamMap &NS) : NS(&NS) {}
28ebf03f6cSZachary Turner
hashLookupKey(StringRef S) const29ebf03f6cSZachary Turner uint16_t NamedStreamMapTraits::hashLookupKey(StringRef S) const {
30cafd4768SZachary Turner // In the reference implementation, this uses
31cafd4768SZachary Turner // HASH Hasher<ULONG*, USHORT*>::hashPbCb(PB pb, size_t cb, ULONG ulMod).
32cafd4768SZachary Turner // Here, the type HASH is a typedef of unsigned short.
33cafd4768SZachary Turner // ** It is not a bug that we truncate the result of hashStringV1, in fact
34cafd4768SZachary Turner // it is a bug if we do not! **
35e577be4eSNico Weber // See NMTNI::hash() in the reference implementation.
36cafd4768SZachary Turner return static_cast<uint16_t>(hashStringV1(S));
37cafd4768SZachary Turner }
381affd805SZachary Turner
storageKeyToLookupKey(uint32_t Offset) const39ebf03f6cSZachary Turner StringRef NamedStreamMapTraits::storageKeyToLookupKey(uint32_t Offset) const {
40ebf03f6cSZachary Turner return NS->getString(Offset);
41ebf03f6cSZachary Turner }
42ebf03f6cSZachary Turner
lookupKeyToStorageKey(StringRef S)43ebf03f6cSZachary Turner uint32_t NamedStreamMapTraits::lookupKeyToStorageKey(StringRef S) {
44ebf03f6cSZachary Turner return NS->appendStringData(S);
45ebf03f6cSZachary Turner }
46ebf03f6cSZachary Turner
NamedStreamMap()4751a52b58SNico Weber NamedStreamMap::NamedStreamMap() : HashTraits(*this), OffsetIndexMap(1) {}
486b6b8c4fSAdrian McCarthy
load(BinaryStreamReader & Stream)49120faca4SZachary Turner Error NamedStreamMap::load(BinaryStreamReader &Stream) {
506b6b8c4fSAdrian McCarthy uint32_t StringBufferSize;
51695ed56bSZachary Turner if (auto EC = Stream.readInteger(StringBufferSize))
526b6b8c4fSAdrian McCarthy return joinErrors(std::move(EC),
536b6b8c4fSAdrian McCarthy make_error<RawError>(raw_error_code::corrupt_file,
546b6b8c4fSAdrian McCarthy "Expected string buffer size"));
556b6b8c4fSAdrian McCarthy
56cafd4768SZachary Turner StringRef Buffer;
57cafd4768SZachary Turner if (auto EC = Stream.readFixedString(Buffer, StringBufferSize))
586b6b8c4fSAdrian McCarthy return EC;
59cafd4768SZachary Turner NamesBuffer.assign(Buffer.begin(), Buffer.end());
606b6b8c4fSAdrian McCarthy
61cafd4768SZachary Turner return OffsetIndexMap.load(Stream);
626b6b8c4fSAdrian McCarthy }
636b6b8c4fSAdrian McCarthy
commit(BinaryStreamWriter & Writer) const64120faca4SZachary Turner Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const {
656b6b8c4fSAdrian McCarthy // The first field is the number of bytes of string data.
66cafd4768SZachary Turner if (auto EC = Writer.writeInteger<uint32_t>(NamesBuffer.size()))
676b6b8c4fSAdrian McCarthy return EC;
686b6b8c4fSAdrian McCarthy
69cafd4768SZachary Turner // Then the actual string data.
70cafd4768SZachary Turner StringRef Data(NamesBuffer.data(), NamesBuffer.size());
71cafd4768SZachary Turner if (auto EC = Writer.writeFixedString(Data))
726b6b8c4fSAdrian McCarthy return EC;
736b6b8c4fSAdrian McCarthy
746b6b8c4fSAdrian McCarthy // And finally the Offset Index map.
75cafd4768SZachary Turner if (auto EC = OffsetIndexMap.commit(Writer))
766b6b8c4fSAdrian McCarthy return EC;
776b6b8c4fSAdrian McCarthy
786b6b8c4fSAdrian McCarthy return Error::success();
796b6b8c4fSAdrian McCarthy }
806b6b8c4fSAdrian McCarthy
calculateSerializedLength() const81cafd4768SZachary Turner uint32_t NamedStreamMap::calculateSerializedLength() const {
82cafd4768SZachary Turner return sizeof(uint32_t) // String data size
83cafd4768SZachary Turner + NamesBuffer.size() // String data
84cafd4768SZachary Turner + OffsetIndexMap.calculateSerializedLength(); // Offset Index Map
856b6b8c4fSAdrian McCarthy }
866b6b8c4fSAdrian McCarthy
size() const87cafd4768SZachary Turner uint32_t NamedStreamMap::size() const { return OffsetIndexMap.size(); }
88cafd4768SZachary Turner
getString(uint32_t Offset) const89cafd4768SZachary Turner StringRef NamedStreamMap::getString(uint32_t Offset) const {
90cafd4768SZachary Turner assert(NamesBuffer.size() > Offset);
91cafd4768SZachary Turner return StringRef(NamesBuffer.data() + Offset);
926b6b8c4fSAdrian McCarthy }
936b6b8c4fSAdrian McCarthy
hashString(uint32_t Offset) const94cafd4768SZachary Turner uint32_t NamedStreamMap::hashString(uint32_t Offset) const {
95cafd4768SZachary Turner return hashStringV1(getString(Offset));
966b6b8c4fSAdrian McCarthy }
976b6b8c4fSAdrian McCarthy
get(StringRef Stream,uint32_t & StreamNo) const986b6b8c4fSAdrian McCarthy bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const {
9951a52b58SNico Weber auto Iter = OffsetIndexMap.find_as(Stream, HashTraits);
100cafd4768SZachary Turner if (Iter == OffsetIndexMap.end())
1016b6b8c4fSAdrian McCarthy return false;
102cafd4768SZachary Turner StreamNo = (*Iter).second;
1036b6b8c4fSAdrian McCarthy return true;
1046b6b8c4fSAdrian McCarthy }
1056b6b8c4fSAdrian McCarthy
entries() const106cafd4768SZachary Turner StringMap<uint32_t> NamedStreamMap::entries() const {
107cafd4768SZachary Turner StringMap<uint32_t> Result;
108cafd4768SZachary Turner for (const auto &Entry : OffsetIndexMap) {
109cafd4768SZachary Turner StringRef Stream(NamesBuffer.data() + Entry.first);
110cafd4768SZachary Turner Result.try_emplace(Stream, Entry.second);
111cafd4768SZachary Turner }
112cafd4768SZachary Turner return Result;
1136b6b8c4fSAdrian McCarthy }
1146b6b8c4fSAdrian McCarthy
appendStringData(StringRef S)115cafd4768SZachary Turner uint32_t NamedStreamMap::appendStringData(StringRef S) {
116cafd4768SZachary Turner uint32_t Offset = NamesBuffer.size();
1170edbc90eSKazu Hirata llvm::append_range(NamesBuffer, S);
118cafd4768SZachary Turner NamesBuffer.push_back('\0');
119cafd4768SZachary Turner return Offset;
120cafd4768SZachary Turner }
121cafd4768SZachary Turner
set(StringRef Stream,uint32_t StreamNo)122cafd4768SZachary Turner void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) {
12351a52b58SNico Weber OffsetIndexMap.set_as(Stream, support::ulittle32_t(StreamNo), HashTraits);
1246b6b8c4fSAdrian McCarthy }
125