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
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"
23#include <algorithm>
24#include <cstddef>
25#include <cstdint>
26
27using namespace llvm;
28using namespace llvm::codeview;
29using namespace llvm::msf;
30using namespace llvm::pdb;
31using namespace llvm::support;
32
33template <typename ContribType>
34static 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");
40
41  uint32_t Count = Reader.bytesRemaining() / sizeof(ContribType);
42  if (auto EC = Reader.readArray(Output, Count))
43    return EC;
44  return Error::success();
45}
46
47DbiStream::DbiStream(std::unique_ptr<BinaryStream> Stream)
48    : Stream(std::move(Stream)), Header(nullptr) {}
49
50DbiStream::~DbiStream() = default;
51
52Error DbiStream::reload(PDBFile *Pdb) {
53  BinaryStreamReader Reader(*Stream);
54
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.");
61
62  if (Header->VersionSignature != -1)
63    return make_error<RawError>(raw_error_code::corrupt_file,
64                                "Invalid DBI version signature.");
65
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.");
72
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.");
80
81  // Only certain substreams are guaranteed to be aligned.  Validate
82  // them here.
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.");
99
100  if (auto EC = Reader.readSubstream(ModiSubstream, Header->ModiSubstreamSize))
101    return EC;
102
103  if (auto EC = Reader.readSubstream(SecContrSubstream,
104                                     Header->SecContrSubstreamSize))
105    return EC;
106  if (auto EC = Reader.readSubstream(SecMapSubstream, Header->SectionMapSize))
107    return EC;
108  if (auto EC = Reader.readSubstream(FileInfoSubstream, Header->FileInfoSize))
109    return EC;
110  if (auto EC =
111          Reader.readSubstream(TypeServerMapSubstream, Header->TypeServerSize))
112    return EC;
113  if (auto EC = Reader.readSubstream(ECSubstream, Header->ECSubstreamSize))
114    return EC;
115  if (auto EC = Reader.readArray(
116          DbgStreams, Header->OptionalDbgHdrSize / sizeof(ulittle16_t)))
117    return EC;
118
119  if (auto EC = Modules.initialize(ModiSubstream.StreamData,
120                                   FileInfoSubstream.StreamData))
121    return EC;
122
123  if (auto EC = initializeSectionContributionData())
124    return EC;
125  if (auto EC = initializeSectionHeadersData(Pdb))
126    return EC;
127  if (auto EC = initializeSectionMapData())
128    return EC;
129  if (auto EC = initializeOldFpoRecords(Pdb))
130    return EC;
131  if (auto EC = initializeNewFpoRecords(Pdb))
132     return EC;
133
134  if (Reader.bytesRemaining() > 0)
135    return make_error<RawError>(raw_error_code::corrupt_file,
136                                "Found unexpected bytes in DBI Stream.");
137
138  if (!ECSubstream.empty()) {
139    BinaryStreamReader ECReader(ECSubstream.StreamData);
140    if (auto EC = ECNames.reload(ECReader))
141      return EC;
142  }
143
144  return Error::success();
145}
146
147PdbRaw_DbiVer DbiStream::getDbiVersion() const {
148  uint32_t Value = Header->VersionHeader;
149  return static_cast<PdbRaw_DbiVer>(Value);
150}
151
152uint32_t DbiStream::getAge() const { return Header->Age; }
153
154uint16_t DbiStream::getPublicSymbolStreamIndex() const {
155  return Header->PublicSymbolStreamIndex;
156}
157
158uint16_t DbiStream::getGlobalSymbolStreamIndex() const {
159  return Header->GlobalSymbolStreamIndex;
160}
161
162uint16_t DbiStream::getFlags() const { return Header->Flags; }
163
164bool DbiStream::isIncrementallyLinked() const {
165  return (Header->Flags & DbiFlags::FlagIncrementalMask) != 0;
166}
167
168bool DbiStream::hasCTypes() const {
169  return (Header->Flags & DbiFlags::FlagHasCTypesMask) != 0;
170}
171
172bool DbiStream::isStripped() const {
173  return (Header->Flags & DbiFlags::FlagStrippedMask) != 0;
174}
175
176uint16_t DbiStream::getBuildNumber() const { return Header->BuildNumber; }
177
178uint16_t DbiStream::getBuildMajorVersion() const {
179  return (Header->BuildNumber & DbiBuildNo::BuildMajorMask) >>
180         DbiBuildNo::BuildMajorShift;
181}
182
183uint16_t DbiStream::getBuildMinorVersion() const {
184  return (Header->BuildNumber & DbiBuildNo::BuildMinorMask) >>
185         DbiBuildNo::BuildMinorShift;
186}
187
188uint16_t DbiStream::getPdbDllRbld() const { return Header->PdbDllRbld; }
189
190uint32_t DbiStream::getPdbDllVersion() const { return Header->PdbDllVersion; }
191
192uint32_t DbiStream::getSymRecordStreamIndex() const {
193  return Header->SymRecordStreamIndex;
194}
195
196PDB_Machine DbiStream::getMachineType() const {
197  uint16_t Machine = Header->MachineType;
198  return static_cast<PDB_Machine>(Machine);
199}
200
201FixedStreamArray<object::coff_section> DbiStream::getSectionHeaders() const {
202  return SectionHeaders;
203}
204
205bool DbiStream::hasOldFpoRecords() const { return OldFpoStream != nullptr; }
206
207FixedStreamArray<object::FpoData> DbiStream::getOldFpoRecords() const {
208  return OldFpoRecords;
209}
210
211bool DbiStream::hasNewFpoRecords() const { return NewFpoStream != nullptr; }
212
213const DebugFrameDataSubsectionRef &DbiStream::getNewFpoRecords() const {
214  return NewFpoRecords;
215}
216
217const DbiModuleList &DbiStream::modules() const { return Modules; }
218
219FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const {
220  return SectionMap;
221}
222
223void DbiStream::visitSectionContributions(
224    ISectionContribVisitor &Visitor) const {
225  if (!SectionContribs.empty()) {
226    assert(SectionContribVersion == DbiSecContribVer60);
227    for (auto &SC : SectionContribs)
228      Visitor.visit(SC);
229  } else if (!SectionContribs2.empty()) {
230    assert(SectionContribVersion == DbiSecContribV2);
231    for (auto &SC : SectionContribs2)
232      Visitor.visit(SC);
233  }
234}
235
236Expected<StringRef> DbiStream::getECName(uint32_t NI) const {
237  return ECNames.getStringForID(NI);
238}
239
240Error DbiStream::initializeSectionContributionData() {
241  if (SecContrSubstream.empty())
242    return Error::success();
243
244  BinaryStreamReader SCReader(SecContrSubstream.StreamData);
245  if (auto EC = SCReader.readEnum(SectionContribVersion))
246    return EC;
247
248  if (SectionContribVersion == DbiSecContribVer60)
249    return loadSectionContribs<SectionContrib>(SectionContribs, SCReader);
250  if (SectionContribVersion == DbiSecContribV2)
251    return loadSectionContribs<SectionContrib2>(SectionContribs2, SCReader);
252
253  return make_error<RawError>(raw_error_code::feature_unsupported,
254                              "Unsupported DBI Section Contribution version");
255}
256
257// Initializes this->SectionHeaders.
258Error DbiStream::initializeSectionHeadersData(PDBFile *Pdb) {
259  Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream =
260      createIndexedStreamForHeaderType(Pdb, DbgHeaderType::SectionHdr);
261  if (auto EC = ExpectedStream.takeError())
262    return EC;
263
264  auto &SHS = *ExpectedStream;
265  if (!SHS)
266    return Error::success();
267
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.");
272
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.");
278
279  SectionHeaderStream = std::move(SHS);
280  return Error::success();
281}
282
283// Initializes this->Fpos.
284Error DbiStream::initializeOldFpoRecords(PDBFile *Pdb) {
285  Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream =
286      createIndexedStreamForHeaderType(Pdb, DbgHeaderType::FPO);
287  if (auto EC = ExpectedStream.takeError())
288    return EC;
289
290  auto &FS = *ExpectedStream;
291  if (!FS)
292    return Error::success();
293
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.");
298
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();
306}
307
308Error DbiStream::initializeNewFpoRecords(PDBFile *Pdb) {
309  Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream =
310      createIndexedStreamForHeaderType(Pdb, DbgHeaderType::NewFPO);
311  if (auto EC = ExpectedStream.takeError())
312    return EC;
313
314  auto &FS = *ExpectedStream;
315  if (!FS)
316    return Error::success();
317
318  if (auto EC = NewFpoRecords.initialize(*FS))
319    return EC;
320
321  NewFpoStream = std::move(FS);
322  return Error::success();
323}
324
325Expected<std::unique_ptr<msf::MappedBlockStream>>
326DbiStream::createIndexedStreamForHeaderType(PDBFile *Pdb,
327                                            DbgHeaderType Type) const {
328  if (!Pdb)
329    return nullptr;
330
331  if (DbgStreams.empty())
332    return nullptr;
333
334  uint32_t StreamNum = getDebugStreamIndex(Type);
335
336  // This means there is no such stream.
337  if (StreamNum == kInvalidStreamIndex)
338    return nullptr;
339
340  return Pdb->safelyCreateIndexedStream(StreamNum);
341}
342
343BinarySubstreamRef DbiStream::getSectionContributionData() const {
344  return SecContrSubstream;
345}
346
347BinarySubstreamRef DbiStream::getSecMapSubstreamData() const {
348  return SecMapSubstream;
349}
350
351BinarySubstreamRef DbiStream::getModiSubstreamData() const {
352  return ModiSubstream;
353}
354
355BinarySubstreamRef DbiStream::getFileInfoSubstreamData() const {
356  return FileInfoSubstream;
357}
358
359BinarySubstreamRef DbiStream::getTypeServerMapSubstreamData() const {
360  return TypeServerMapSubstream;
361}
362
363BinarySubstreamRef DbiStream::getECSubstreamData() const { return ECSubstream; }
364
365Error DbiStream::initializeSectionMapData() {
366  if (SecMapSubstream.empty())
367    return Error::success();
368
369  BinaryStreamReader SMReader(SecMapSubstream.StreamData);
370  const SecMapHeader *Header;
371  if (auto EC = SMReader.readObject(Header))
372    return EC;
373  if (auto EC = SMReader.readArray(SectionMap, Header->SecCount))
374    return EC;
375  return Error::success();
376}
377
378uint32_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];
383}
384