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