blob: 62a86dac03856137785b496d63a9abd154ccb358 [file] [log] [blame]
Zachary Turner2f09b502016-04-29 17:28:47 +00001//===- NameMap.cpp - PDB Name Map -------------------------------*- C++ -*-===//
Zachary Turnerf34e0162016-04-26 16:20:00 +00002//
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
Zachary Turner2f09b502016-04-29 17:28:47 +000010#include "llvm/DebugInfo/PDB/Raw/NameMap.h"
Zachary Turnerf34e0162016-04-26 16:20:00 +000011#include "llvm/ADT/BitVector.h"
Zachary Turnerd5d37dc2016-05-25 20:37:03 +000012#include "llvm/DebugInfo/CodeView/StreamReader.h"
Zachary Turner819e77d2016-05-06 20:51:57 +000013#include "llvm/DebugInfo/PDB/Raw/RawError.h"
Zachary Turnerf34e0162016-04-26 16:20:00 +000014
15using namespace llvm;
Zachary Turner2f09b502016-04-29 17:28:47 +000016using namespace llvm::pdb;
Zachary Turnerf34e0162016-04-26 16:20:00 +000017
Zachary Turner2f09b502016-04-29 17:28:47 +000018NameMap::NameMap() {}
Zachary Turnerf34e0162016-04-26 16:20:00 +000019
Zachary Turnerd5d37dc2016-05-25 20:37:03 +000020Error NameMap::load(codeview::StreamReader &Stream) {
Zachary Turner6ba65de2016-04-29 17:22:58 +000021
Zachary Turnerf34e0162016-04-26 16:20:00 +000022 // This is some sort of weird string-set/hash table encoded in the stream.
23 // It starts with the number of bytes in the table.
24 uint32_t NumberOfBytes;
David Majnemer836937e2016-05-27 16:16:56 +000025 if (auto EC = Stream.readInteger(NumberOfBytes))
26 return joinErrors(std::move(EC),
27 make_error<RawError>(raw_error_code::corrupt_file,
28 "Expected name map length"));
Zachary Turner819e77d2016-05-06 20:51:57 +000029 if (Stream.bytesRemaining() < NumberOfBytes)
30 return make_error<RawError>(raw_error_code::corrupt_file,
31 "Invalid name map length");
Zachary Turnerf34e0162016-04-26 16:20:00 +000032
33 // Following that field is the starting offset of strings in the name table.
34 uint32_t StringsOffset = Stream.getOffset();
35 Stream.setOffset(StringsOffset + NumberOfBytes);
36
37 // This appears to be equivalent to the total number of strings *actually*
38 // in the name table.
39 uint32_t HashSize;
David Majnemer836937e2016-05-27 16:16:56 +000040 if (auto EC = Stream.readInteger(HashSize))
41 return joinErrors(std::move(EC),
42 make_error<RawError>(raw_error_code::corrupt_file,
43 "Expected name map hash size"));
Zachary Turnerf34e0162016-04-26 16:20:00 +000044
45 // This appears to be an upper bound on the number of strings in the name
46 // table.
47 uint32_t MaxNumberOfStrings;
David Majnemer836937e2016-05-27 16:16:56 +000048 if (auto EC = Stream.readInteger(MaxNumberOfStrings))
49 return joinErrors(std::move(EC),
50 make_error<RawError>(raw_error_code::corrupt_file,
51 "Expected name map max strings"));
Zachary Turnerf34e0162016-04-26 16:20:00 +000052
David Majnemer328b6d32016-05-28 18:03:37 +000053 if (MaxNumberOfStrings > (UINT32_MAX / sizeof(uint32_t)))
54 return make_error<RawError>(raw_error_code::corrupt_file,
55 "Implausible number of strings");
56
57 const uint32_t MaxNumberOfWords = UINT32_MAX / (sizeof(uint32_t) * 8);
David Majnemer869631f2016-05-28 05:59:25 +000058
Zachary Turnerf34e0162016-04-26 16:20:00 +000059 // This appears to be a hash table which uses bitfields to determine whether
60 // or not a bucket is 'present'.
61 uint32_t NumPresentWords;
David Majnemer836937e2016-05-27 16:16:56 +000062 if (auto EC = Stream.readInteger(NumPresentWords))
63 return joinErrors(std::move(EC),
64 make_error<RawError>(raw_error_code::corrupt_file,
65 "Expected name map num words"));
Zachary Turnerf34e0162016-04-26 16:20:00 +000066
David Majnemer869631f2016-05-28 05:59:25 +000067 if (NumPresentWords > MaxNumberOfWords)
68 return make_error<RawError>(raw_error_code::corrupt_file,
69 "Number of present words is too large");
70
Zachary Turnerf34e0162016-04-26 16:20:00 +000071 // Store all the 'present' bits in a vector for later processing.
72 SmallVector<uint32_t, 1> PresentWords;
73 for (uint32_t I = 0; I != NumPresentWords; ++I) {
74 uint32_t Word;
David Majnemer836937e2016-05-27 16:16:56 +000075 if (auto EC = Stream.readInteger(Word))
76 return joinErrors(std::move(EC),
77 make_error<RawError>(raw_error_code::corrupt_file,
78 "Expected name map word"));
Zachary Turner819e77d2016-05-06 20:51:57 +000079
Zachary Turnerf34e0162016-04-26 16:20:00 +000080 PresentWords.push_back(Word);
81 }
82
83 // This appears to be a hash table which uses bitfields to determine whether
84 // or not a bucket is 'deleted'.
85 uint32_t NumDeletedWords;
David Majnemer836937e2016-05-27 16:16:56 +000086 if (auto EC = Stream.readInteger(NumDeletedWords))
87 return joinErrors(
88 std::move(EC),
89 make_error<RawError>(raw_error_code::corrupt_file,
90 "Expected name map num deleted words"));
Zachary Turnerf34e0162016-04-26 16:20:00 +000091
David Majnemer869631f2016-05-28 05:59:25 +000092 if (NumDeletedWords > MaxNumberOfWords)
93 return make_error<RawError>(raw_error_code::corrupt_file,
94 "Number of deleted words is too large");
95
Zachary Turnerf34e0162016-04-26 16:20:00 +000096 // Store all the 'deleted' bits in a vector for later processing.
97 SmallVector<uint32_t, 1> DeletedWords;
98 for (uint32_t I = 0; I != NumDeletedWords; ++I) {
99 uint32_t Word;
David Majnemer836937e2016-05-27 16:16:56 +0000100 if (auto EC = Stream.readInteger(Word))
101 return joinErrors(std::move(EC),
102 make_error<RawError>(raw_error_code::corrupt_file,
103 "Expected name map deleted word"));
Zachary Turner819e77d2016-05-06 20:51:57 +0000104
Zachary Turnerf34e0162016-04-26 16:20:00 +0000105 DeletedWords.push_back(Word);
106 }
107
108 BitVector Present(MaxNumberOfStrings, false);
109 if (!PresentWords.empty())
110 Present.setBitsInMask(PresentWords.data(), PresentWords.size());
111 BitVector Deleted(MaxNumberOfStrings, false);
112 if (!DeletedWords.empty())
113 Deleted.setBitsInMask(DeletedWords.data(), DeletedWords.size());
114
115 for (uint32_t I = 0; I < MaxNumberOfStrings; ++I) {
116 if (!Present.test(I))
117 continue;
118
119 // For all present entries, dump out their mapping.
120
121 // This appears to be an offset relative to the start of the strings.
122 // It tells us where the null-terminated string begins.
123 uint32_t NameOffset;
David Majnemer836937e2016-05-27 16:16:56 +0000124 if (auto EC = Stream.readInteger(NameOffset))
125 return joinErrors(std::move(EC),
126 make_error<RawError>(raw_error_code::corrupt_file,
127 "Expected name map name offset"));
Zachary Turnerf34e0162016-04-26 16:20:00 +0000128
129 // This appears to be a stream number into the stream directory.
130 uint32_t NameIndex;
David Majnemer836937e2016-05-27 16:16:56 +0000131 if (auto EC = Stream.readInteger(NameIndex))
132 return joinErrors(std::move(EC),
133 make_error<RawError>(raw_error_code::corrupt_file,
134 "Expected name map name index"));
Zachary Turnerf34e0162016-04-26 16:20:00 +0000135
136 // Compute the offset of the start of the string relative to the stream.
137 uint32_t StringOffset = StringsOffset + NameOffset;
138 uint32_t OldOffset = Stream.getOffset();
139 // Pump out our c-string from the stream.
Zachary Turner8dbe3622016-05-27 01:54:44 +0000140 StringRef Str;
Zachary Turnerf34e0162016-04-26 16:20:00 +0000141 Stream.setOffset(StringOffset);
David Majnemer836937e2016-05-27 16:16:56 +0000142 if (auto EC = Stream.readZeroString(Str))
143 return joinErrors(std::move(EC),
144 make_error<RawError>(raw_error_code::corrupt_file,
145 "Expected name map name"));
Zachary Turnerf34e0162016-04-26 16:20:00 +0000146
147 Stream.setOffset(OldOffset);
148 // Add this to a string-map from name to stream number.
149 Mapping.insert({Str, NameIndex});
150 }
151
Zachary Turner819e77d2016-05-06 20:51:57 +0000152 return Error::success();
Zachary Turnerf34e0162016-04-26 16:20:00 +0000153}
154
Zachary Turner85ed80b2016-05-25 03:43:17 +0000155iterator_range<StringMapConstIterator<uint32_t>> NameMap::entries() const {
156 return llvm::make_range<StringMapConstIterator<uint32_t>>(Mapping.begin(),
157 Mapping.end());
158}
159
Zachary Turner2f09b502016-04-29 17:28:47 +0000160bool NameMap::tryGetValue(StringRef Name, uint32_t &Value) const {
Zachary Turnerf34e0162016-04-26 16:20:00 +0000161 auto Iter = Mapping.find(Name);
162 if (Iter == Mapping.end())
163 return false;
164 Value = Iter->second;
165 return true;
166}