1 //===- NamedStreamMap.cpp - PDB Named Stream Map ----------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h"
11 
12 #include "llvm/ADT/SparseBitVector.h"
13 #include "llvm/ADT/StringMap.h"
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/ADT/iterator_range.h"
16 #include "llvm/DebugInfo/PDB/Native/HashTable.h"
17 #include "llvm/DebugInfo/PDB/Native/RawError.h"
18 #include "llvm/Support/BinaryStreamReader.h"
19 #include "llvm/Support/Error.h"
20 #include <algorithm>
21 #include <cstdint>
22 
23 using namespace llvm;
24 using namespace llvm::pdb;
25 
26 NamedStreamMap::NamedStreamMap() = default;
27 
28 Error NamedStreamMap::load(BinaryStreamReader &Stream) {
29   Mapping.clear();
30   FinalizedHashTable.clear();
31   FinalizedInfo.reset();
32 
33   uint32_t StringBufferSize;
34   if (auto EC = Stream.readInteger(StringBufferSize))
35     return joinErrors(std::move(EC),
36                       make_error<RawError>(raw_error_code::corrupt_file,
37                                            "Expected string buffer size"));
38 
39   BinaryStreamRef StringsBuffer;
40   if (auto EC = Stream.readStreamRef(StringsBuffer, StringBufferSize))
41     return EC;
42 
43   HashTable OffsetIndexMap;
44   if (auto EC = OffsetIndexMap.load(Stream))
45     return EC;
46 
47   uint32_t NameOffset;
48   uint32_t NameIndex;
49   for (const auto &Entry : OffsetIndexMap) {
50     std::tie(NameOffset, NameIndex) = Entry;
51 
52     // Compute the offset of the start of the string relative to the stream.
53     BinaryStreamReader NameReader(StringsBuffer);
54     NameReader.setOffset(NameOffset);
55     // Pump out our c-string from the stream.
56     StringRef Str;
57     if (auto EC = NameReader.readCString(Str))
58       return joinErrors(std::move(EC),
59                         make_error<RawError>(raw_error_code::corrupt_file,
60                                              "Expected name map name"));
61 
62     // Add this to a string-map from name to stream number.
63     Mapping.insert({Str, NameIndex});
64   }
65 
66   return Error::success();
67 }
68 
69 Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const {
70   assert(FinalizedInfo.hasValue());
71 
72   // The first field is the number of bytes of string data.
73   if (auto EC = Writer.writeInteger(FinalizedInfo->StringDataBytes))
74     return EC;
75 
76   // Now all of the string data itself.
77   for (const auto &Item : Mapping) {
78     if (auto EC = Writer.writeCString(Item.getKey()))
79       return EC;
80   }
81 
82   // And finally the Offset Index map.
83   if (auto EC = FinalizedHashTable.commit(Writer))
84     return EC;
85 
86   return Error::success();
87 }
88 
89 uint32_t NamedStreamMap::finalize() {
90   if (FinalizedInfo.hasValue())
91     return FinalizedInfo->SerializedLength;
92 
93   // Build the finalized hash table.
94   FinalizedHashTable.clear();
95   FinalizedInfo.emplace();
96   for (const auto &Item : Mapping) {
97     FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item.getValue());
98     FinalizedInfo->StringDataBytes += Item.getKeyLength() + 1;
99   }
100 
101   // Number of bytes of string data.
102   FinalizedInfo->SerializedLength += sizeof(support::ulittle32_t);
103   // Followed by that many actual bytes of string data.
104   FinalizedInfo->SerializedLength += FinalizedInfo->StringDataBytes;
105   // Followed by the mapping from Offset to Index.
106   FinalizedInfo->SerializedLength +=
107       FinalizedHashTable.calculateSerializedLength();
108   return FinalizedInfo->SerializedLength;
109 }
110 
111 iterator_range<StringMapConstIterator<uint32_t>>
112 NamedStreamMap::entries() const {
113   return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
114                                                       Mapping.end());
115 }
116 
117 bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const {
118   auto Iter = Mapping.find(Stream);
119   if (Iter == Mapping.end())
120     return false;
121   StreamNo = Iter->second;
122   return true;
123 }
124 
125 void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) {
126   FinalizedInfo.reset();
127   Mapping[Stream] = StreamNo;
128 }
129 
130 void NamedStreamMap::remove(StringRef Stream) {
131   FinalizedInfo.reset();
132   Mapping.erase(Stream);
133 }
134