]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp
MFV r336490:
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / DebugInfo / PDB / Native / NamedStreamMap.cpp
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 }