121
|
1 //===- NamedStreamMap.cpp - PDB Named Stream Map --------------------------===//
|
|
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 #include "llvm/ADT/StringMap.h"
|
|
12 #include "llvm/ADT/StringRef.h"
|
|
13 #include "llvm/ADT/iterator_range.h"
|
|
14 #include "llvm/DebugInfo/PDB/Native/HashTable.h"
|
|
15 #include "llvm/DebugInfo/PDB/Native/RawError.h"
|
|
16 #include "llvm/Support/BinaryStreamReader.h"
|
|
17 #include "llvm/Support/BinaryStreamRef.h"
|
|
18 #include "llvm/Support/BinaryStreamWriter.h"
|
|
19 #include "llvm/Support/Endian.h"
|
|
20 #include "llvm/Support/Error.h"
|
|
21 #include <algorithm>
|
|
22 #include <cassert>
|
|
23 #include <cstdint>
|
|
24 #include <tuple>
|
|
25
|
|
26 using namespace llvm;
|
|
27 using namespace llvm::pdb;
|
|
28
|
|
29 // FIXME: This shouldn't be necessary, but if we insert the strings in any
|
|
30 // other order, cvdump cannot read the generated name map. This suggests that
|
|
31 // we may be using the wrong hash function. A closer inspection of the cvdump
|
|
32 // source code may reveal something, but for now this at least makes us work,
|
|
33 // even if only by accident.
|
|
34 static constexpr const char *OrderedStreamNames[] = {"/LinkInfo", "/names",
|
|
35 "/src/headerblock"};
|
|
36
|
|
37 NamedStreamMap::NamedStreamMap() = default;
|
|
38
|
|
39 Error NamedStreamMap::load(BinaryStreamReader &Stream) {
|
|
40 Mapping.clear();
|
|
41 FinalizedHashTable.clear();
|
|
42 FinalizedInfo.reset();
|
|
43
|
|
44 uint32_t StringBufferSize;
|
|
45 if (auto EC = Stream.readInteger(StringBufferSize))
|
|
46 return joinErrors(std::move(EC),
|
|
47 make_error<RawError>(raw_error_code::corrupt_file,
|
|
48 "Expected string buffer size"));
|
|
49
|
|
50 BinaryStreamRef StringsBuffer;
|
|
51 if (auto EC = Stream.readStreamRef(StringsBuffer, StringBufferSize))
|
|
52 return EC;
|
|
53
|
|
54 HashTable OffsetIndexMap;
|
|
55 if (auto EC = OffsetIndexMap.load(Stream))
|
|
56 return EC;
|
|
57
|
|
58 uint32_t NameOffset;
|
|
59 uint32_t NameIndex;
|
|
60 for (const auto &Entry : OffsetIndexMap) {
|
|
61 std::tie(NameOffset, NameIndex) = Entry;
|
|
62
|
|
63 // Compute the offset of the start of the string relative to the stream.
|
|
64 BinaryStreamReader NameReader(StringsBuffer);
|
|
65 NameReader.setOffset(NameOffset);
|
|
66 // Pump out our c-string from the stream.
|
|
67 StringRef Str;
|
|
68 if (auto EC = NameReader.readCString(Str))
|
|
69 return joinErrors(std::move(EC),
|
|
70 make_error<RawError>(raw_error_code::corrupt_file,
|
|
71 "Expected name map name"));
|
|
72
|
|
73 // Add this to a string-map from name to stream number.
|
|
74 Mapping.insert({Str, NameIndex});
|
|
75 }
|
|
76
|
|
77 return Error::success();
|
|
78 }
|
|
79
|
|
80 Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const {
|
|
81 assert(FinalizedInfo.hasValue());
|
|
82
|
|
83 // The first field is the number of bytes of string data.
|
|
84 if (auto EC = Writer.writeInteger(FinalizedInfo->StringDataBytes))
|
|
85 return EC;
|
|
86
|
|
87 for (const auto &Name : OrderedStreamNames) {
|
|
88 auto Item = Mapping.find(Name);
|
|
89 if (Item == Mapping.end())
|
|
90 continue;
|
|
91 if (auto EC = Writer.writeCString(Item->getKey()))
|
|
92 return EC;
|
|
93 }
|
|
94
|
|
95 // And finally the Offset Index map.
|
|
96 if (auto EC = FinalizedHashTable.commit(Writer))
|
|
97 return EC;
|
|
98
|
|
99 return Error::success();
|
|
100 }
|
|
101
|
|
102 uint32_t NamedStreamMap::finalize() {
|
|
103 if (FinalizedInfo.hasValue())
|
|
104 return FinalizedInfo->SerializedLength;
|
|
105
|
|
106 // Build the finalized hash table.
|
|
107 FinalizedHashTable.clear();
|
|
108 FinalizedInfo.emplace();
|
|
109
|
|
110 for (const auto &Name : OrderedStreamNames) {
|
|
111 auto Item = Mapping.find(Name);
|
|
112 if (Item == Mapping.end())
|
|
113 continue;
|
|
114 FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item->getValue());
|
|
115 FinalizedInfo->StringDataBytes += Item->getKeyLength() + 1;
|
|
116 }
|
|
117
|
|
118 // Number of bytes of string data.
|
|
119 FinalizedInfo->SerializedLength += sizeof(support::ulittle32_t);
|
|
120 // Followed by that many actual bytes of string data.
|
|
121 FinalizedInfo->SerializedLength += FinalizedInfo->StringDataBytes;
|
|
122 // Followed by the mapping from Offset to Index.
|
|
123 FinalizedInfo->SerializedLength +=
|
|
124 FinalizedHashTable.calculateSerializedLength();
|
|
125 return FinalizedInfo->SerializedLength;
|
|
126 }
|
|
127
|
|
128 iterator_range<StringMapConstIterator<uint32_t>>
|
|
129 NamedStreamMap::entries() const {
|
|
130 return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
|
|
131 Mapping.end());
|
|
132 }
|
|
133
|
|
134 uint32_t NamedStreamMap::size() const { return Mapping.size(); }
|
|
135
|
|
136 bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const {
|
|
137 auto Iter = Mapping.find(Stream);
|
|
138 if (Iter == Mapping.end())
|
|
139 return false;
|
|
140 StreamNo = Iter->second;
|
|
141 return true;
|
|
142 }
|
|
143
|
|
144 void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) {
|
|
145 FinalizedInfo.reset();
|
|
146 Mapping[Stream] = StreamNo;
|
|
147 }
|
|
148
|
|
149 void NamedStreamMap::remove(StringRef Stream) {
|
|
150 FinalizedInfo.reset();
|
|
151 Mapping.erase(Stream);
|
|
152 }
|