LLVM  4.0.0
DbiStream.cpp
Go to the documentation of this file.
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"
24 #include "llvm/Object/COFF.h"
25 #include "llvm/Support/Error.h"
26 #include <algorithm>
27 #include <cstddef>
28 #include <cstdint>
29 
30 using namespace llvm;
31 using namespace llvm::codeview;
32 using namespace llvm::msf;
33 using namespace llvm::pdb;
34 using namespace llvm::support;
35 
36 template <typename ContribType>
38  StreamReader &Reader) {
39  if (Reader.bytesRemaining() % sizeof(ContribType) != 0)
40  return make_error<RawError>(
41  raw_error_code::corrupt_file,
42  "Invalid number of bytes of section contributions");
43 
44  uint32_t Count = Reader.bytesRemaining() / sizeof(ContribType);
45  if (auto EC = Reader.readArray(Output, Count))
46  return EC;
47  return Error::success();
48 }
49 
50 DbiStream::DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream)
51  : Pdb(File), Stream(std::move(Stream)), Header(nullptr) {
52 }
53 
54 DbiStream::~DbiStream() = default;
55 
57  StreamReader Reader(*Stream);
58 
59  if (Stream->getLength() < sizeof(DbiStreamHeader))
60  return make_error<RawError>(raw_error_code::corrupt_file,
61  "DBI Stream does not contain a header.");
62  if (auto EC = Reader.readObject(Header))
63  return make_error<RawError>(raw_error_code::corrupt_file,
64  "DBI Stream does not contain a header.");
65 
66  if (Header->VersionSignature != -1)
67  return make_error<RawError>(raw_error_code::corrupt_file,
68  "Invalid DBI version signature.");
69 
70  // Require at least version 7, which should be present in all PDBs
71  // produced in the last decade and allows us to avoid having to
72  // special case all kinds of complicated arcane formats.
73  if (Header->VersionHeader < PdbDbiV70)
74  return make_error<RawError>(raw_error_code::feature_unsupported,
75  "Unsupported DBI version.");
76 
77  auto IS = Pdb.getPDBInfoStream();
78  if (!IS)
79  return IS.takeError();
80 
81  if (Header->Age != IS->getAge())
82  return make_error<RawError>(raw_error_code::corrupt_file,
83  "DBI Age does not match PDB Age.");
84 
85  if (Stream->getLength() !=
86  sizeof(DbiStreamHeader) + Header->ModiSubstreamSize +
87  Header->SecContrSubstreamSize + Header->SectionMapSize +
88  Header->FileInfoSize + Header->TypeServerSize +
89  Header->OptionalDbgHdrSize + Header->ECSubstreamSize)
90  return make_error<RawError>(raw_error_code::corrupt_file,
91  "DBI Length does not equal sum of substreams.");
92 
93  // Only certain substreams are guaranteed to be aligned. Validate
94  // them here.
95  if (Header->ModiSubstreamSize % sizeof(uint32_t) != 0)
96  return make_error<RawError>(raw_error_code::corrupt_file,
97  "DBI MODI substream not aligned.");
98  if (Header->SecContrSubstreamSize % sizeof(uint32_t) != 0)
99  return make_error<RawError>(
100  raw_error_code::corrupt_file,
101  "DBI section contribution substream not aligned.");
102  if (Header->SectionMapSize % sizeof(uint32_t) != 0)
103  return make_error<RawError>(raw_error_code::corrupt_file,
104  "DBI section map substream not aligned.");
105  if (Header->FileInfoSize % sizeof(uint32_t) != 0)
106  return make_error<RawError>(raw_error_code::corrupt_file,
107  "DBI file info substream not aligned.");
108  if (Header->TypeServerSize % sizeof(uint32_t) != 0)
109  return make_error<RawError>(raw_error_code::corrupt_file,
110  "DBI type server substream not aligned.");
111 
112  if (auto EC =
113  Reader.readStreamRef(ModInfoSubstream, Header->ModiSubstreamSize))
114  return EC;
115  if (auto EC = initializeModInfoArray())
116  return EC;
117 
118  if (auto EC = Reader.readStreamRef(SecContrSubstream,
119  Header->SecContrSubstreamSize))
120  return EC;
121  if (auto EC = Reader.readStreamRef(SecMapSubstream, Header->SectionMapSize))
122  return EC;
123  if (auto EC = Reader.readStreamRef(FileInfoSubstream, Header->FileInfoSize))
124  return EC;
125  if (auto EC =
126  Reader.readStreamRef(TypeServerMapSubstream, Header->TypeServerSize))
127  return EC;
128  if (auto EC = Reader.readStreamRef(ECSubstream, Header->ECSubstreamSize))
129  return EC;
130  if (auto EC = Reader.readArray(DbgStreams, Header->OptionalDbgHdrSize /
131  sizeof(ulittle16_t)))
132  return EC;
133 
134  if (auto EC = initializeSectionContributionData())
135  return EC;
136  if (auto EC = initializeSectionHeadersData())
137  return EC;
138  if (auto EC = initializeSectionMapData())
139  return EC;
140  if (auto EC = initializeFileInfo())
141  return EC;
142  if (auto EC = initializeFpoRecords())
143  return EC;
144 
145  if (Reader.bytesRemaining() > 0)
146  return make_error<RawError>(raw_error_code::corrupt_file,
147  "Found unexpected bytes in DBI Stream.");
148 
149  if (ECSubstream.getLength() > 0) {
150  StreamReader ECReader(ECSubstream);
151  if (auto EC = ECNames.load(ECReader))
152  return EC;
153  }
154 
155  return Error::success();
156 }
157 
159  uint32_t Value = Header->VersionHeader;
160  return static_cast<PdbRaw_DbiVer>(Value);
161 }
162 
163 uint32_t DbiStream::getAge() const { return Header->Age; }
164 
166  return Header->PublicSymbolStreamIndex;
167 }
168 
170  return Header->GlobalSymbolStreamIndex;
171 }
172 
173 uint16_t DbiStream::getFlags() const { return Header->Flags; }
174 
176  return (Header->Flags & DbiFlags::FlagIncrementalMask) != 0;
177 }
178 
179 bool DbiStream::hasCTypes() const {
180  return (Header->Flags & DbiFlags::FlagHasCTypesMask) != 0;
181 }
182 
183 bool DbiStream::isStripped() const {
184  return (Header->Flags & DbiFlags::FlagStrippedMask) != 0;
185 }
186 
187 uint16_t DbiStream::getBuildNumber() const { return Header->BuildNumber; }
188 
190  return (Header->BuildNumber & DbiBuildNo::BuildMajorMask) >>
192 }
193 
195  return (Header->BuildNumber & DbiBuildNo::BuildMinorMask) >>
197 }
198 
199 uint16_t DbiStream::getPdbDllRbld() const { return Header->PdbDllRbld; }
200 
202 
204  return Header->SymRecordStreamIndex;
205 }
206 
208  uint16_t Machine = Header->MachineType;
209  return static_cast<PDB_Machine>(Machine);
210 }
211 
213  return SectionHeaders;
214 }
215 
217  return FpoRecords;
218 }
219 
220 ArrayRef<ModuleInfoEx> DbiStream::modules() const { return ModuleInfos; }
222  return SectionMap;
223 }
224 
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  StreamReader 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 Error DbiStream::initializeModInfoArray() {
254  if (ModInfoSubstream.getLength() == 0)
255  return Error::success();
256 
257  // Since each ModInfo in the stream is a variable length, we have to iterate
258  // them to know how many there actually are.
259  StreamReader Reader(ModInfoSubstream);
260 
261  VarStreamArray<ModInfo> ModInfoArray;
262  if (auto EC = Reader.readArray(ModInfoArray, ModInfoSubstream.getLength()))
263  return EC;
264  for (auto &Info : ModInfoArray) {
265  ModuleInfos.emplace_back(Info);
266  }
267 
268  return Error::success();
269 }
270 
271 // Initializes this->SectionHeaders.
272 Error DbiStream::initializeSectionHeadersData() {
273  if (DbgStreams.size() == 0)
274  return Error::success();
275 
277  if (StreamNum >= Pdb.getNumStreams())
278  return make_error<RawError>(raw_error_code::no_stream);
279 
280  auto SHS = MappedBlockStream::createIndexedStream(
281  Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum);
282 
283  size_t StreamLen = SHS->getLength();
284  if (StreamLen % sizeof(object::coff_section))
285  return make_error<RawError>(raw_error_code::corrupt_file,
286  "Corrupted section header stream.");
287 
288  size_t NumSections = StreamLen / sizeof(object::coff_section);
289  msf::StreamReader Reader(*SHS);
290  if (auto EC = Reader.readArray(SectionHeaders, NumSections))
291  return make_error<RawError>(raw_error_code::corrupt_file,
292  "Could not read a bitmap.");
293 
294  SectionHeaderStream = std::move(SHS);
295  return Error::success();
296 }
297 
298 // Initializes this->Fpos.
299 Error DbiStream::initializeFpoRecords() {
300  if (DbgStreams.size() == 0)
301  return Error::success();
302 
304 
305  // This means there is no FPO data.
306  if (StreamNum == kInvalidStreamIndex)
307  return Error::success();
308 
309  if (StreamNum >= Pdb.getNumStreams())
310  return make_error<RawError>(raw_error_code::no_stream);
311 
312  auto FS = MappedBlockStream::createIndexedStream(
313  Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum);
314 
315  size_t StreamLen = FS->getLength();
316  if (StreamLen % sizeof(object::FpoData))
317  return make_error<RawError>(raw_error_code::corrupt_file,
318  "Corrupted New FPO stream.");
319 
320  size_t NumRecords = StreamLen / sizeof(object::FpoData);
321  msf::StreamReader Reader(*FS);
322  if (auto EC = Reader.readArray(FpoRecords, NumRecords))
323  return make_error<RawError>(raw_error_code::corrupt_file,
324  "Corrupted New FPO stream.");
325  FpoStream = std::move(FS);
326  return Error::success();
327 }
328 
329 Error DbiStream::initializeSectionMapData() {
330  if (SecMapSubstream.getLength() == 0)
331  return Error::success();
332 
333  StreamReader SMReader(SecMapSubstream);
334  const SecMapHeader *Header;
335  if (auto EC = SMReader.readObject(Header))
336  return EC;
337  if (auto EC = SMReader.readArray(SectionMap, Header->SecCount))
338  return EC;
339  return Error::success();
340 }
341 
342 Error DbiStream::initializeFileInfo() {
343  if (FileInfoSubstream.getLength() == 0)
344  return Error::success();
345 
346  const FileInfoSubstreamHeader *FH;
347  StreamReader FISR(FileInfoSubstream);
348  if (auto EC = FISR.readObject(FH))
349  return EC;
350 
351  // The number of modules in the stream should be the same as reported by
352  // the FileInfoSubstreamHeader.
353  if (FH->NumModules != ModuleInfos.size())
354  return make_error<RawError>(raw_error_code::corrupt_file,
355  "FileInfo substream count doesn't match DBI.");
356 
357  FixedStreamArray<ulittle16_t> ModIndexArray;
358  FixedStreamArray<ulittle16_t> ModFileCountArray;
359 
360  // First is an array of `NumModules` module indices. This is not used for the
361  // same reason that `NumSourceFiles` is not used. It's an array of uint16's,
362  // but it's possible there are more than 64k source files, which would imply
363  // more than 64k modules (e.g. object files) as well. So we ignore this
364  // field.
365  if (auto EC = FISR.readArray(ModIndexArray, ModuleInfos.size()))
366  return EC;
367  if (auto EC = FISR.readArray(ModFileCountArray, ModuleInfos.size()))
368  return EC;
369 
370  // Compute the real number of source files.
371  uint32_t NumSourceFiles = 0;
372  for (auto Count : ModFileCountArray)
373  NumSourceFiles += Count;
374 
375  // This is the array that in the reference implementation corresponds to
376  // `ModInfo::FileLayout::FileNameOffs`, which is commented there as being a
377  // pointer. Due to the mentioned problems of pointers causing difficulty
378  // when reading from the file on 64-bit systems, we continue to ignore that
379  // field in `ModInfo`, and instead build a vector of StringRefs and stores
380  // them in `ModuleInfoEx`. The value written to and read from the file is
381  // not used anyway, it is only there as a way to store the offsets for the
382  // purposes of later accessing the names at runtime.
383  if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles))
384  return EC;
385 
386  if (auto EC = FISR.readStreamRef(NamesBuffer))
387  return EC;
388 
389  // We go through each ModuleInfo, determine the number N of source files for
390  // that module, and then get the next N offsets from the Offsets array, using
391  // them to get the corresponding N names from the Names buffer and associating
392  // each one with the corresponding module.
393  uint32_t NextFileIndex = 0;
394  for (size_t I = 0; I < ModuleInfos.size(); ++I) {
395  uint32_t NumFiles = ModFileCountArray[I];
396  ModuleInfos[I].SourceFiles.resize(NumFiles);
397  for (size_t J = 0; J < NumFiles; ++J, ++NextFileIndex) {
398  auto ThisName = getFileNameForIndex(NextFileIndex);
399  if (!ThisName)
400  return ThisName.takeError();
401  ModuleInfos[I].SourceFiles[J] = *ThisName;
402  }
403  }
404 
405  return Error::success();
406 }
407 
409  uint16_t T = static_cast<uint16_t>(Type);
410  if (T >= DbgStreams.size())
411  return kInvalidStreamIndex;
412  return DbgStreams[T];
413 }
414 
416  StreamReader Names(NamesBuffer);
417  if (Index >= FileNameOffsets.size())
418  return make_error<RawError>(raw_error_code::index_out_of_bounds);
419 
420  uint32_t FileOffset = FileNameOffsets[Index];
421  Names.setOffset(FileOffset);
422  StringRef Name;
423  if (auto EC = Names.readZeroString(Name))
424  return std::move(EC);
425  return Name;
426 }
support::little32_t FileInfoSize
Size of file info substream.
Definition: RawTypes.h:145
virtual void visit(const SectionContrib &C)=0
void visitSectionContributions(ISectionContribVisitor &Visitor) const
Definition: DbiStream.cpp:225
static const uint16_t FlagHasCTypesMask
Definition: RawTypes.h:95
support::little32_t VersionSignature
Definition: RawTypes.h:111
static const uint16_t BuildMinorMask
uint16_t MinorVersion : 8; uint16_t MajorVersion : 7; uint16_t NewVersionFormat : 1; ...
Definition: RawTypes.h:102
support::ulittle16_t GlobalSymbolStreamIndex
Global symbol stream #.
Definition: RawTypes.h:118
uint16_t getPublicSymbolStreamIndex() const
Definition: DbiStream.cpp:165
uint16_t getGlobalSymbolStreamIndex() const
Definition: DbiStream.cpp:169
void setOffset(uint32_t Off)
Definition: StreamReader.h:105
uint32_t getPdbDllVersion() const
Definition: DbiStream.cpp:201
support::ulittle16_t BuildNumber
See DbiBuildNo structure.
Definition: RawTypes.h:121
bool isStripped() const
Definition: DbiStream.cpp:183
uint32_t getNumStreams() const override
Definition: PDBFile.cpp:77
bool isIncrementallyLinked() const
Definition: DbiStream.cpp:175
support::little32_t TypeServerSize
Size of type server map.
Definition: RawTypes.h:148
uint16_t getBuildMajorVersion() const
Definition: DbiStream.cpp:189
support::little32_t SectionMapSize
Size of sec. map substream.
Definition: RawTypes.h:142
Error readZeroString(StringRef &Dest)
Tagged union holding either a T or a Error.
uint32_t size() const
Definition: StreamArray.h:233
The fixed size header that appears at the beginning of the DBI Stream.
Definition: RawTypes.h:110
support::little32_t ECSubstreamSize
Size of EC stream (what is EC?)
Definition: RawTypes.h:157
#define T
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
Definition: APInt.h:33
COFF::MachineTypes Machine
Definition: COFFYAML.cpp:303
uint32_t getAge() const
Definition: DbiStream.cpp:163
const uint16_t kInvalidStreamIndex
Definition: RawConstants.h:20
support::ulittle16_t PdbDllRbld
rbld number of mspdbNNN.dll
Definition: RawTypes.h:133
uint16_t getFlags() const
Definition: DbiStream.cpp:173
msf::FixedStreamArray< SecMapEntry > getSectionMap() const
Definition: DbiStream.cpp:221
static const uint16_t BuildMajorShift
Definition: RawTypes.h:106
uint32_t getLength() const
Definition: StreamRef.h:29
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:45
uint16_t getBuildNumber() const
Definition: DbiStream.cpp:187
PDB_Machine getMachineType() const
Definition: DbiStream.cpp:207
Error readArray(ArrayRef< T > &Array, uint32_t NumElements)
Definition: StreamReader.h:62
Expected< StringRef > getFileNameForIndex(uint32_t Index) const
Definition: DbiStream.cpp:415
msf::FixedStreamArray< object::FpoData > getFpoRecords()
Definition: DbiStream.cpp:216
const msf::ReadableStream & getMsfBuffer() const
Definition: PDBFile.h:80
const msf::MSFLayout & getMsfLayout() const
Definition: PDBFile.h:79
The header preceeding the File Info Substream of the DBI stream.
Definition: RawTypes.h:183
ArrayRef< ModuleInfoEx > modules() const
Definition: DbiStream.cpp:220
support::ulittle16_t PdbDllVersion
version of mspdbNNN.dll
Definition: RawTypes.h:127
uint32_t getSymRecordStreamIndex() const
Definition: DbiStream.cpp:203
static const uint16_t FlagIncrementalMask
uint16_t IncrementalLinking : 1; // True if linked incrementally uint16_t IsStripped : 1; // True if ...
Definition: RawTypes.h:93
support::little32_t OptionalDbgHdrSize
Size of DbgHeader info.
Definition: RawTypes.h:154
support::ulittle16_t Flags
See DbiFlags enum.
Definition: RawTypes.h:160
static ErrorSuccess success()
Create a success value.
CHAIN = SC CHAIN, Imm128 - System call.
support::ulittle16_t NumModules
Total # of modules, should match number of records in the ModuleInfo substream.
Definition: RawTypes.h:186
static Error loadSectionContribs(FixedStreamArray< ContribType > &Output, StreamReader &Reader)
Definition: DbiStream.cpp:37
support::ulittle16_t SecCount
Definition: RawTypes.h:53
uint16_t getPdbDllRbld() const
Definition: DbiStream.cpp:199
static const uint16_t FlagStrippedMask
Definition: RawTypes.h:94
support::little32_t ModiSubstreamSize
Size of module info stream.
Definition: RawTypes.h:136
uint32_t getDebugStreamIndex(DbgHeaderType Type) const
If the given stream type is present, returns its stream index.
Definition: DbiStream.cpp:408
PdbRaw_DbiVer getDbiVersion() const
Definition: DbiStream.cpp:158
msf::FixedStreamArray< object::coff_section > getSectionHeaders()
Definition: DbiStream.cpp:212
uint16_t getBuildMinorVersion() const
Definition: DbiStream.cpp:194
Error load(msf::StreamReader &Stream)
support::little32_t SecContrSubstreamSize
Size of sec. contrib stream.
Definition: RawTypes.h:139
static const uint16_t BuildMajorMask
Definition: RawTypes.h:105
#define I(x, y, z)
Definition: MD5.cpp:54
support::ulittle32_t Age
How "old" is this DBI Stream. Should match the age of the PDB InfoStream.
Definition: RawTypes.h:115
Error readStreamRef(ReadableStreamRef &Ref)
support::ulittle16_t SymRecordStreamIndex
Symbol records stream #.
Definition: RawTypes.h:130
support::ulittle32_t VersionHeader
Definition: RawTypes.h:112
static const uint16_t BuildMinorShift
Definition: RawTypes.h:103
uint32_t bytesRemaining() const
Definition: StreamReader.h:108
Expected< InfoStream & > getPDBInfoStream()
Definition: PDBFile.cpp:241
LLVM Value Representation.
Definition: Value.h:71
Lightweight error class with error context and mandatory checking.
support::ulittle16_t PublicSymbolStreamIndex
Public symbols stream #.
Definition: RawTypes.h:124
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:47
support::ulittle16_t MachineType
See PDB_MachineType enum.
Definition: RawTypes.h:163
bool hasCTypes() const
Definition: DbiStream.cpp:179
Error readObject(const T *&Dest)
Definition: StreamReader.h:53