1 //===- DbiStream.cpp - PDB Dbi Stream (Stream 3) Access -------------------===//
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 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
13 #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
14 #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
15 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
16 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
17 #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
18 #include "llvm/DebugInfo/PDB/Native/RawError.h"
19 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
20 #include "llvm/DebugInfo/PDB/PDBTypes.h"
21 #include "llvm/Object/COFF.h"
22 #include "llvm/Support/BinaryStreamArray.h"
23 #include "llvm/Support/BinaryStreamReader.h"
24 #include "llvm/Support/Error.h"
25 #include <algorithm>
26 #include <cstddef>
27 #include <cstdint>
28 
29 using namespace llvm;
30 using namespace llvm::codeview;
31 using namespace llvm::msf;
32 using namespace llvm::pdb;
33 using namespace llvm::support;
34 
35 template <typename ContribType>
36 static Error loadSectionContribs(FixedStreamArray<ContribType> &Output,
37                                  BinaryStreamReader &Reader) {
38   if (Reader.bytesRemaining() % sizeof(ContribType) != 0)
39     return make_error<RawError>(
40         raw_error_code::corrupt_file,
41         "Invalid number of bytes of section contributions");
42 
43   uint32_t Count = Reader.bytesRemaining() / sizeof(ContribType);
44   if (auto EC = Reader.readArray(Output, Count))
45     return EC;
46   return Error::success();
47 }
48 
49 DbiStream::DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream)
50     : Pdb(File), Stream(std::move(Stream)), Header(nullptr) {}
51 
52 DbiStream::~DbiStream() = default;
53 
54 Error DbiStream::reload() {
55   BinaryStreamReader Reader(*Stream);
56 
57   if (Stream->getLength() < sizeof(DbiStreamHeader))
58     return make_error<RawError>(raw_error_code::corrupt_file,
59                                 "DBI Stream does not contain a header.");
60   if (auto EC = Reader.readObject(Header))
61     return make_error<RawError>(raw_error_code::corrupt_file,
62                                 "DBI Stream does not contain a header.");
63 
64   if (Header->VersionSignature != -1)
65     return make_error<RawError>(raw_error_code::corrupt_file,
66                                 "Invalid DBI version signature.");
67 
68   // Require at least version 7, which should be present in all PDBs
69   // produced in the last decade and allows us to avoid having to
70   // special case all kinds of complicated arcane formats.
71   if (Header->VersionHeader < PdbDbiV70)
72     return make_error<RawError>(raw_error_code::feature_unsupported,
73                                 "Unsupported DBI version.");
74 
75   auto IS = Pdb.getPDBInfoStream();
76   if (!IS)
77     return IS.takeError();
78 
79   if (Header->Age != IS->getAge())
80     return make_error<RawError>(raw_error_code::corrupt_file,
81                                 "DBI Age does not match PDB Age.");
82 
83   if (Stream->getLength() !=
84       sizeof(DbiStreamHeader) + Header->ModiSubstreamSize +
85           Header->SecContrSubstreamSize + Header->SectionMapSize +
86           Header->FileInfoSize + Header->TypeServerSize +
87           Header->OptionalDbgHdrSize + Header->ECSubstreamSize)
88     return make_error<RawError>(raw_error_code::corrupt_file,
89                                 "DBI Length does not equal sum of substreams.");
90 
91   // Only certain substreams are guaranteed to be aligned.  Validate
92   // them here.
93   if (Header->ModiSubstreamSize % sizeof(uint32_t) != 0)
94     return make_error<RawError>(raw_error_code::corrupt_file,
95                                 "DBI MODI substream not aligned.");
96   if (Header->SecContrSubstreamSize % sizeof(uint32_t) != 0)
97     return make_error<RawError>(
98         raw_error_code::corrupt_file,
99         "DBI section contribution substream not aligned.");
100   if (Header->SectionMapSize % sizeof(uint32_t) != 0)
101     return make_error<RawError>(raw_error_code::corrupt_file,
102                                 "DBI section map substream not aligned.");
103   if (Header->FileInfoSize % sizeof(uint32_t) != 0)
104     return make_error<RawError>(raw_error_code::corrupt_file,
105                                 "DBI file info substream not aligned.");
106   if (Header->TypeServerSize % sizeof(uint32_t) != 0)
107     return make_error<RawError>(raw_error_code::corrupt_file,
108                                 "DBI type server substream not aligned.");
109 
110   BinaryStreamRef ModInfoSubstream;
111   BinaryStreamRef FileInfoSubstream;
112   if (auto EC =
113           Reader.readStreamRef(ModInfoSubstream, Header->ModiSubstreamSize))
114     return EC;
115 
116   if (auto EC = Reader.readStreamRef(SecContrSubstream,
117                                      Header->SecContrSubstreamSize))
118     return EC;
119   if (auto EC = Reader.readStreamRef(SecMapSubstream, Header->SectionMapSize))
120     return EC;
121   if (auto EC = Reader.readStreamRef(FileInfoSubstream, Header->FileInfoSize))
122     return EC;
123   if (auto EC =
124           Reader.readStreamRef(TypeServerMapSubstream, Header->TypeServerSize))
125     return EC;
126   if (auto EC = Reader.readStreamRef(ECSubstream, Header->ECSubstreamSize))
127     return EC;
128   if (auto EC = Reader.readArray(
129           DbgStreams, Header->OptionalDbgHdrSize / sizeof(ulittle16_t)))
130     return EC;
131 
132   if (auto EC = Modules.initialize(ModInfoSubstream, FileInfoSubstream))
133     return EC;
134 
135   if (auto EC = initializeSectionContributionData())
136     return EC;
137   if (auto EC = initializeSectionHeadersData())
138     return EC;
139   if (auto EC = initializeSectionMapData())
140     return EC;
141   if (auto EC = initializeFpoRecords())
142     return EC;
143 
144   if (Reader.bytesRemaining() > 0)
145     return make_error<RawError>(raw_error_code::corrupt_file,
146                                 "Found unexpected bytes in DBI Stream.");
147 
148   if (ECSubstream.getLength() > 0) {
149     BinaryStreamReader ECReader(ECSubstream);
150     if (auto EC = ECNames.reload(ECReader))
151       return EC;
152   }
153 
154   return Error::success();
155 }
156 
157 PdbRaw_DbiVer DbiStream::getDbiVersion() const {
158   uint32_t Value = Header->VersionHeader;
159   return static_cast<PdbRaw_DbiVer>(Value);
160 }
161 
162 uint32_t DbiStream::getAge() const { return Header->Age; }
163 
164 uint16_t DbiStream::getPublicSymbolStreamIndex() const {
165   return Header->PublicSymbolStreamIndex;
166 }
167 
168 uint16_t DbiStream::getGlobalSymbolStreamIndex() const {
169   return Header->GlobalSymbolStreamIndex;
170 }
171 
172 uint16_t DbiStream::getFlags() const { return Header->Flags; }
173 
174 bool DbiStream::isIncrementallyLinked() const {
175   return (Header->Flags & DbiFlags::FlagIncrementalMask) != 0;
176 }
177 
178 bool DbiStream::hasCTypes() const {
179   return (Header->Flags & DbiFlags::FlagHasCTypesMask) != 0;
180 }
181 
182 bool DbiStream::isStripped() const {
183   return (Header->Flags & DbiFlags::FlagStrippedMask) != 0;
184 }
185 
186 uint16_t DbiStream::getBuildNumber() const { return Header->BuildNumber; }
187 
188 uint16_t DbiStream::getBuildMajorVersion() const {
189   return (Header->BuildNumber & DbiBuildNo::BuildMajorMask) >>
190          DbiBuildNo::BuildMajorShift;
191 }
192 
193 uint16_t DbiStream::getBuildMinorVersion() const {
194   return (Header->BuildNumber & DbiBuildNo::BuildMinorMask) >>
195          DbiBuildNo::BuildMinorShift;
196 }
197 
198 uint16_t DbiStream::getPdbDllRbld() const { return Header->PdbDllRbld; }
199 
200 uint32_t DbiStream::getPdbDllVersion() const { return Header->PdbDllVersion; }
201 
202 uint32_t DbiStream::getSymRecordStreamIndex() const {
203   return Header->SymRecordStreamIndex;
204 }
205 
206 PDB_Machine DbiStream::getMachineType() const {
207   uint16_t Machine = Header->MachineType;
208   return static_cast<PDB_Machine>(Machine);
209 }
210 
211 FixedStreamArray<object::coff_section> DbiStream::getSectionHeaders() {
212   return SectionHeaders;
213 }
214 
215 FixedStreamArray<object::FpoData> DbiStream::getFpoRecords() {
216   return FpoRecords;
217 }
218 
219 const DbiModuleList &DbiStream::modules() const { return Modules; }
220 
221 FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const {
222   return SectionMap;
223 }
224 
225 void DbiStream::visitSectionContributions(
226     ISectionContribVisitor &Visitor) const {
227   if (SectionContribVersion == DbiSecContribVer60) {
228     for (auto &SC : SectionContribs)
229       Visitor.visit(SC);
230   } else if (SectionContribVersion == DbiSecContribV2) {
231     for (auto &SC : SectionContribs2)
232       Visitor.visit(SC);
233   }
234 }
235 
236 Error DbiStream::initializeSectionContributionData() {
237   if (SecContrSubstream.getLength() == 0)
238     return Error::success();
239 
240   BinaryStreamReader SCReader(SecContrSubstream);
241   if (auto EC = SCReader.readEnum(SectionContribVersion))
242     return EC;
243 
244   if (SectionContribVersion == DbiSecContribVer60)
245     return loadSectionContribs<SectionContrib>(SectionContribs, SCReader);
246   if (SectionContribVersion == DbiSecContribV2)
247     return loadSectionContribs<SectionContrib2>(SectionContribs2, SCReader);
248 
249   return make_error<RawError>(raw_error_code::feature_unsupported,
250                               "Unsupported DBI Section Contribution version");
251 }
252 
253 // Initializes this->SectionHeaders.
254 Error DbiStream::initializeSectionHeadersData() {
255   if (DbgStreams.size() == 0)
256     return Error::success();
257 
258   uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::SectionHdr);
259   if (StreamNum >= Pdb.getNumStreams())
260     return make_error<RawError>(raw_error_code::no_stream);
261 
262   auto SHS = MappedBlockStream::createIndexedStream(
263       Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum);
264 
265   size_t StreamLen = SHS->getLength();
266   if (StreamLen % sizeof(object::coff_section))
267     return make_error<RawError>(raw_error_code::corrupt_file,
268                                 "Corrupted section header stream.");
269 
270   size_t NumSections = StreamLen / sizeof(object::coff_section);
271   BinaryStreamReader Reader(*SHS);
272   if (auto EC = Reader.readArray(SectionHeaders, NumSections))
273     return make_error<RawError>(raw_error_code::corrupt_file,
274                                 "Could not read a bitmap.");
275 
276   SectionHeaderStream = std::move(SHS);
277   return Error::success();
278 }
279 
280 // Initializes this->Fpos.
281 Error DbiStream::initializeFpoRecords() {
282   if (DbgStreams.size() == 0)
283     return Error::success();
284 
285   uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::NewFPO);
286 
287   // This means there is no FPO data.
288   if (StreamNum == kInvalidStreamIndex)
289     return Error::success();
290 
291   if (StreamNum >= Pdb.getNumStreams())
292     return make_error<RawError>(raw_error_code::no_stream);
293 
294   auto FS = MappedBlockStream::createIndexedStream(
295       Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum);
296 
297   size_t StreamLen = FS->getLength();
298   if (StreamLen % sizeof(object::FpoData))
299     return make_error<RawError>(raw_error_code::corrupt_file,
300                                 "Corrupted New FPO stream.");
301 
302   size_t NumRecords = StreamLen / sizeof(object::FpoData);
303   BinaryStreamReader Reader(*FS);
304   if (auto EC = Reader.readArray(FpoRecords, NumRecords))
305     return make_error<RawError>(raw_error_code::corrupt_file,
306                                 "Corrupted New FPO stream.");
307   FpoStream = std::move(FS);
308   return Error::success();
309 }
310 
311 Error DbiStream::initializeSectionMapData() {
312   if (SecMapSubstream.getLength() == 0)
313     return Error::success();
314 
315   BinaryStreamReader SMReader(SecMapSubstream);
316   const SecMapHeader *Header;
317   if (auto EC = SMReader.readObject(Header))
318     return EC;
319   if (auto EC = SMReader.readArray(SectionMap, Header->SecCount))
320     return EC;
321   return Error::success();
322 }
323 
324 uint32_t DbiStream::getDebugStreamIndex(DbgHeaderType Type) const {
325   uint16_t T = static_cast<uint16_t>(Type);
326   if (T >= DbgStreams.size())
327     return kInvalidStreamIndex;
328   return DbgStreams[T];
329 }
330