1 //===- DbiStream.cpp - PDB Dbi Stream (Stream 3) Access -------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
10 #include "llvm/ADT/StringRef.h"
11 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
12 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
13 #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
14 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
15 #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
16 #include "llvm/DebugInfo/PDB/Native/RawError.h"
17 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
18 #include "llvm/DebugInfo/PDB/PDBTypes.h"
19 #include "llvm/Object/COFF.h"
20 #include "llvm/Support/BinaryStreamArray.h"
21 #include "llvm/Support/BinaryStreamReader.h"
22 #include "llvm/Support/Error.h"
28 using namespace llvm::codeview
;
29 using namespace llvm::msf
;
30 using namespace llvm::pdb
;
31 using namespace llvm::support
;
33 template <typename ContribType
>
34 static Error
loadSectionContribs(FixedStreamArray
<ContribType
> &Output
,
35 BinaryStreamReader
&Reader
) {
36 if (Reader
.bytesRemaining() % sizeof(ContribType
) != 0)
37 return make_error
<RawError
>(
38 raw_error_code::corrupt_file
,
39 "Invalid number of bytes of section contributions");
41 uint32_t Count
= Reader
.bytesRemaining() / sizeof(ContribType
);
42 if (auto EC
= Reader
.readArray(Output
, Count
))
44 return Error::success();
47 DbiStream::DbiStream(std::unique_ptr
<BinaryStream
> Stream
)
48 : Stream(std::move(Stream
)), Header(nullptr) {}
50 DbiStream::~DbiStream() = default;
52 Error
DbiStream::reload(PDBFile
*Pdb
) {
53 BinaryStreamReader
Reader(*Stream
);
55 if (Stream
->getLength() < sizeof(DbiStreamHeader
))
56 return make_error
<RawError
>(raw_error_code::corrupt_file
,
57 "DBI Stream does not contain a header.");
58 if (auto EC
= Reader
.readObject(Header
))
59 return make_error
<RawError
>(raw_error_code::corrupt_file
,
60 "DBI Stream does not contain a header.");
62 if (Header
->VersionSignature
!= -1)
63 return make_error
<RawError
>(raw_error_code::corrupt_file
,
64 "Invalid DBI version signature.");
66 // Require at least version 7, which should be present in all PDBs
67 // produced in the last decade and allows us to avoid having to
68 // special case all kinds of complicated arcane formats.
69 if (Header
->VersionHeader
< PdbDbiV70
)
70 return make_error
<RawError
>(raw_error_code::feature_unsupported
,
71 "Unsupported DBI version.");
73 if (Stream
->getLength() !=
74 sizeof(DbiStreamHeader
) + Header
->ModiSubstreamSize
+
75 Header
->SecContrSubstreamSize
+ Header
->SectionMapSize
+
76 Header
->FileInfoSize
+ Header
->TypeServerSize
+
77 Header
->OptionalDbgHdrSize
+ Header
->ECSubstreamSize
)
78 return make_error
<RawError
>(raw_error_code::corrupt_file
,
79 "DBI Length does not equal sum of substreams.");
81 // Only certain substreams are guaranteed to be aligned. Validate
83 if (Header
->ModiSubstreamSize
% sizeof(uint32_t) != 0)
84 return make_error
<RawError
>(raw_error_code::corrupt_file
,
85 "DBI MODI substream not aligned.");
86 if (Header
->SecContrSubstreamSize
% sizeof(uint32_t) != 0)
87 return make_error
<RawError
>(
88 raw_error_code::corrupt_file
,
89 "DBI section contribution substream not aligned.");
90 if (Header
->SectionMapSize
% sizeof(uint32_t) != 0)
91 return make_error
<RawError
>(raw_error_code::corrupt_file
,
92 "DBI section map substream not aligned.");
93 if (Header
->FileInfoSize
% sizeof(uint32_t) != 0)
94 return make_error
<RawError
>(raw_error_code::corrupt_file
,
95 "DBI file info substream not aligned.");
96 if (Header
->TypeServerSize
% sizeof(uint32_t) != 0)
97 return make_error
<RawError
>(raw_error_code::corrupt_file
,
98 "DBI type server substream not aligned.");
100 if (auto EC
= Reader
.readSubstream(ModiSubstream
, Header
->ModiSubstreamSize
))
103 if (auto EC
= Reader
.readSubstream(SecContrSubstream
,
104 Header
->SecContrSubstreamSize
))
106 if (auto EC
= Reader
.readSubstream(SecMapSubstream
, Header
->SectionMapSize
))
108 if (auto EC
= Reader
.readSubstream(FileInfoSubstream
, Header
->FileInfoSize
))
111 Reader
.readSubstream(TypeServerMapSubstream
, Header
->TypeServerSize
))
113 if (auto EC
= Reader
.readSubstream(ECSubstream
, Header
->ECSubstreamSize
))
115 if (auto EC
= Reader
.readArray(
116 DbgStreams
, Header
->OptionalDbgHdrSize
/ sizeof(ulittle16_t
)))
119 if (auto EC
= Modules
.initialize(ModiSubstream
.StreamData
,
120 FileInfoSubstream
.StreamData
))
123 if (auto EC
= initializeSectionContributionData())
125 if (auto EC
= initializeSectionHeadersData(Pdb
))
127 if (auto EC
= initializeSectionMapData())
129 if (auto EC
= initializeOldFpoRecords(Pdb
))
131 if (auto EC
= initializeNewFpoRecords(Pdb
))
134 if (Reader
.bytesRemaining() > 0)
135 return make_error
<RawError
>(raw_error_code::corrupt_file
,
136 "Found unexpected bytes in DBI Stream.");
138 if (!ECSubstream
.empty()) {
139 BinaryStreamReader
ECReader(ECSubstream
.StreamData
);
140 if (auto EC
= ECNames
.reload(ECReader
))
144 return Error::success();
147 PdbRaw_DbiVer
DbiStream::getDbiVersion() const {
148 uint32_t Value
= Header
->VersionHeader
;
149 return static_cast<PdbRaw_DbiVer
>(Value
);
152 uint32_t DbiStream::getAge() const { return Header
->Age
; }
154 uint16_t DbiStream::getPublicSymbolStreamIndex() const {
155 return Header
->PublicSymbolStreamIndex
;
158 uint16_t DbiStream::getGlobalSymbolStreamIndex() const {
159 return Header
->GlobalSymbolStreamIndex
;
162 uint16_t DbiStream::getFlags() const { return Header
->Flags
; }
164 bool DbiStream::isIncrementallyLinked() const {
165 return (Header
->Flags
& DbiFlags::FlagIncrementalMask
) != 0;
168 bool DbiStream::hasCTypes() const {
169 return (Header
->Flags
& DbiFlags::FlagHasCTypesMask
) != 0;
172 bool DbiStream::isStripped() const {
173 return (Header
->Flags
& DbiFlags::FlagStrippedMask
) != 0;
176 uint16_t DbiStream::getBuildNumber() const { return Header
->BuildNumber
; }
178 uint16_t DbiStream::getBuildMajorVersion() const {
179 return (Header
->BuildNumber
& DbiBuildNo::BuildMajorMask
) >>
180 DbiBuildNo::BuildMajorShift
;
183 uint16_t DbiStream::getBuildMinorVersion() const {
184 return (Header
->BuildNumber
& DbiBuildNo::BuildMinorMask
) >>
185 DbiBuildNo::BuildMinorShift
;
188 uint16_t DbiStream::getPdbDllRbld() const { return Header
->PdbDllRbld
; }
190 uint32_t DbiStream::getPdbDllVersion() const { return Header
->PdbDllVersion
; }
192 uint32_t DbiStream::getSymRecordStreamIndex() const {
193 return Header
->SymRecordStreamIndex
;
196 PDB_Machine
DbiStream::getMachineType() const {
197 uint16_t Machine
= Header
->MachineType
;
198 return static_cast<PDB_Machine
>(Machine
);
201 FixedStreamArray
<object::coff_section
> DbiStream::getSectionHeaders() const {
202 return SectionHeaders
;
205 bool DbiStream::hasOldFpoRecords() const { return OldFpoStream
!= nullptr; }
207 FixedStreamArray
<object::FpoData
> DbiStream::getOldFpoRecords() const {
208 return OldFpoRecords
;
211 bool DbiStream::hasNewFpoRecords() const { return NewFpoStream
!= nullptr; }
213 const DebugFrameDataSubsectionRef
&DbiStream::getNewFpoRecords() const {
214 return NewFpoRecords
;
217 const DbiModuleList
&DbiStream::modules() const { return Modules
; }
219 FixedStreamArray
<SecMapEntry
> DbiStream::getSectionMap() const {
223 void DbiStream::visitSectionContributions(
224 ISectionContribVisitor
&Visitor
) const {
225 if (!SectionContribs
.empty()) {
226 assert(SectionContribVersion
== DbiSecContribVer60
);
227 for (auto &SC
: SectionContribs
)
229 } else if (!SectionContribs2
.empty()) {
230 assert(SectionContribVersion
== DbiSecContribV2
);
231 for (auto &SC
: SectionContribs2
)
236 Expected
<StringRef
> DbiStream::getECName(uint32_t NI
) const {
237 return ECNames
.getStringForID(NI
);
240 Error
DbiStream::initializeSectionContributionData() {
241 if (SecContrSubstream
.empty())
242 return Error::success();
244 BinaryStreamReader
SCReader(SecContrSubstream
.StreamData
);
245 if (auto EC
= SCReader
.readEnum(SectionContribVersion
))
248 if (SectionContribVersion
== DbiSecContribVer60
)
249 return loadSectionContribs
<SectionContrib
>(SectionContribs
, SCReader
);
250 if (SectionContribVersion
== DbiSecContribV2
)
251 return loadSectionContribs
<SectionContrib2
>(SectionContribs2
, SCReader
);
253 return make_error
<RawError
>(raw_error_code::feature_unsupported
,
254 "Unsupported DBI Section Contribution version");
257 // Initializes this->SectionHeaders.
258 Error
DbiStream::initializeSectionHeadersData(PDBFile
*Pdb
) {
259 Expected
<std::unique_ptr
<msf::MappedBlockStream
>> ExpectedStream
=
260 createIndexedStreamForHeaderType(Pdb
, DbgHeaderType::SectionHdr
);
261 if (auto EC
= ExpectedStream
.takeError())
264 auto &SHS
= *ExpectedStream
;
266 return Error::success();
268 size_t StreamLen
= SHS
->getLength();
269 if (StreamLen
% sizeof(object::coff_section
))
270 return make_error
<RawError
>(raw_error_code::corrupt_file
,
271 "Corrupted section header stream.");
273 size_t NumSections
= StreamLen
/ sizeof(object::coff_section
);
274 BinaryStreamReader
Reader(*SHS
);
275 if (auto EC
= Reader
.readArray(SectionHeaders
, NumSections
))
276 return make_error
<RawError
>(raw_error_code::corrupt_file
,
277 "Could not read a bitmap.");
279 SectionHeaderStream
= std::move(SHS
);
280 return Error::success();
283 // Initializes this->Fpos.
284 Error
DbiStream::initializeOldFpoRecords(PDBFile
*Pdb
) {
285 Expected
<std::unique_ptr
<msf::MappedBlockStream
>> ExpectedStream
=
286 createIndexedStreamForHeaderType(Pdb
, DbgHeaderType::FPO
);
287 if (auto EC
= ExpectedStream
.takeError())
290 auto &FS
= *ExpectedStream
;
292 return Error::success();
294 size_t StreamLen
= FS
->getLength();
295 if (StreamLen
% sizeof(object::FpoData
))
296 return make_error
<RawError
>(raw_error_code::corrupt_file
,
297 "Corrupted Old FPO stream.");
299 size_t NumRecords
= StreamLen
/ sizeof(object::FpoData
);
300 BinaryStreamReader
Reader(*FS
);
301 if (auto EC
= Reader
.readArray(OldFpoRecords
, NumRecords
))
302 return make_error
<RawError
>(raw_error_code::corrupt_file
,
303 "Corrupted Old FPO stream.");
304 OldFpoStream
= std::move(FS
);
305 return Error::success();
308 Error
DbiStream::initializeNewFpoRecords(PDBFile
*Pdb
) {
309 Expected
<std::unique_ptr
<msf::MappedBlockStream
>> ExpectedStream
=
310 createIndexedStreamForHeaderType(Pdb
, DbgHeaderType::NewFPO
);
311 if (auto EC
= ExpectedStream
.takeError())
314 auto &FS
= *ExpectedStream
;
316 return Error::success();
318 if (auto EC
= NewFpoRecords
.initialize(*FS
))
321 NewFpoStream
= std::move(FS
);
322 return Error::success();
325 Expected
<std::unique_ptr
<msf::MappedBlockStream
>>
326 DbiStream::createIndexedStreamForHeaderType(PDBFile
*Pdb
,
327 DbgHeaderType Type
) const {
331 if (DbgStreams
.empty())
334 uint32_t StreamNum
= getDebugStreamIndex(Type
);
336 // This means there is no such stream.
337 if (StreamNum
== kInvalidStreamIndex
)
340 return Pdb
->safelyCreateIndexedStream(StreamNum
);
343 BinarySubstreamRef
DbiStream::getSectionContributionData() const {
344 return SecContrSubstream
;
347 BinarySubstreamRef
DbiStream::getSecMapSubstreamData() const {
348 return SecMapSubstream
;
351 BinarySubstreamRef
DbiStream::getModiSubstreamData() const {
352 return ModiSubstream
;
355 BinarySubstreamRef
DbiStream::getFileInfoSubstreamData() const {
356 return FileInfoSubstream
;
359 BinarySubstreamRef
DbiStream::getTypeServerMapSubstreamData() const {
360 return TypeServerMapSubstream
;
363 BinarySubstreamRef
DbiStream::getECSubstreamData() const { return ECSubstream
; }
365 Error
DbiStream::initializeSectionMapData() {
366 if (SecMapSubstream
.empty())
367 return Error::success();
369 BinaryStreamReader
SMReader(SecMapSubstream
.StreamData
);
370 const SecMapHeader
*Header
;
371 if (auto EC
= SMReader
.readObject(Header
))
373 if (auto EC
= SMReader
.readArray(SectionMap
, Header
->SecCount
))
375 return Error::success();
378 uint32_t DbiStream::getDebugStreamIndex(DbgHeaderType Type
) const {
379 uint16_t T
= static_cast<uint16_t>(Type
);
380 if (T
>= DbgStreams
.size())
381 return kInvalidStreamIndex
;
382 return DbgStreams
[T
];