1 //===- NameMap.cpp - PDB Name 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/Raw/NameMap.h"
11 #include "llvm/ADT/SparseBitVector.h"
12 #include "llvm/DebugInfo/CodeView/StreamReader.h"
13 #include "llvm/DebugInfo/CodeView/StreamWriter.h"
14 #include "llvm/DebugInfo/PDB/Raw/RawError.h"
15
16 using namespace llvm;
17 using namespace llvm::codeview;
18 using namespace llvm::pdb;
19
NameMap()20 NameMap::NameMap() {}
21
load(codeview::StreamReader & Stream)22 Error NameMap::load(codeview::StreamReader &Stream) {
23
24 // This is some sort of weird string-set/hash table encoded in the stream.
25 // It starts with the number of bytes in the table.
26 uint32_t NumberOfBytes;
27 if (auto EC = Stream.readInteger(NumberOfBytes))
28 return joinErrors(std::move(EC),
29 make_error<RawError>(raw_error_code::corrupt_file,
30 "Expected name map length"));
31 if (Stream.bytesRemaining() < NumberOfBytes)
32 return make_error<RawError>(raw_error_code::corrupt_file,
33 "Invalid name map length");
34
35 // Following that field is the starting offset of strings in the name table.
36 uint32_t StringsOffset = Stream.getOffset();
37 Stream.setOffset(StringsOffset + NumberOfBytes);
38
39 // This appears to be equivalent to the total number of strings *actually*
40 // in the name table.
41 uint32_t HashSize;
42 if (auto EC = Stream.readInteger(HashSize))
43 return joinErrors(std::move(EC),
44 make_error<RawError>(raw_error_code::corrupt_file,
45 "Expected name map hash size"));
46
47 // This appears to be an upper bound on the number of strings in the name
48 // table.
49 uint32_t MaxNumberOfStrings;
50 if (auto EC = Stream.readInteger(MaxNumberOfStrings))
51 return joinErrors(std::move(EC),
52 make_error<RawError>(raw_error_code::corrupt_file,
53 "Expected name map max strings"));
54
55 if (MaxNumberOfStrings > (UINT32_MAX / sizeof(uint32_t)))
56 return make_error<RawError>(raw_error_code::corrupt_file,
57 "Implausible number of strings");
58
59 const uint32_t MaxNumberOfWords = UINT32_MAX / (sizeof(uint32_t) * 8);
60
61 // This appears to be a hash table which uses bitfields to determine whether
62 // or not a bucket is 'present'.
63 uint32_t NumPresentWords;
64 if (auto EC = Stream.readInteger(NumPresentWords))
65 return joinErrors(std::move(EC),
66 make_error<RawError>(raw_error_code::corrupt_file,
67 "Expected name map num words"));
68
69 if (NumPresentWords > MaxNumberOfWords)
70 return make_error<RawError>(raw_error_code::corrupt_file,
71 "Number of present words is too large");
72
73 SparseBitVector<> Present;
74 for (uint32_t I = 0; I != NumPresentWords; ++I) {
75 uint32_t Word;
76 if (auto EC = Stream.readInteger(Word))
77 return joinErrors(std::move(EC),
78 make_error<RawError>(raw_error_code::corrupt_file,
79 "Expected name map word"));
80 for (unsigned Idx = 0; Idx < 32; ++Idx)
81 if (Word & (1U << Idx))
82 Present.set((I * 32) + Idx);
83 }
84
85 // This appears to be a hash table which uses bitfields to determine whether
86 // or not a bucket is 'deleted'.
87 uint32_t NumDeletedWords;
88 if (auto EC = Stream.readInteger(NumDeletedWords))
89 return joinErrors(
90 std::move(EC),
91 make_error<RawError>(raw_error_code::corrupt_file,
92 "Expected name map num deleted words"));
93
94 if (NumDeletedWords > MaxNumberOfWords)
95 return make_error<RawError>(raw_error_code::corrupt_file,
96 "Number of deleted words is too large");
97
98 SparseBitVector<> Deleted;
99 for (uint32_t I = 0; I != NumDeletedWords; ++I) {
100 uint32_t Word;
101 if (auto EC = Stream.readInteger(Word))
102 return joinErrors(std::move(EC),
103 make_error<RawError>(raw_error_code::corrupt_file,
104 "Expected name map word"));
105 for (unsigned Idx = 0; Idx < 32; ++Idx)
106 if (Word & (1U << Idx))
107 Deleted.set((I * 32) + Idx);
108 }
109
110 for (unsigned I : Present) {
111 // For all present entries, dump out their mapping.
112 (void)I;
113
114 // This appears to be an offset relative to the start of the strings.
115 // It tells us where the null-terminated string begins.
116 uint32_t NameOffset;
117 if (auto EC = Stream.readInteger(NameOffset))
118 return joinErrors(std::move(EC),
119 make_error<RawError>(raw_error_code::corrupt_file,
120 "Expected name map name offset"));
121
122 // This appears to be a stream number into the stream directory.
123 uint32_t NameIndex;
124 if (auto EC = Stream.readInteger(NameIndex))
125 return joinErrors(std::move(EC),
126 make_error<RawError>(raw_error_code::corrupt_file,
127 "Expected name map name index"));
128
129 // Compute the offset of the start of the string relative to the stream.
130 uint32_t StringOffset = StringsOffset + NameOffset;
131 uint32_t OldOffset = Stream.getOffset();
132 // Pump out our c-string from the stream.
133 StringRef Str;
134 Stream.setOffset(StringOffset);
135 if (auto EC = Stream.readZeroString(Str))
136 return joinErrors(std::move(EC),
137 make_error<RawError>(raw_error_code::corrupt_file,
138 "Expected name map name"));
139
140 Stream.setOffset(OldOffset);
141 // Add this to a string-map from name to stream number.
142 Mapping.insert({Str, NameIndex});
143 }
144
145 return Error::success();
146 }
147
commit(codeview::StreamWriter & Writer)148 Error NameMap::commit(codeview::StreamWriter &Writer) {
149 if (auto EC = Writer.writeInteger(0U)) // Number of bytes in table
150 return EC;
151
152 if (auto EC = Writer.writeInteger(0U)) // Hash Size
153 return EC;
154
155 if (auto EC = Writer.writeInteger(0U)) // Max Number of Strings
156 return EC;
157
158 if (auto EC = Writer.writeInteger(0U)) // Num Present Words
159 return EC;
160
161 if (auto EC = Writer.writeInteger(0U)) // Num Deleted Words
162 return EC;
163 return Error::success();
164 }
165
entries() const166 iterator_range<StringMapConstIterator<uint32_t>> NameMap::entries() const {
167 return llvm::make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
168 Mapping.end());
169 }
170
tryGetValue(StringRef Name,uint32_t & Value) const171 bool NameMap::tryGetValue(StringRef Name, uint32_t &Value) const {
172 auto Iter = Mapping.find(Name);
173 if (Iter == Mapping.end())
174 return false;
175 Value = Iter->second;
176 return true;
177 }
178