LLVM 20.0.0git
DbiStream.cpp
Go to the documentation of this file.
1//===- DbiStream.cpp - PDB Dbi Stream (Stream 3) Access -------------------===//
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
10#include "llvm/ADT/StringRef.h"
18#include "llvm/Object/COFF.h"
21#include "llvm/Support/Error.h"
22#include <cstddef>
23#include <cstdint>
24
25using namespace llvm;
26using namespace llvm::codeview;
27using namespace llvm::msf;
28using namespace llvm::pdb;
29using namespace llvm::support;
30
31template <typename ContribType>
33 BinaryStreamReader &Reader) {
34 if (Reader.bytesRemaining() % sizeof(ContribType) != 0)
35 return make_error<RawError>(
36 raw_error_code::corrupt_file,
37 "Invalid number of bytes of section contributions");
38
39 uint32_t Count = Reader.bytesRemaining() / sizeof(ContribType);
40 if (auto EC = Reader.readArray(Output, Count))
41 return EC;
42 return Error::success();
43}
44
45DbiStream::DbiStream(std::unique_ptr<BinaryStream> Stream)
46 : Stream(std::move(Stream)), Header(nullptr) {}
47
48DbiStream::~DbiStream() = default;
49
51 BinaryStreamReader Reader(*Stream);
52
53 if (Stream->getLength() < sizeof(DbiStreamHeader))
54 return make_error<RawError>(raw_error_code::corrupt_file,
55 "DBI Stream does not contain a header.");
56 if (auto EC = Reader.readObject(Header))
57 return make_error<RawError>(raw_error_code::corrupt_file,
58 "DBI Stream does not contain a header.");
59
60 if (Header->VersionSignature != -1)
61 return make_error<RawError>(raw_error_code::corrupt_file,
62 "Invalid DBI version signature.");
63
64 // Require at least version 7, which should be present in all PDBs
65 // produced in the last decade and allows us to avoid having to
66 // special case all kinds of complicated arcane formats.
67 if (Header->VersionHeader < PdbDbiV70)
68 return make_error<RawError>(raw_error_code::feature_unsupported,
69 "Unsupported DBI version.");
70
71 if (Stream->getLength() !=
72 sizeof(DbiStreamHeader) + Header->ModiSubstreamSize +
73 Header->SecContrSubstreamSize + Header->SectionMapSize +
74 Header->FileInfoSize + Header->TypeServerSize +
75 Header->OptionalDbgHdrSize + Header->ECSubstreamSize)
76 return make_error<RawError>(raw_error_code::corrupt_file,
77 "DBI Length does not equal sum of substreams.");
78
79 // Only certain substreams are guaranteed to be aligned. Validate
80 // them here.
81 if (Header->ModiSubstreamSize % sizeof(uint32_t) != 0)
82 return make_error<RawError>(raw_error_code::corrupt_file,
83 "DBI MODI substream not aligned.");
84 if (Header->SecContrSubstreamSize % sizeof(uint32_t) != 0)
85 return make_error<RawError>(
87 "DBI section contribution substream not aligned.");
88 if (Header->SectionMapSize % sizeof(uint32_t) != 0)
89 return make_error<RawError>(raw_error_code::corrupt_file,
90 "DBI section map substream not aligned.");
91 if (Header->FileInfoSize % sizeof(uint32_t) != 0)
92 return make_error<RawError>(raw_error_code::corrupt_file,
93 "DBI file info substream not aligned.");
94 if (Header->TypeServerSize % sizeof(uint32_t) != 0)
95 return make_error<RawError>(raw_error_code::corrupt_file,
96 "DBI type server substream not aligned.");
97
98 if (auto EC = Reader.readSubstream(ModiSubstream, Header->ModiSubstreamSize))
99 return EC;
100
101 if (auto EC = Reader.readSubstream(SecContrSubstream,
102 Header->SecContrSubstreamSize))
103 return EC;
104 if (auto EC = Reader.readSubstream(SecMapSubstream, Header->SectionMapSize))
105 return EC;
106 if (auto EC = Reader.readSubstream(FileInfoSubstream, Header->FileInfoSize))
107 return EC;
108 if (auto EC =
109 Reader.readSubstream(TypeServerMapSubstream, Header->TypeServerSize))
110 return EC;
111 if (auto EC = Reader.readSubstream(ECSubstream, Header->ECSubstreamSize))
112 return EC;
113 if (auto EC = Reader.readArray(
114 DbgStreams, Header->OptionalDbgHdrSize / sizeof(ulittle16_t)))
115 return EC;
116
117 if (auto EC = Modules.initialize(ModiSubstream.StreamData,
118 FileInfoSubstream.StreamData))
119 return EC;
120
121 if (auto EC = initializeSectionContributionData())
122 return EC;
123 if (auto EC = initializeSectionHeadersData(Pdb))
124 return EC;
125 if (auto EC = initializeSectionMapData())
126 return EC;
127 if (auto EC = initializeOldFpoRecords(Pdb))
128 return EC;
129 if (auto EC = initializeNewFpoRecords(Pdb))
130 return EC;
131
132 if (Reader.bytesRemaining() > 0)
133 return make_error<RawError>(raw_error_code::corrupt_file,
134 "Found unexpected bytes in DBI Stream.");
135
136 if (!ECSubstream.empty()) {
137 BinaryStreamReader ECReader(ECSubstream.StreamData);
138 if (auto EC = ECNames.reload(ECReader))
139 return EC;
140 }
141
142 return Error::success();
143}
144
146 uint32_t Value = Header->VersionHeader;
147 return static_cast<PdbRaw_DbiVer>(Value);
148}
149
150uint32_t DbiStream::getAge() const { return Header->Age; }
151
153 return Header->PublicSymbolStreamIndex;
154}
155
157 return Header->GlobalSymbolStreamIndex;
158}
159
160uint16_t DbiStream::getFlags() const { return Header->Flags; }
161
163 return (Header->Flags & DbiFlags::FlagIncrementalMask) != 0;
164}
165
167 return (Header->Flags & DbiFlags::FlagHasCTypesMask) != 0;
168}
169
171 return (Header->Flags & DbiFlags::FlagStrippedMask) != 0;
172}
173
175
177 return (Header->BuildNumber & DbiBuildNo::BuildMajorMask) >>
179}
180
182 return (Header->BuildNumber & DbiBuildNo::BuildMinorMask) >>
184}
185
187
189
191 return Header->SymRecordStreamIndex;
192}
193
195 uint16_t Machine = Header->MachineType;
196 return static_cast<PDB_Machine>(Machine);
197}
198
200 return SectionHeaders;
201}
202
203bool DbiStream::hasOldFpoRecords() const { return OldFpoStream != nullptr; }
204
206 return OldFpoRecords;
207}
208
209bool DbiStream::hasNewFpoRecords() const { return NewFpoStream != nullptr; }
210
212 return NewFpoRecords;
213}
214
215const DbiModuleList &DbiStream::modules() const { return Modules; }
216
218 return SectionMap;
219}
220
222 ISectionContribVisitor &Visitor) const {
223 if (!SectionContribs.empty()) {
224 assert(SectionContribVersion == DbiSecContribVer60);
225 for (auto &SC : SectionContribs)
226 Visitor.visit(SC);
227 } else if (!SectionContribs2.empty()) {
228 assert(SectionContribVersion == DbiSecContribV2);
229 for (auto &SC : SectionContribs2)
230 Visitor.visit(SC);
231 }
232}
233
235 return ECNames.getStringForID(NI);
236}
237
238Error DbiStream::initializeSectionContributionData() {
239 if (SecContrSubstream.empty())
240 return Error::success();
241
242 BinaryStreamReader SCReader(SecContrSubstream.StreamData);
243 if (auto EC = SCReader.readEnum(SectionContribVersion))
244 return EC;
245
246 if (SectionContribVersion == DbiSecContribVer60)
247 return loadSectionContribs<SectionContrib>(SectionContribs, SCReader);
248 if (SectionContribVersion == DbiSecContribV2)
249 return loadSectionContribs<SectionContrib2>(SectionContribs2, SCReader);
250
251 return make_error<RawError>(raw_error_code::feature_unsupported,
252 "Unsupported DBI Section Contribution version");
253}
254
255// Initializes this->SectionHeaders.
256Error DbiStream::initializeSectionHeadersData(PDBFile *Pdb) {
258 createIndexedStreamForHeaderType(Pdb, DbgHeaderType::SectionHdr);
259 if (auto EC = ExpectedStream.takeError())
260 return EC;
261
262 auto &SHS = *ExpectedStream;
263 if (!SHS)
264 return Error::success();
265
266 size_t StreamLen = SHS->getLength();
267 if (StreamLen % sizeof(object::coff_section))
268 return make_error<RawError>(raw_error_code::corrupt_file,
269 "Corrupted section header stream.");
270
271 size_t NumSections = StreamLen / sizeof(object::coff_section);
272 BinaryStreamReader Reader(*SHS);
273 if (auto EC = Reader.readArray(SectionHeaders, NumSections))
274 return make_error<RawError>(raw_error_code::corrupt_file,
275 "Could not read a bitmap.");
276
277 SectionHeaderStream = std::move(SHS);
278 return Error::success();
279}
280
281// Initializes this->Fpos.
282Error DbiStream::initializeOldFpoRecords(PDBFile *Pdb) {
284 createIndexedStreamForHeaderType(Pdb, DbgHeaderType::FPO);
285 if (auto EC = ExpectedStream.takeError())
286 return EC;
287
288 auto &FS = *ExpectedStream;
289 if (!FS)
290 return Error::success();
291
292 size_t StreamLen = FS->getLength();
293 if (StreamLen % sizeof(object::FpoData))
294 return make_error<RawError>(raw_error_code::corrupt_file,
295 "Corrupted Old FPO stream.");
296
297 size_t NumRecords = StreamLen / sizeof(object::FpoData);
298 BinaryStreamReader Reader(*FS);
299 if (auto EC = Reader.readArray(OldFpoRecords, NumRecords))
300 return make_error<RawError>(raw_error_code::corrupt_file,
301 "Corrupted Old FPO stream.");
302 OldFpoStream = std::move(FS);
303 return Error::success();
304}
305
306Error DbiStream::initializeNewFpoRecords(PDBFile *Pdb) {
308 createIndexedStreamForHeaderType(Pdb, DbgHeaderType::NewFPO);
309 if (auto EC = ExpectedStream.takeError())
310 return EC;
311
312 auto &FS = *ExpectedStream;
313 if (!FS)
314 return Error::success();
315
316 if (auto EC = NewFpoRecords.initialize(*FS))
317 return EC;
318
319 NewFpoStream = std::move(FS);
320 return Error::success();
321}
322
324DbiStream::createIndexedStreamForHeaderType(PDBFile *Pdb,
325 DbgHeaderType Type) const {
326 if (!Pdb)
327 return nullptr;
328
329 if (DbgStreams.empty())
330 return nullptr;
331
332 uint32_t StreamNum = getDebugStreamIndex(Type);
333
334 // This means there is no such stream.
335 if (StreamNum == kInvalidStreamIndex)
336 return nullptr;
337
338 return Pdb->safelyCreateIndexedStream(StreamNum);
339}
340
342 return SecContrSubstream;
343}
344
346 return SecMapSubstream;
347}
348
350 return ModiSubstream;
351}
352
354 return FileInfoSubstream;
355}
356
358 return TypeServerMapSubstream;
359}
360
362
363Error DbiStream::initializeSectionMapData() {
364 if (SecMapSubstream.empty())
365 return Error::success();
366
367 BinaryStreamReader SMReader(SecMapSubstream.StreamData);
368 const SecMapHeader *Header;
369 if (auto EC = SMReader.readObject(Header))
370 return EC;
371 if (auto EC = SMReader.readArray(SectionMap, Header->SecCount))
372 return EC;
373 return Error::success();
374}
375
377 uint16_t T = static_cast<uint16_t>(Type);
378 if (T >= DbgStreams.size())
379 return kInvalidStreamIndex;
380 return DbgStreams[T];
381}
Lightweight arrays that are backed by an arbitrary BinaryStream.
COFF::MachineTypes Machine
Definition: COFFYAML.cpp:371
static Error loadSectionContribs(FixedStreamArray< ContribType > &Output, BinaryStreamReader &Reader)
Definition: DbiStream.cpp:32
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Provides read only access to a subclass of BinaryStream.
Error readObject(const T *&Dest)
Get a pointer to an object of type T from the underlying stream, as if by memcpy, and store the resul...
Error readSubstream(BinarySubstreamRef &Ref, uint32_t Length)
Read Length bytes from the underlying stream into Ref.
uint64_t bytesRemaining() const
Error readArray(ArrayRef< T > &Array, uint32_t NumElements)
Get a reference to a NumElements element array of objects of type T from the underlying stream as if ...
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
Tagged union holding either a T or a Error.
Definition: Error.h:481
Error takeError()
Take ownership of the stored error.
Definition: Error.h:608
FixedStreamArray is similar to VarStreamArray, except with each record having a fixed-length.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
LLVM Value Representation.
Definition: Value.h:74
Error initialize(BinaryStreamRef ModInfo, BinaryStreamRef FileInfo)
Expected< StringRef > getECName(uint32_t NI) const
Definition: DbiStream.cpp:234
BinarySubstreamRef getSecMapSubstreamData() const
Definition: DbiStream.cpp:345
PDB_Machine getMachineType() const
Definition: DbiStream.cpp:194
BinarySubstreamRef getFileInfoSubstreamData() const
Definition: DbiStream.cpp:353
void visitSectionContributions(ISectionContribVisitor &Visitor) const
Definition: DbiStream.cpp:221
uint32_t getAge() const
Definition: DbiStream.cpp:150
bool isIncrementallyLinked() const
Definition: DbiStream.cpp:162
uint16_t getFlags() const
Definition: DbiStream.cpp:160
PdbRaw_DbiVer getDbiVersion() const
Definition: DbiStream.cpp:145
bool isStripped() const
Definition: DbiStream.cpp:170
bool hasNewFpoRecords() const
Definition: DbiStream.cpp:209
uint16_t getBuildMajorVersion() const
Definition: DbiStream.cpp:176
FixedStreamArray< object::coff_section > getSectionHeaders() const
Definition: DbiStream.cpp:199
uint16_t getGlobalSymbolStreamIndex() const
Definition: DbiStream.cpp:156
DbiStream(std::unique_ptr< BinaryStream > Stream)
Definition: DbiStream.cpp:45
Error reload(PDBFile *Pdb)
Definition: DbiStream.cpp:50
BinarySubstreamRef getTypeServerMapSubstreamData() const
Definition: DbiStream.cpp:357
BinarySubstreamRef getModiSubstreamData() const
Definition: DbiStream.cpp:349
const DbiModuleList & modules() const
Definition: DbiStream.cpp:215
uint16_t getBuildNumber() const
Definition: DbiStream.cpp:174
const codeview::DebugFrameDataSubsectionRef & getNewFpoRecords() const
Definition: DbiStream.cpp:211
uint16_t getBuildMinorVersion() const
Definition: DbiStream.cpp:181
uint32_t getDebugStreamIndex(DbgHeaderType Type) const
If the given stream type is present, returns its stream index.
Definition: DbiStream.cpp:376
FixedStreamArray< object::FpoData > getOldFpoRecords() const
Definition: DbiStream.cpp:205
uint32_t getPdbDllVersion() const
Definition: DbiStream.cpp:188
uint32_t getSymRecordStreamIndex() const
Definition: DbiStream.cpp:190
uint16_t getPublicSymbolStreamIndex() const
Definition: DbiStream.cpp:152
BinarySubstreamRef getECSubstreamData() const
Definition: DbiStream.cpp:361
bool hasCTypes() const
Definition: DbiStream.cpp:166
uint16_t getPdbDllRbld() const
Definition: DbiStream.cpp:186
FixedStreamArray< SecMapEntry > getSectionMap() const
Definition: DbiStream.cpp:217
BinarySubstreamRef getSectionContributionData() const
Definition: DbiStream.cpp:341
bool hasOldFpoRecords() const
Definition: DbiStream.cpp:203
virtual void visit(const SectionContrib &C)=0
Error reload(BinaryStreamReader &Reader)
Expected< StringRef > getStringForID(uint32_t ID) const
@ FS
Definition: X86.h:210
const uint16_t kInvalidStreamIndex
Definition: RawConstants.h:19
@ DbiSecContribVer60
Definition: RawConstants.h:68
@ DbiSecContribV2
Definition: RawConstants.h:69
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1856
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
BinaryStreamRef StreamData
static const uint16_t BuildMajorShift
Definition: RawTypes.h:113
static const uint16_t BuildMajorMask
Definition: RawTypes.h:112
static const uint16_t BuildMinorMask
uint16_t MinorVersion : 8; uint16_t MajorVersion : 7; uint16_t NewVersionFormat : 1;
Definition: RawTypes.h:109
static const uint16_t BuildMinorShift
Definition: RawTypes.h:110
static const uint16_t FlagIncrementalMask
uint16_t IncrementalLinking : 1; // True if linked incrementally uint16_t IsStripped : 1; // True if ...
Definition: RawTypes.h:100
static const uint16_t FlagHasCTypesMask
Definition: RawTypes.h:102
static const uint16_t FlagStrippedMask
Definition: RawTypes.h:101
The fixed size header that appears at the beginning of the DBI Stream.
Definition: RawTypes.h:119
support::ulittle16_t PdbDllRbld
rbld number of mspdbNNN.dll
Definition: RawTypes.h:142
support::ulittle16_t PublicSymbolStreamIndex
Public symbols stream #.
Definition: RawTypes.h:133
support::ulittle16_t MachineType
See PDB_MachineType enum.
Definition: RawTypes.h:172
support::little32_t TypeServerSize
Size of type server map.
Definition: RawTypes.h:157
support::little32_t FileInfoSize
Size of file info substream.
Definition: RawTypes.h:154
support::ulittle32_t VersionHeader
Definition: RawTypes.h:121
support::little32_t ModiSubstreamSize
Size of module info stream.
Definition: RawTypes.h:145
support::little32_t SectionMapSize
Size of sec. map substream.
Definition: RawTypes.h:151
support::ulittle16_t Flags
See DbiFlags enum.
Definition: RawTypes.h:169
support::ulittle32_t Age
How "old" is this DBI Stream. Should match the age of the PDB InfoStream.
Definition: RawTypes.h:124
support::little32_t ECSubstreamSize
Size of EC stream (what is EC?)
Definition: RawTypes.h:166
support::ulittle16_t BuildNumber
See DbiBuildNo structure.
Definition: RawTypes.h:130
support::ulittle16_t SymRecordStreamIndex
Symbol records stream #.
Definition: RawTypes.h:139
support::little32_t SecContrSubstreamSize
Size of sec. contrib stream.
Definition: RawTypes.h:148
support::little32_t VersionSignature
Definition: RawTypes.h:120
support::little32_t OptionalDbgHdrSize
Size of DbgHeader info.
Definition: RawTypes.h:163
support::ulittle16_t PdbDllVersion
version of mspdbNNN.dll
Definition: RawTypes.h:136
support::ulittle16_t GlobalSymbolStreamIndex
Global symbol stream #.
Definition: RawTypes.h:127