Line data Source code
1 : //===- GlobalsStream.cpp - PDB Index of Symbols by Name ---------*- 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 : // The on-disk structores used in this file are based on the reference
11 : // implementation which is available at
12 : // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h
13 : //
14 : // When you are reading the reference source code, you'd find the
15 : // information below useful.
16 : //
17 : // - ppdb1->m_fMinimalDbgInfo seems to be always true.
18 : // - SMALLBUCKETS macro is defined.
19 : //
20 : //===----------------------------------------------------------------------===//
21 :
22 : #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
23 :
24 : #include "llvm/DebugInfo/CodeView/RecordName.h"
25 : #include "llvm/DebugInfo/PDB/Native/Hash.h"
26 : #include "llvm/DebugInfo/PDB/Native/RawError.h"
27 : #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
28 : #include "llvm/Support/BinaryStreamReader.h"
29 : #include "llvm/Support/Error.h"
30 : #include <algorithm>
31 :
32 : using namespace llvm;
33 : using namespace llvm::msf;
34 : using namespace llvm::pdb;
35 :
36 15 : GlobalsStream::GlobalsStream(std::unique_ptr<MappedBlockStream> Stream)
37 15 : : Stream(std::move(Stream)) {}
38 :
39 : GlobalsStream::~GlobalsStream() = default;
40 :
41 15 : Error GlobalsStream::reload() {
42 15 : BinaryStreamReader Reader(*Stream);
43 30 : if (auto E = GlobalsTable.read(Reader))
44 : return E;
45 : return Error::success();
46 : }
47 :
48 : std::vector<std::pair<uint32_t, codeview::CVSymbol>>
49 4 : GlobalsStream::findRecordsByName(StringRef Name,
50 : const SymbolStream &Symbols) const {
51 : std::vector<std::pair<uint32_t, codeview::CVSymbol>> Result;
52 :
53 : // Hash the name to figure out which bucket this goes into.
54 4 : size_t ExpandedBucketIndex = hashStringV1(Name) % IPHR_HASH;
55 4 : int32_t CompressedBucketIndex = GlobalsTable.BucketMap[ExpandedBucketIndex];
56 4 : if (CompressedBucketIndex == -1)
57 : return Result;
58 :
59 3 : uint32_t LastBucketIndex = GlobalsTable.HashBuckets.size() - 1;
60 : uint32_t StartRecordIndex =
61 3 : GlobalsTable.HashBuckets[CompressedBucketIndex] / 12;
62 : uint32_t EndRecordIndex = 0;
63 3 : if (LLVM_LIKELY(uint32_t(CompressedBucketIndex) < LastBucketIndex)) {
64 2 : EndRecordIndex = GlobalsTable.HashBuckets[CompressedBucketIndex + 1];
65 : } else {
66 : // If this is the last bucket, it consists of all hash records until the end
67 : // of the HashRecords array.
68 1 : EndRecordIndex = GlobalsTable.HashRecords.size() * 12;
69 : }
70 :
71 3 : EndRecordIndex /= 12;
72 :
73 : assert(EndRecordIndex <= GlobalsTable.HashRecords.size());
74 9 : while (StartRecordIndex < EndRecordIndex) {
75 6 : PSHashRecord PSH = GlobalsTable.HashRecords[StartRecordIndex];
76 6 : uint32_t Off = PSH.Off - 1;
77 6 : codeview::CVSymbol Record = Symbols.readRecord(Off);
78 12 : if (codeview::getSymbolName(Record) == Name)
79 6 : Result.push_back(std::make_pair(Off, std::move(Record)));
80 6 : ++StartRecordIndex;
81 : }
82 : return Result;
83 : }
84 :
85 35 : static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) {
86 35 : if (HashHdr->VerHdr != GSIHashHeader::HdrVersion)
87 : return make_error<RawError>(
88 : raw_error_code::feature_unsupported,
89 : "Encountered unsupported globals stream version.");
90 :
91 : return Error::success();
92 : }
93 :
94 18 : static Error readGSIHashHeader(const GSIHashHeader *&HashHdr,
95 : BinaryStreamReader &Reader) {
96 36 : if (Reader.readObject(HashHdr))
97 : return make_error<RawError>(raw_error_code::corrupt_file,
98 : "Stream does not contain a GSIHashHeader.");
99 :
100 36 : if (HashHdr->VerSignature != GSIHashHeader::HdrSignature)
101 : return make_error<RawError>(
102 : raw_error_code::feature_unsupported,
103 : "GSIHashHeader signature (0xffffffff) not found.");
104 :
105 : return Error::success();
106 : }
107 :
108 18 : static Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords,
109 : const GSIHashHeader *HashHdr,
110 : BinaryStreamReader &Reader) {
111 36 : if (auto EC = checkHashHdrVersion(HashHdr))
112 : return EC;
113 :
114 : // HashHdr->HrSize specifies the number of bytes of PSHashRecords we have.
115 : // Verify that we can read them all.
116 18 : if (HashHdr->HrSize % sizeof(PSHashRecord))
117 : return make_error<RawError>(raw_error_code::corrupt_file,
118 : "Invalid HR array size.");
119 18 : uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord);
120 36 : if (auto EC = Reader.readArray(HashRecords, NumHashRecords))
121 : return joinErrors(std::move(EC),
122 0 : make_error<RawError>(raw_error_code::corrupt_file,
123 0 : "Error reading hash records."));
124 :
125 : return Error::success();
126 : }
127 :
128 : static Error
129 0 : readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets,
130 : FixedStreamArray<support::ulittle32_t> &HashBitmap,
131 : const GSIHashHeader *HashHdr,
132 : MutableArrayRef<int32_t> BucketMap,
133 : BinaryStreamReader &Reader) {
134 0 : if (auto EC = checkHashHdrVersion(HashHdr))
135 : return EC;
136 :
137 : // Before the actual hash buckets, there is a bitmap of length determined by
138 : // IPHR_HASH.
139 : size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32);
140 : uint32_t NumBitmapEntries = BitmapSizeInBits / 32;
141 0 : if (auto EC = Reader.readArray(HashBitmap, NumBitmapEntries))
142 : return joinErrors(std::move(EC),
143 0 : make_error<RawError>(raw_error_code::corrupt_file,
144 0 : "Could not read a bitmap."));
145 : uint32_t NumBuckets1 = 0;
146 : uint32_t CompressedBucketIdx = 0;
147 0 : for (uint32_t I = 0; I <= IPHR_HASH; ++I) {
148 0 : uint8_t WordIdx = I / 32;
149 0 : uint8_t BitIdx = I % 32;
150 0 : bool IsSet = HashBitmap[WordIdx] & (1U << BitIdx);
151 0 : if (IsSet) {
152 0 : ++NumBuckets1;
153 0 : BucketMap[I] = CompressedBucketIdx++;
154 : } else {
155 0 : BucketMap[I] = -1;
156 : }
157 : }
158 :
159 : uint32_t NumBuckets = 0;
160 0 : for (uint32_t B : HashBitmap)
161 0 : NumBuckets += countPopulation(B);
162 :
163 : // Hash buckets follow.
164 0 : if (auto EC = Reader.readArray(HashBuckets, NumBuckets))
165 : return joinErrors(std::move(EC),
166 0 : make_error<RawError>(raw_error_code::corrupt_file,
167 0 : "Hash buckets corrupted."));
168 :
169 : return Error::success();
170 : }
171 :
172 18 : Error GSIHashTable::read(BinaryStreamReader &Reader) {
173 36 : if (auto EC = readGSIHashHeader(HashHdr, Reader))
174 : return EC;
175 36 : if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader))
176 : return EC;
177 36 : if (HashHdr->HrSize > 0)
178 17 : if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr,
179 17 : BucketMap, Reader))
180 : return EC;
181 : return Error::success();
182 : }
|