blob: db84192bc364affbdf83d855130e6e94cd37ea91 [file] [log] [blame]
Zachary Turner53a65ba2016-04-26 18:42:34 +00001//===- PDBDbiStream.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/Raw/PDBDbiStream.h"
Zachary Turner1822af542016-04-27 23:41:42 +000011#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
Zachary Turner53a65ba2016-04-26 18:42:34 +000012#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
13#include "llvm/DebugInfo/PDB/Raw/PDBInfoStream.h"
14#include "llvm/DebugInfo/PDB/Raw/PDBRawConstants.h"
15
16using namespace llvm;
17using namespace llvm::support;
18
19namespace {
20// Some of the values are stored in bitfields. Since this needs to be portable
21// across compilers and architectures (big / little endian in particular) we
22// can't use the actual structures below, but must instead do the shifting
23// and masking ourselves. The struct definitions are provided for reference.
24
25// struct DbiFlags {
26// uint16_t IncrementalLinking : 1; // True if linked incrementally
27// uint16_t IsStripped : 1; // True if private symbols were stripped.
28// uint16_t HasCTypes : 1; // True if linked with /debug:ctypes.
29// uint16_t Reserved : 13;
30//};
31const uint16_t FlagIncrementalMask = 0x0001;
32const uint16_t FlagStrippedMask = 0x0002;
33const uint16_t FlagHasCTypesMask = 0x0004;
34
35// struct DbiBuildNo {
36// uint16_t MinorVersion : 8;
37// uint16_t MajorVersion : 7;
38// uint16_t NewVersionFormat : 1;
39//};
40const uint16_t BuildMinorMask = 0x00FF;
41const uint16_t BuildMinorShift = 0;
42
43const uint16_t BuildMajorMask = 0x7F00;
44const uint16_t BuildMajorShift = 8;
Zachary Turner53a65ba2016-04-26 18:42:34 +000045}
46
47struct PDBDbiStream::HeaderInfo {
Zachary Turnerff788aa2016-04-26 19:24:10 +000048 little32_t VersionSignature;
Zachary Turner53a65ba2016-04-26 18:42:34 +000049 ulittle32_t VersionHeader;
50 ulittle32_t Age; // Should match PDBInfoStream.
51 ulittle16_t GSSyms;
52 ulittle16_t BuildNumber; // See DbiBuildNo structure.
53 ulittle16_t PSSyms;
54 ulittle16_t PdbDllVersion; // version of mspdbNNN.dll
55 ulittle16_t SymRecords; // Number of symbols
56 ulittle16_t PdbDllRbld; // rbld number of mspdbNNN.dll
57 little32_t ModiSubstreamSize; // Size of module info stream
58 little32_t SecContrSubstreamSize; // Size of sec. contribution stream
59 little32_t SectionMapSize;
60 little32_t FileInfoSize;
61 little32_t TypeServerSize; // Size of type server map
62 ulittle32_t MFCTypeServerIndex; // Index of MFC Type Server
63 little32_t OptionalDbgHdrSize; // Size of DbgHeader info
64 little32_t ECSubstreamSize; // Size of EC stream (what is EC?)
65 ulittle16_t Flags; // See DbiFlags enum.
66 ulittle16_t MachineType; // See PDB_MachineType enum.
67
68 ulittle32_t Reserved; // Pad to 64 bytes
69};
70
71PDBDbiStream::PDBDbiStream(PDBFile &File) : Pdb(File), Stream(3, File) {
72 static_assert(sizeof(HeaderInfo) == 64, "Invalid HeaderInfo size!");
73}
74
75PDBDbiStream::~PDBDbiStream() {}
76
77std::error_code PDBDbiStream::reload() {
78 Stream.setOffset(0);
79 Header.reset(new HeaderInfo());
80
81 if (Stream.getLength() < sizeof(HeaderInfo))
82 return std::make_error_code(std::errc::illegal_byte_sequence);
83 Stream.readObject(Header.get());
84
85 if (Header->VersionSignature != -1)
86 return std::make_error_code(std::errc::illegal_byte_sequence);
87
Zachary Turner1822af542016-04-27 23:41:42 +000088 // Require at least version 7, which should be present in all PDBs
89 // produced in the last decade and allows us to avoid having to
90 // special case all kinds of complicated arcane formats.
91 if (Header->VersionHeader < PdbDbiV70)
Zachary Turner53a65ba2016-04-26 18:42:34 +000092 return std::make_error_code(std::errc::not_supported);
93
94 if (Header->Age != Pdb.getPDBInfoStream().getAge())
95 return std::make_error_code(std::errc::illegal_byte_sequence);
96
97 if (Stream.getLength() !=
98 sizeof(HeaderInfo) + Header->ModiSubstreamSize +
99 Header->SecContrSubstreamSize + Header->SectionMapSize +
100 Header->FileInfoSize + Header->TypeServerSize +
101 Header->OptionalDbgHdrSize + Header->ECSubstreamSize)
102 return std::make_error_code(std::errc::illegal_byte_sequence);
103
Zachary Turner1822af542016-04-27 23:41:42 +0000104 if (Header->ModiSubstreamSize % sizeof(uint32_t) != 0)
105 return std::make_error_code(std::errc::illegal_byte_sequence);
106
107 ModInfoSubstream.resize(Header->ModiSubstreamSize);
108 if (auto EC =
109 Stream.readBytes(&ModInfoSubstream[0], Header->ModiSubstreamSize))
110 return EC;
111
Zachary Turner53a65ba2016-04-26 18:42:34 +0000112 return std::error_code();
113}
114
115PdbRaw_DbiVer PDBDbiStream::getDbiVersion() const {
116 uint32_t Value = Header->VersionHeader;
117 return static_cast<PdbRaw_DbiVer>(Value);
118}
119
120uint32_t PDBDbiStream::getAge() const { return Header->Age; }
121
122bool PDBDbiStream::isIncrementallyLinked() const {
123 return (Header->Flags & FlagIncrementalMask) != 0;
124}
125
126bool PDBDbiStream::hasCTypes() const {
127 return (Header->Flags & FlagHasCTypesMask) != 0;
128}
129
130bool PDBDbiStream::isStripped() const {
131 return (Header->Flags & FlagStrippedMask) != 0;
132}
133
134uint16_t PDBDbiStream::getBuildMajorVersion() const {
135 return (Header->BuildNumber & BuildMajorMask) >> BuildMajorShift;
136}
137
138uint16_t PDBDbiStream::getBuildMinorVersion() const {
139 return (Header->BuildNumber & BuildMinorMask) >> BuildMinorShift;
140}
141
142uint32_t PDBDbiStream::getPdbDllVersion() const {
143 return Header->PdbDllVersion;
144}
145
146uint32_t PDBDbiStream::getNumberOfSymbols() const { return Header->SymRecords; }
147
148PDB_Machine PDBDbiStream::getMachineType() const {
149 uint16_t Machine = Header->MachineType;
150 return static_cast<PDB_Machine>(Machine);
151}
Zachary Turner1822af542016-04-27 23:41:42 +0000152
153llvm::iterator_range<ModInfoIterator> PDBDbiStream::modules() const {
154 return llvm::make_range(ModInfoIterator(&ModInfoSubstream.front()),
155 ModInfoIterator(&ModInfoSubstream.back() + 1));
156}