1 //===- NamedStreamMap.cpp - PDB Named Stream Map --------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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"
27 using namespace llvm::pdb;
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",
37 NamedStreamMap::NamedStreamMap() = default;
39 Error NamedStreamMap::load(BinaryStreamReader &Stream) {
41 FinalizedHashTable.clear();
42 FinalizedInfo.reset();
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"));
50 BinaryStreamRef StringsBuffer;
51 if (auto EC = Stream.readStreamRef(StringsBuffer, StringBufferSize))
54 HashTable OffsetIndexMap;
55 if (auto EC = OffsetIndexMap.load(Stream))
60 for (const auto &Entry : OffsetIndexMap) {
61 std::tie(NameOffset, NameIndex) = Entry;
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.
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"));
73 // Add this to a string-map from name to stream number.
74 Mapping.insert({Str, NameIndex});
77 return Error::success();
80 Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const {
81 assert(FinalizedInfo.hasValue());
83 // The first field is the number of bytes of string data.
84 if (auto EC = Writer.writeInteger(FinalizedInfo->StringDataBytes))
87 for (const auto &Name : OrderedStreamNames) {
88 auto Item = Mapping.find(Name);
89 if (Item == Mapping.end())
91 if (auto EC = Writer.writeCString(Item->getKey()))
95 // And finally the Offset Index map.
96 if (auto EC = FinalizedHashTable.commit(Writer))
99 return Error::success();
102 uint32_t NamedStreamMap::finalize() {
103 if (FinalizedInfo.hasValue())
104 return FinalizedInfo->SerializedLength;
106 // Build the finalized hash table.
107 FinalizedHashTable.clear();
108 FinalizedInfo.emplace();
110 for (const auto &Name : OrderedStreamNames) {
111 auto Item = Mapping.find(Name);
112 if (Item == Mapping.end())
114 FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item->getValue());
115 FinalizedInfo->StringDataBytes += Item->getKeyLength() + 1;
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;
128 iterator_range<StringMapConstIterator<uint32_t>>
129 NamedStreamMap::entries() const {
130 return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
134 uint32_t NamedStreamMap::size() const { return Mapping.size(); }
136 bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const {
137 auto Iter = Mapping.find(Stream);
138 if (Iter == Mapping.end())
140 StreamNo = Iter->second;
144 void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) {
145 FinalizedInfo.reset();
146 Mapping[Stream] = StreamNo;
149 void NamedStreamMap::remove(StringRef Stream) {
150 FinalizedInfo.reset();
151 Mapping.erase(Stream);