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" 106b6b8c4fSAdrian McCarthy #include "llvm/ADT/StringMap.h" 116b6b8c4fSAdrian McCarthy #include "llvm/ADT/StringRef.h" 126b6b8c4fSAdrian McCarthy #include "llvm/ADT/iterator_range.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/BinaryStreamRef.h" 184fcfc199SEugene Zelenko #include "llvm/Support/BinaryStreamWriter.h" 194fcfc199SEugene Zelenko #include "llvm/Support/Endian.h" 206b6b8c4fSAdrian McCarthy #include "llvm/Support/Error.h" 216b6b8c4fSAdrian McCarthy #include <algorithm> 224fcfc199SEugene Zelenko #include <cassert> 236b6b8c4fSAdrian McCarthy #include <cstdint> 244fcfc199SEugene Zelenko #include <tuple> 256b6b8c4fSAdrian McCarthy 266b6b8c4fSAdrian McCarthy using namespace llvm; 276b6b8c4fSAdrian McCarthy using namespace llvm::pdb; 286b6b8c4fSAdrian McCarthy 29ebf03f6cSZachary Turner NamedStreamMapTraits::NamedStreamMapTraits(NamedStreamMap &NS) : NS(&NS) {} 30ebf03f6cSZachary Turner 31ebf03f6cSZachary Turner uint16_t NamedStreamMapTraits::hashLookupKey(StringRef S) const { 32cafd4768SZachary Turner // In the reference implementation, this uses 33cafd4768SZachary Turner // HASH Hasher<ULONG*, USHORT*>::hashPbCb(PB pb, size_t cb, ULONG ulMod). 34cafd4768SZachary Turner // Here, the type HASH is a typedef of unsigned short. 35cafd4768SZachary Turner // ** It is not a bug that we truncate the result of hashStringV1, in fact 36cafd4768SZachary Turner // it is a bug if we do not! ** 37*e577be4eSNico Weber // See NMTNI::hash() in the reference implementation. 38cafd4768SZachary Turner return static_cast<uint16_t>(hashStringV1(S)); 39cafd4768SZachary Turner } 401affd805SZachary Turner 41ebf03f6cSZachary Turner StringRef NamedStreamMapTraits::storageKeyToLookupKey(uint32_t Offset) const { 42ebf03f6cSZachary Turner return NS->getString(Offset); 43ebf03f6cSZachary Turner } 44ebf03f6cSZachary Turner 45ebf03f6cSZachary Turner uint32_t NamedStreamMapTraits::lookupKeyToStorageKey(StringRef S) { 46ebf03f6cSZachary Turner return NS->appendStringData(S); 47ebf03f6cSZachary Turner } 48ebf03f6cSZachary Turner 49ebf03f6cSZachary Turner NamedStreamMap::NamedStreamMap() 50a6fb536eSZachary Turner : HashTraits(*this), OffsetIndexMap(1, HashTraits) {} 516b6b8c4fSAdrian McCarthy 52120faca4SZachary Turner Error NamedStreamMap::load(BinaryStreamReader &Stream) { 536b6b8c4fSAdrian McCarthy uint32_t StringBufferSize; 54695ed56bSZachary Turner if (auto EC = Stream.readInteger(StringBufferSize)) 556b6b8c4fSAdrian McCarthy return joinErrors(std::move(EC), 566b6b8c4fSAdrian McCarthy make_error<RawError>(raw_error_code::corrupt_file, 576b6b8c4fSAdrian McCarthy "Expected string buffer size")); 586b6b8c4fSAdrian McCarthy 59cafd4768SZachary Turner StringRef Buffer; 60cafd4768SZachary Turner if (auto EC = Stream.readFixedString(Buffer, StringBufferSize)) 616b6b8c4fSAdrian McCarthy return EC; 62cafd4768SZachary Turner NamesBuffer.assign(Buffer.begin(), Buffer.end()); 636b6b8c4fSAdrian McCarthy 64cafd4768SZachary Turner return OffsetIndexMap.load(Stream); 656b6b8c4fSAdrian McCarthy } 666b6b8c4fSAdrian McCarthy 67120faca4SZachary Turner Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const { 686b6b8c4fSAdrian McCarthy // The first field is the number of bytes of string data. 69cafd4768SZachary Turner if (auto EC = Writer.writeInteger<uint32_t>(NamesBuffer.size())) 706b6b8c4fSAdrian McCarthy return EC; 716b6b8c4fSAdrian McCarthy 72cafd4768SZachary Turner // Then the actual string data. 73cafd4768SZachary Turner StringRef Data(NamesBuffer.data(), NamesBuffer.size()); 74cafd4768SZachary Turner if (auto EC = Writer.writeFixedString(Data)) 756b6b8c4fSAdrian McCarthy return EC; 766b6b8c4fSAdrian McCarthy 776b6b8c4fSAdrian McCarthy // And finally the Offset Index map. 78cafd4768SZachary Turner if (auto EC = OffsetIndexMap.commit(Writer)) 796b6b8c4fSAdrian McCarthy return EC; 806b6b8c4fSAdrian McCarthy 816b6b8c4fSAdrian McCarthy return Error::success(); 826b6b8c4fSAdrian McCarthy } 836b6b8c4fSAdrian McCarthy 84cafd4768SZachary Turner uint32_t NamedStreamMap::calculateSerializedLength() const { 85cafd4768SZachary Turner return sizeof(uint32_t) // String data size 86cafd4768SZachary Turner + NamesBuffer.size() // String data 87cafd4768SZachary Turner + OffsetIndexMap.calculateSerializedLength(); // Offset Index Map 886b6b8c4fSAdrian McCarthy } 896b6b8c4fSAdrian McCarthy 90cafd4768SZachary Turner uint32_t NamedStreamMap::size() const { return OffsetIndexMap.size(); } 91cafd4768SZachary Turner 92cafd4768SZachary Turner StringRef NamedStreamMap::getString(uint32_t Offset) const { 93cafd4768SZachary Turner assert(NamesBuffer.size() > Offset); 94cafd4768SZachary Turner return StringRef(NamesBuffer.data() + Offset); 956b6b8c4fSAdrian McCarthy } 966b6b8c4fSAdrian McCarthy 97cafd4768SZachary Turner uint32_t NamedStreamMap::hashString(uint32_t Offset) const { 98cafd4768SZachary Turner return hashStringV1(getString(Offset)); 996b6b8c4fSAdrian McCarthy } 1006b6b8c4fSAdrian McCarthy 1016b6b8c4fSAdrian McCarthy bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const { 102ebf03f6cSZachary Turner auto Iter = OffsetIndexMap.find_as(Stream); 103cafd4768SZachary Turner if (Iter == OffsetIndexMap.end()) 1046b6b8c4fSAdrian McCarthy return false; 105cafd4768SZachary Turner StreamNo = (*Iter).second; 1066b6b8c4fSAdrian McCarthy return true; 1076b6b8c4fSAdrian McCarthy } 1086b6b8c4fSAdrian McCarthy 109cafd4768SZachary Turner StringMap<uint32_t> NamedStreamMap::entries() const { 110cafd4768SZachary Turner StringMap<uint32_t> Result; 111cafd4768SZachary Turner for (const auto &Entry : OffsetIndexMap) { 112cafd4768SZachary Turner StringRef Stream(NamesBuffer.data() + Entry.first); 113cafd4768SZachary Turner Result.try_emplace(Stream, Entry.second); 114cafd4768SZachary Turner } 115cafd4768SZachary Turner return Result; 1166b6b8c4fSAdrian McCarthy } 1176b6b8c4fSAdrian McCarthy 118cafd4768SZachary Turner uint32_t NamedStreamMap::appendStringData(StringRef S) { 119cafd4768SZachary Turner uint32_t Offset = NamesBuffer.size(); 120cafd4768SZachary Turner NamesBuffer.insert(NamesBuffer.end(), S.begin(), S.end()); 121cafd4768SZachary Turner NamesBuffer.push_back('\0'); 122cafd4768SZachary Turner return Offset; 123cafd4768SZachary Turner } 124cafd4768SZachary Turner 125cafd4768SZachary Turner void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) { 126ebf03f6cSZachary Turner OffsetIndexMap.set_as(Stream, support::ulittle32_t(StreamNo)); 1276b6b8c4fSAdrian McCarthy } 128