14fcfc199SEugene Zelenko //===- NamedStreamMap.cpp - PDB Named Stream Map --------------------------===//
26b6b8c4fSAdrian McCarthy //
36b6b8c4fSAdrian McCarthy //                     The LLVM Compiler Infrastructure
46b6b8c4fSAdrian McCarthy //
56b6b8c4fSAdrian McCarthy // This file is distributed under the University of Illinois Open Source
66b6b8c4fSAdrian McCarthy // License. See LICENSE.TXT for details.
76b6b8c4fSAdrian McCarthy //
86b6b8c4fSAdrian McCarthy //===----------------------------------------------------------------------===//
96b6b8c4fSAdrian McCarthy 
106b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h"
116b6b8c4fSAdrian McCarthy #include "llvm/ADT/StringMap.h"
126b6b8c4fSAdrian McCarthy #include "llvm/ADT/StringRef.h"
136b6b8c4fSAdrian McCarthy #include "llvm/ADT/iterator_range.h"
14cafd4768SZachary Turner #include "llvm/DebugInfo/PDB/Native/Hash.h"
156b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/HashTable.h"
166b6b8c4fSAdrian McCarthy #include "llvm/DebugInfo/PDB/Native/RawError.h"
17d9dc2829SZachary Turner #include "llvm/Support/BinaryStreamReader.h"
184fcfc199SEugene Zelenko #include "llvm/Support/BinaryStreamRef.h"
194fcfc199SEugene Zelenko #include "llvm/Support/BinaryStreamWriter.h"
204fcfc199SEugene Zelenko #include "llvm/Support/Endian.h"
216b6b8c4fSAdrian McCarthy #include "llvm/Support/Error.h"
226b6b8c4fSAdrian McCarthy #include <algorithm>
234fcfc199SEugene Zelenko #include <cassert>
246b6b8c4fSAdrian McCarthy #include <cstdint>
254fcfc199SEugene Zelenko #include <tuple>
266b6b8c4fSAdrian McCarthy 
276b6b8c4fSAdrian McCarthy using namespace llvm;
286b6b8c4fSAdrian McCarthy using namespace llvm::pdb;
296b6b8c4fSAdrian McCarthy 
30ebf03f6cSZachary Turner NamedStreamMapTraits::NamedStreamMapTraits(NamedStreamMap &NS) : NS(&NS) {}
31ebf03f6cSZachary Turner 
32ebf03f6cSZachary Turner uint16_t NamedStreamMapTraits::hashLookupKey(StringRef S) const {
33cafd4768SZachary Turner   // In the reference implementation, this uses
34cafd4768SZachary Turner   // HASH Hasher<ULONG*, USHORT*>::hashPbCb(PB pb, size_t cb, ULONG ulMod).
35cafd4768SZachary Turner   // Here, the type HASH is a typedef of unsigned short.
36cafd4768SZachary Turner   // ** It is not a bug that we truncate the result of hashStringV1, in fact
37cafd4768SZachary Turner   //    it is a bug if we do not! **
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()
50*a6fb536eSZachary 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