Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/PDB/Native/GlobalsStream.cpp
35293 views
1
//===- GlobalsStream.cpp - PDB Index of Symbols by Name ---------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// The on-disk structores used in this file are based on the reference
10
// implementation which is available at
11
// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h
12
//
13
// When you are reading the reference source code, you'd find the
14
// information below useful.
15
//
16
// - ppdb1->m_fMinimalDbgInfo seems to be always true.
17
// - SMALLBUCKETS macro is defined.
18
//
19
//===----------------------------------------------------------------------===//
20
21
#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
22
23
#include "llvm/DebugInfo/CodeView/RecordName.h"
24
#include "llvm/DebugInfo/MSF/MappedBlockStream.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
GlobalsStream::GlobalsStream(std::unique_ptr<MappedBlockStream> Stream)
37
: Stream(std::move(Stream)) {}
38
39
GlobalsStream::~GlobalsStream() = default;
40
41
Error GlobalsStream::reload() {
42
BinaryStreamReader Reader(*Stream);
43
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
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
size_t ExpandedBucketIndex = hashStringV1(Name) % IPHR_HASH;
55
int32_t CompressedBucketIndex = GlobalsTable.BucketMap[ExpandedBucketIndex];
56
if (CompressedBucketIndex == -1)
57
return Result;
58
59
uint32_t LastBucketIndex = GlobalsTable.HashBuckets.size() - 1;
60
uint32_t StartRecordIndex =
61
GlobalsTable.HashBuckets[CompressedBucketIndex] / 12;
62
uint32_t EndRecordIndex = 0;
63
if (LLVM_LIKELY(uint32_t(CompressedBucketIndex) < LastBucketIndex)) {
64
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
EndRecordIndex = GlobalsTable.HashRecords.size() * 12;
69
}
70
71
EndRecordIndex /= 12;
72
73
assert(EndRecordIndex <= GlobalsTable.HashRecords.size());
74
while (StartRecordIndex < EndRecordIndex) {
75
PSHashRecord PSH = GlobalsTable.HashRecords[StartRecordIndex];
76
uint32_t Off = PSH.Off - 1;
77
codeview::CVSymbol Record = Symbols.readRecord(Off);
78
if (codeview::getSymbolName(Record) == Name)
79
Result.push_back(std::make_pair(Off, std::move(Record)));
80
++StartRecordIndex;
81
}
82
return Result;
83
}
84
85
static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) {
86
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
static Error readGSIHashHeader(const GSIHashHeader *&HashHdr,
95
BinaryStreamReader &Reader) {
96
if (Reader.readObject(HashHdr))
97
return make_error<RawError>(raw_error_code::corrupt_file,
98
"Stream does not contain a GSIHashHeader.");
99
100
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
static Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords,
109
const GSIHashHeader *HashHdr,
110
BinaryStreamReader &Reader) {
111
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
if (HashHdr->HrSize % sizeof(PSHashRecord))
117
return make_error<RawError>(raw_error_code::corrupt_file,
118
"Invalid HR array size.");
119
uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord);
120
if (auto EC = Reader.readArray(HashRecords, NumHashRecords))
121
return joinErrors(std::move(EC),
122
make_error<RawError>(raw_error_code::corrupt_file,
123
"Error reading hash records."));
124
125
return Error::success();
126
}
127
128
static Error
129
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
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
if (auto EC = Reader.readArray(HashBitmap, NumBitmapEntries))
142
return joinErrors(std::move(EC),
143
make_error<RawError>(raw_error_code::corrupt_file,
144
"Could not read a bitmap."));
145
uint32_t CompressedBucketIdx = 0;
146
for (uint32_t I = 0; I <= IPHR_HASH; ++I) {
147
uint8_t WordIdx = I / 32;
148
uint8_t BitIdx = I % 32;
149
bool IsSet = HashBitmap[WordIdx] & (1U << BitIdx);
150
if (IsSet) {
151
BucketMap[I] = CompressedBucketIdx++;
152
} else {
153
BucketMap[I] = -1;
154
}
155
}
156
157
uint32_t NumBuckets = 0;
158
for (uint32_t B : HashBitmap)
159
NumBuckets += llvm::popcount(B);
160
161
// Hash buckets follow.
162
if (auto EC = Reader.readArray(HashBuckets, NumBuckets))
163
return joinErrors(std::move(EC),
164
make_error<RawError>(raw_error_code::corrupt_file,
165
"Hash buckets corrupted."));
166
167
return Error::success();
168
}
169
170
Error GSIHashTable::read(BinaryStreamReader &Reader) {
171
if (auto EC = readGSIHashHeader(HashHdr, Reader))
172
return EC;
173
if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader))
174
return EC;
175
if (HashHdr->HrSize > 0)
176
if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr,
177
BucketMap, Reader))
178
return EC;
179
return Error::success();
180
}
181
182