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