/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 128 | NamedStreamMap::NamedStreamMap() = default; |
38 | | |
39 | 68 | Error NamedStreamMap::load(BinaryStreamReader &Stream) { |
40 | 68 | Mapping.clear(); |
41 | 68 | FinalizedHashTable.clear(); |
42 | 68 | FinalizedInfo.reset(); |
43 | 68 | |
44 | 68 | uint32_t StringBufferSize; |
45 | 68 | if (auto EC = Stream.readInteger(StringBufferSize)) |
46 | 0 | return joinErrors(std::move(EC), |
47 | 0 | make_error<RawError>(raw_error_code::corrupt_file, |
48 | 0 | "Expected string buffer size")); |
49 | 68 | |
50 | 68 | BinaryStreamRef StringsBuffer; |
51 | 68 | if (auto EC = Stream.readStreamRef(StringsBuffer, StringBufferSize)) |
52 | 0 | return EC; |
53 | 68 | |
54 | 68 | HashTable OffsetIndexMap; |
55 | 68 | if (auto EC = OffsetIndexMap.load(Stream)) |
56 | 0 | return EC; |
57 | 68 | |
58 | 68 | uint32_t NameOffset; |
59 | 68 | uint32_t NameIndex; |
60 | 165 | for (const auto &Entry : OffsetIndexMap) { |
61 | 165 | std::tie(NameOffset, NameIndex) = Entry; |
62 | 165 | |
63 | 165 | // Compute the offset of the start of the string relative to the stream. |
64 | 165 | BinaryStreamReader NameReader(StringsBuffer); |
65 | 165 | NameReader.setOffset(NameOffset); |
66 | 165 | // Pump out our c-string from the stream. |
67 | 165 | StringRef Str; |
68 | 165 | if (auto EC = NameReader.readCString(Str)) |
69 | 0 | return joinErrors(std::move(EC), |
70 | 0 | make_error<RawError>(raw_error_code::corrupt_file, |
71 | 0 | "Expected name map name")); |
72 | 165 | |
73 | 165 | // Add this to a string-map from name to stream number. |
74 | 165 | Mapping.insert({Str, NameIndex}); |
75 | 165 | } |
76 | 68 | |
77 | 68 | return Error::success(); |
78 | 68 | } |
79 | | |
80 | 60 | Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const { |
81 | 60 | assert(FinalizedInfo.hasValue()); |
82 | 60 | |
83 | 60 | // The first field is the number of bytes of string data. |
84 | 60 | if (auto EC = Writer.writeInteger(FinalizedInfo->StringDataBytes)) |
85 | 0 | return EC; |
86 | 60 | |
87 | 60 | for (const auto &Name : OrderedStreamNames) 60 { |
88 | 180 | auto Item = Mapping.find(Name); |
89 | 180 | if (Item == Mapping.end()) |
90 | 60 | continue; |
91 | 120 | if (auto 120 EC120 = Writer.writeCString(Item->getKey())) |
92 | 0 | return EC; |
93 | 60 | } |
94 | 60 | |
95 | 60 | // And finally the Offset Index map. |
96 | 60 | if (auto 60 EC60 = FinalizedHashTable.commit(Writer)) |
97 | 0 | return EC; |
98 | 60 | |
99 | 60 | return Error::success(); |
100 | 60 | } |
101 | | |
102 | 60 | uint32_t NamedStreamMap::finalize() { |
103 | 60 | if (FinalizedInfo.hasValue()) |
104 | 0 | return FinalizedInfo->SerializedLength; |
105 | 60 | |
106 | 60 | // Build the finalized hash table. |
107 | 60 | FinalizedHashTable.clear(); |
108 | 60 | FinalizedInfo.emplace(); |
109 | 60 | |
110 | 180 | for (const auto &Name : OrderedStreamNames) { |
111 | 180 | auto Item = Mapping.find(Name); |
112 | 180 | if (Item == Mapping.end()) |
113 | 60 | continue; |
114 | 120 | FinalizedHashTable.set(FinalizedInfo->StringDataBytes, Item->getValue()); |
115 | 120 | FinalizedInfo->StringDataBytes += Item->getKeyLength() + 1; |
116 | 120 | } |
117 | 60 | |
118 | 60 | // Number of bytes of string data. |
119 | 60 | FinalizedInfo->SerializedLength += sizeof(support::ulittle32_t); |
120 | 60 | // Followed by that many actual bytes of string data. |
121 | 60 | FinalizedInfo->SerializedLength += FinalizedInfo->StringDataBytes; |
122 | 60 | // Followed by the mapping from Offset to Index. |
123 | 60 | FinalizedInfo->SerializedLength += |
124 | 60 | FinalizedHashTable.calculateSerializedLength(); |
125 | 60 | return FinalizedInfo->SerializedLength; |
126 | 60 | } |
127 | | |
128 | | iterator_range<StringMapConstIterator<uint32_t>> |
129 | 11 | NamedStreamMap::entries() const { |
130 | 11 | return make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(), |
131 | 11 | Mapping.end()); |
132 | 11 | } |
133 | | |
134 | 0 | uint32_t NamedStreamMap::size() const { return Mapping.size(); } |
135 | | |
136 | 97 | bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const { |
137 | 97 | auto Iter = Mapping.find(Stream); |
138 | 97 | if (Iter == Mapping.end()) |
139 | 0 | return false; |
140 | 97 | StreamNo = Iter->second; |
141 | 97 | return true; |
142 | 97 | } |
143 | | |
144 | 120 | void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) { |
145 | 120 | FinalizedInfo.reset(); |
146 | 120 | Mapping[Stream] = StreamNo; |
147 | 120 | } |
148 | | |
149 | 0 | void NamedStreamMap::remove(StringRef Stream) { |
150 | 0 | FinalizedInfo.reset(); |
151 | 0 | Mapping.erase(Stream); |
152 | 0 | } |