Line data Source code
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/ADT/StringRef.h"
11 : #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
12 : #include "llvm/DebugInfo/MSF/StreamArray.h"
13 : #include "llvm/DebugInfo/MSF/StreamReader.h"
14 : #include "llvm/DebugInfo/PDB/PDBTypes.h"
15 : #include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
16 : #include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h"
17 : #include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
18 : #include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
19 : #include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
20 : #include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
21 : #include "llvm/DebugInfo/PDB/Raw/RawError.h"
22 : #include "llvm/DebugInfo/PDB/Raw/RawTypes.h"
23 : #include "llvm/Object/COFF.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 9 : static Error loadSectionContribs(FixedStreamArray<ContribType> &Output,
37 : StreamReader &Reader) {
38 9 : if (Reader.bytesRemaining() % sizeof(ContribType) != 0)
39 : return make_error<RawError>(
40 : raw_error_code::corrupt_file,
41 0 : "Invalid number of bytes of section contributions");
42 :
43 9 : uint32_t Count = Reader.bytesRemaining() / sizeof(ContribType);
44 27 : if (auto EC = Reader.readArray(Output, Count))
45 0 : return EC;
46 27 : return Error::success();
47 : }
48 :
49 10 : DbiStream::DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream)
50 190 : : Pdb(File), Stream(std::move(Stream)), Header(nullptr) {
51 10 : }
52 :
53 : DbiStream::~DbiStream() = default;
54 :
55 10 : Error DbiStream::reload() {
56 30 : StreamReader Reader(*Stream);
57 :
58 20 : if (Stream->getLength() < sizeof(DbiStreamHeader))
59 : return make_error<RawError>(raw_error_code::corrupt_file,
60 0 : "DBI Stream does not contain a header.");
61 30 : if (auto EC = Reader.readObject(Header))
62 : return make_error<RawError>(raw_error_code::corrupt_file,
63 0 : "DBI Stream does not contain a header.");
64 :
65 20 : if (Header->VersionSignature != -1)
66 : return make_error<RawError>(raw_error_code::corrupt_file,
67 0 : "Invalid DBI version signature.");
68 :
69 : // Require at least version 7, which should be present in all PDBs
70 : // produced in the last decade and allows us to avoid having to
71 : // special case all kinds of complicated arcane formats.
72 20 : if (Header->VersionHeader < PdbDbiV70)
73 : return make_error<RawError>(raw_error_code::feature_unsupported,
74 0 : "Unsupported DBI version.");
75 :
76 10 : auto IS = Pdb.getPDBInfoStream();
77 10 : if (!IS)
78 0 : return IS.takeError();
79 :
80 30 : if (Header->Age != IS->getAge())
81 : return make_error<RawError>(raw_error_code::corrupt_file,
82 0 : "DBI Age does not match PDB Age.");
83 :
84 30 : if (Stream->getLength() !=
85 30 : sizeof(DbiStreamHeader) + Header->ModiSubstreamSize +
86 50 : Header->SecContrSubstreamSize + Header->SectionMapSize +
87 50 : Header->FileInfoSize + Header->TypeServerSize +
88 40 : Header->OptionalDbgHdrSize + Header->ECSubstreamSize)
89 : return make_error<RawError>(raw_error_code::corrupt_file,
90 0 : "DBI Length does not equal sum of substreams.");
91 :
92 : // Only certain substreams are guaranteed to be aligned. Validate
93 : // them here.
94 20 : if (Header->ModiSubstreamSize % sizeof(uint32_t) != 0)
95 : return make_error<RawError>(raw_error_code::corrupt_file,
96 0 : "DBI MODI substream not aligned.");
97 20 : if (Header->SecContrSubstreamSize % sizeof(uint32_t) != 0)
98 : return make_error<RawError>(
99 : raw_error_code::corrupt_file,
100 0 : "DBI section contribution substream not aligned.");
101 20 : if (Header->SectionMapSize % sizeof(uint32_t) != 0)
102 : return make_error<RawError>(raw_error_code::corrupt_file,
103 0 : "DBI section map substream not aligned.");
104 20 : if (Header->FileInfoSize % sizeof(uint32_t) != 0)
105 : return make_error<RawError>(raw_error_code::corrupt_file,
106 0 : "DBI file info substream not aligned.");
107 20 : if (Header->TypeServerSize % sizeof(uint32_t) != 0)
108 : return make_error<RawError>(raw_error_code::corrupt_file,
109 0 : "DBI type server substream not aligned.");
110 :
111 10 : if (auto EC =
112 30 : Reader.readStreamRef(ModInfoSubstream, Header->ModiSubstreamSize))
113 0 : return EC;
114 30 : if (auto EC = initializeModInfoArray())
115 0 : return EC;
116 :
117 10 : if (auto EC = Reader.readStreamRef(SecContrSubstream,
118 30 : Header->SecContrSubstreamSize))
119 0 : return EC;
120 40 : if (auto EC = Reader.readStreamRef(SecMapSubstream, Header->SectionMapSize))
121 0 : return EC;
122 40 : if (auto EC = Reader.readStreamRef(FileInfoSubstream, Header->FileInfoSize))
123 0 : return EC;
124 10 : if (auto EC =
125 30 : Reader.readStreamRef(TypeServerMapSubstream, Header->TypeServerSize))
126 0 : return EC;
127 40 : if (auto EC = Reader.readStreamRef(ECSubstream, Header->ECSubstreamSize))
128 0 : return EC;
129 30 : if (auto EC = Reader.readArray(DbgStreams, Header->OptionalDbgHdrSize /
130 40 : sizeof(ulittle16_t)))
131 0 : return EC;
132 :
133 30 : if (auto EC = initializeSectionContributionData())
134 0 : return EC;
135 30 : if (auto EC = initializeSectionHeadersData())
136 0 : return EC;
137 30 : if (auto EC = initializeSectionMapData())
138 0 : return EC;
139 30 : if (auto EC = initializeFileInfo())
140 0 : return EC;
141 30 : if (auto EC = initializeFpoRecords())
142 0 : return EC;
143 :
144 10 : if (Reader.bytesRemaining() > 0)
145 : return make_error<RawError>(raw_error_code::corrupt_file,
146 0 : "Found unexpected bytes in DBI Stream.");
147 :
148 10 : if (ECSubstream.getLength() > 0) {
149 8 : StreamReader ECReader(ECSubstream);
150 24 : if (auto EC = ECNames.load(ECReader))
151 0 : return EC;
152 : }
153 :
154 30 : return Error::success();
155 : }
156 :
157 8 : PdbRaw_DbiVer DbiStream::getDbiVersion() const {
158 16 : uint32_t Value = Header->VersionHeader;
159 8 : return static_cast<PdbRaw_DbiVer>(Value);
160 : }
161 :
162 16 : uint32_t DbiStream::getAge() const { return Header->Age; }
163 :
164 55 : uint16_t DbiStream::getPublicSymbolStreamIndex() const {
165 110 : return Header->PublicSymbolStreamIndex;
166 : }
167 :
168 59 : uint16_t DbiStream::getGlobalSymbolStreamIndex() const {
169 118 : return Header->GlobalSymbolStreamIndex;
170 : }
171 :
172 6 : uint16_t DbiStream::getFlags() const { return Header->Flags; }
173 :
174 5 : bool DbiStream::isIncrementallyLinked() const {
175 10 : return (Header->Flags & DbiFlags::FlagIncrementalMask) != 0;
176 : }
177 :
178 5 : bool DbiStream::hasCTypes() const {
179 10 : return (Header->Flags & DbiFlags::FlagHasCTypesMask) != 0;
180 : }
181 :
182 5 : bool DbiStream::isStripped() const {
183 10 : return (Header->Flags & DbiFlags::FlagStrippedMask) != 0;
184 : }
185 :
186 6 : uint16_t DbiStream::getBuildNumber() const { return Header->BuildNumber; }
187 :
188 5 : uint16_t DbiStream::getBuildMajorVersion() const {
189 10 : return (Header->BuildNumber & DbiBuildNo::BuildMajorMask) >>
190 5 : DbiBuildNo::BuildMajorShift;
191 : }
192 :
193 5 : uint16_t DbiStream::getBuildMinorVersion() const {
194 10 : return (Header->BuildNumber & DbiBuildNo::BuildMinorMask) >>
195 5 : DbiBuildNo::BuildMinorShift;
196 : }
197 :
198 6 : uint16_t DbiStream::getPdbDllRbld() const { return Header->PdbDllRbld; }
199 :
200 16 : uint32_t DbiStream::getPdbDllVersion() const { return Header->PdbDllVersion; }
201 :
202 47 : uint32_t DbiStream::getSymRecordStreamIndex() const {
203 94 : return Header->SymRecordStreamIndex;
204 : }
205 :
206 8 : PDB_Machine DbiStream::getMachineType() const {
207 16 : uint16_t Machine = Header->MachineType;
208 8 : return static_cast<PDB_Machine>(Machine);
209 : }
210 :
211 2 : msf::FixedStreamArray<object::coff_section> DbiStream::getSectionHeaders() {
212 2 : return SectionHeaders;
213 : }
214 :
215 2 : msf::FixedStreamArray<object::FpoData> DbiStream::getFpoRecords() {
216 2 : return FpoRecords;
217 : }
218 :
219 42 : ArrayRef<ModuleInfoEx> DbiStream::modules() const { return ModuleInfos; }
220 2 : msf::FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const {
221 2 : return SectionMap;
222 : }
223 :
224 2 : void DbiStream::visitSectionContributions(
225 : ISectionContribVisitor &Visitor) const {
226 2 : if (SectionContribVersion == DbiSecContribVer60) {
227 30 : for (auto &SC : SectionContribs)
228 12 : Visitor.visit(SC);
229 0 : } else if (SectionContribVersion == DbiSecContribV2) {
230 0 : for (auto &SC : SectionContribs2)
231 0 : Visitor.visit(SC);
232 : }
233 2 : }
234 :
235 10 : Error DbiStream::initializeSectionContributionData() {
236 10 : if (SecContrSubstream.getLength() == 0)
237 3 : return Error::success();
238 :
239 9 : StreamReader SCReader(SecContrSubstream);
240 27 : if (auto EC = SCReader.readEnum(SectionContribVersion))
241 0 : return EC;
242 :
243 9 : if (SectionContribVersion == DbiSecContribVer60)
244 9 : return loadSectionContribs<SectionContrib>(SectionContribs, SCReader);
245 0 : if (SectionContribVersion == DbiSecContribV2)
246 0 : return loadSectionContribs<SectionContrib2>(SectionContribs2, SCReader);
247 :
248 : return make_error<RawError>(raw_error_code::feature_unsupported,
249 0 : "Unsupported DBI Section Contribution version");
250 : }
251 :
252 10 : Error DbiStream::initializeModInfoArray() {
253 10 : if (ModInfoSubstream.getLength() == 0)
254 0 : return Error::success();
255 :
256 : // Since each ModInfo in the stream is a variable length, we have to iterate
257 : // them to know how many there actually are.
258 10 : StreamReader Reader(ModInfoSubstream);
259 :
260 10 : VarStreamArray<ModInfo> ModInfoArray;
261 30 : if (auto EC = Reader.readArray(ModInfoArray, ModInfoSubstream.getLength()))
262 0 : return EC;
263 180 : for (auto &Info : ModInfoArray) {
264 65 : ModuleInfos.emplace_back(Info);
265 : }
266 :
267 30 : return Error::success();
268 : }
269 :
270 : // Initializes this->SectionHeaders.
271 10 : Error DbiStream::initializeSectionHeadersData() {
272 20 : if (DbgStreams.size() == 0)
273 0 : return Error::success();
274 :
275 10 : uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::SectionHdr);
276 10 : if (StreamNum >= Pdb.getNumStreams())
277 0 : return make_error<RawError>(raw_error_code::no_stream);
278 :
279 : auto SHS = MappedBlockStream::createIndexedStream(
280 30 : Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum);
281 :
282 10 : size_t StreamLen = SHS->getLength();
283 10 : if (StreamLen % sizeof(object::coff_section))
284 : return make_error<RawError>(raw_error_code::corrupt_file,
285 0 : "Corrupted section header stream.");
286 :
287 10 : size_t NumSections = StreamLen / sizeof(object::coff_section);
288 20 : msf::StreamReader Reader(*SHS);
289 30 : if (auto EC = Reader.readArray(SectionHeaders, NumSections))
290 : return make_error<RawError>(raw_error_code::corrupt_file,
291 0 : "Could not read a bitmap.");
292 :
293 20 : SectionHeaderStream = std::move(SHS);
294 30 : return Error::success();
295 : }
296 :
297 : // Initializes this->Fpos.
298 10 : Error DbiStream::initializeFpoRecords() {
299 20 : if (DbgStreams.size() == 0)
300 0 : return Error::success();
301 :
302 10 : uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::NewFPO);
303 :
304 : // This means there is no FPO data.
305 10 : if (StreamNum == kInvalidStreamIndex)
306 0 : return Error::success();
307 :
308 10 : if (StreamNum >= Pdb.getNumStreams())
309 0 : return make_error<RawError>(raw_error_code::no_stream);
310 :
311 : auto FS = MappedBlockStream::createIndexedStream(
312 30 : Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum);
313 :
314 10 : size_t StreamLen = FS->getLength();
315 10 : if (StreamLen % sizeof(object::FpoData))
316 : return make_error<RawError>(raw_error_code::corrupt_file,
317 0 : "Corrupted New FPO stream.");
318 :
319 10 : size_t NumRecords = StreamLen / sizeof(object::FpoData);
320 20 : msf::StreamReader Reader(*FS);
321 30 : if (auto EC = Reader.readArray(FpoRecords, NumRecords))
322 : return make_error<RawError>(raw_error_code::corrupt_file,
323 0 : "Corrupted New FPO stream.");
324 20 : FpoStream = std::move(FS);
325 30 : return Error::success();
326 : }
327 :
328 10 : Error DbiStream::initializeSectionMapData() {
329 10 : if (SecMapSubstream.getLength() == 0)
330 3 : return Error::success();
331 :
332 9 : StreamReader SMReader(SecMapSubstream);
333 : const SecMapHeader *Header;
334 27 : if (auto EC = SMReader.readObject(Header))
335 0 : return EC;
336 36 : if (auto EC = SMReader.readArray(SectionMap, Header->SecCount))
337 0 : return EC;
338 27 : return Error::success();
339 : }
340 :
341 10 : Error DbiStream::initializeFileInfo() {
342 10 : if (FileInfoSubstream.getLength() == 0)
343 0 : return Error::success();
344 :
345 : const FileInfoSubstreamHeader *FH;
346 10 : StreamReader FISR(FileInfoSubstream);
347 30 : if (auto EC = FISR.readObject(FH))
348 0 : return EC;
349 :
350 : // The number of modules in the stream should be the same as reported by
351 : // the FileInfoSubstreamHeader.
352 30 : if (FH->NumModules != ModuleInfos.size())
353 : return make_error<RawError>(raw_error_code::corrupt_file,
354 0 : "FileInfo substream count doesn't match DBI.");
355 :
356 10 : FixedStreamArray<ulittle16_t> ModIndexArray;
357 10 : FixedStreamArray<ulittle16_t> ModFileCountArray;
358 :
359 : // First is an array of `NumModules` module indices. This is not used for the
360 : // same reason that `NumSourceFiles` is not used. It's an array of uint16's,
361 : // but it's possible there are more than 64k source files, which would imply
362 : // more than 64k modules (e.g. object files) as well. So we ignore this
363 : // field.
364 30 : if (auto EC = FISR.readArray(ModIndexArray, ModuleInfos.size()))
365 0 : return EC;
366 40 : if (auto EC = FISR.readArray(ModFileCountArray, ModuleInfos.size()))
367 0 : return EC;
368 :
369 : // Compute the real number of source files.
370 10 : uint32_t NumSourceFiles = 0;
371 160 : for (auto Count : ModFileCountArray)
372 65 : NumSourceFiles += Count;
373 :
374 : // This is the array that in the reference implementation corresponds to
375 : // `ModInfo::FileLayout::FileNameOffs`, which is commented there as being a
376 : // pointer. Due to the mentioned problems of pointers causing difficulty
377 : // when reading from the file on 64-bit systems, we continue to ignore that
378 : // field in `ModInfo`, and instead build a vector of StringRefs and stores
379 : // them in `ModuleInfoEx`. The value written to and read from the file is
380 : // not used anyway, it is only there as a way to store the offsets for the
381 : // purposes of later accessing the names at runtime.
382 30 : if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles))
383 0 : return EC;
384 :
385 30 : if (auto EC = FISR.readStreamRef(NamesBuffer))
386 0 : return EC;
387 :
388 : // We go through each ModuleInfo, determine the number N of source files for
389 : // that module, and then get the next N offsets from the Offsets array, using
390 : // them to get the corresponding N names from the Names buffer and associating
391 : // each one with the corresponding module.
392 10 : uint32_t NextFileIndex = 0;
393 150 : for (size_t I = 0; I < ModuleInfos.size(); ++I) {
394 130 : uint32_t NumFiles = ModFileCountArray[I];
395 130 : ModuleInfos[I].SourceFiles.resize(NumFiles);
396 387 : for (size_t J = 0; J < NumFiles; ++J, ++NextFileIndex) {
397 644 : auto ThisName = getFileNameForIndex(NextFileIndex);
398 322 : if (!ThisName)
399 0 : return ThisName.takeError();
400 1288 : ModuleInfos[I].SourceFiles[J] = *ThisName;
401 : }
402 : }
403 :
404 30 : return Error::success();
405 : }
406 :
407 288 : uint32_t DbiStream::getDebugStreamIndex(DbgHeaderType Type) const {
408 288 : uint16_t T = static_cast<uint16_t>(Type);
409 576 : if (T >= DbgStreams.size())
410 : return kInvalidStreamIndex;
411 576 : return DbgStreams[T];
412 : }
413 :
414 324 : Expected<StringRef> DbiStream::getFileNameForIndex(uint32_t Index) const {
415 324 : StreamReader Names(NamesBuffer);
416 648 : if (Index >= FileNameOffsets.size())
417 0 : return make_error<RawError>(raw_error_code::index_out_of_bounds);
418 :
419 648 : uint32_t FileOffset = FileNameOffsets[Index];
420 648 : Names.setOffset(FileOffset);
421 324 : StringRef Name;
422 972 : if (auto EC = Names.readZeroString(Name))
423 0 : return std::move(EC);
424 : return Name;
425 : }
|