blob: 8604f982cb7540514dee87306936559e6a301aef [file] [log] [blame]
Zachary Turnerdbeaea72016-07-11 21:45:26 +00001//===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- C++ -*-===//
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/DbiStreamBuilder.h"
11
Rui Ueyamaf9904042016-10-11 19:43:12 +000012#include "llvm/ADT/ArrayRef.h"
Zachary Turner620961d2016-09-14 23:00:02 +000013#include "llvm/DebugInfo/MSF/MSFBuilder.h"
Zachary Turnera3225b02016-07-29 20:56:36 +000014#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
15#include "llvm/DebugInfo/MSF/StreamWriter.h"
Zachary Turnerdbeaea72016-07-11 21:45:26 +000016#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
Zachary Turnerdbeaea72016-07-11 21:45:26 +000017#include "llvm/DebugInfo/PDB/Raw/RawError.h"
18
19using namespace llvm;
20using namespace llvm::codeview;
Zachary Turnerbac69d32016-07-22 19:56:05 +000021using namespace llvm::msf;
Zachary Turnerdbeaea72016-07-11 21:45:26 +000022using namespace llvm::pdb;
23
Zachary Turnerd218c262016-07-22 15:46:37 +000024namespace {
25class ModiSubstreamBuilder {};
26}
27
Zachary Turner620961d2016-09-14 23:00:02 +000028DbiStreamBuilder::DbiStreamBuilder(msf::MSFBuilder &Msf)
29 : Msf(Msf), Allocator(Msf.getAllocator()), Age(1), BuildNumber(0),
30 PdbDllVersion(0), PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86),
Reid Kleckner5d0bc632016-10-11 20:02:57 +000031 Header(nullptr), DbgStreams((int)DbgHeaderType::Max) {}
Zachary Turnerdbeaea72016-07-11 21:45:26 +000032
33void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; }
34
35void DbiStreamBuilder::setAge(uint32_t A) { Age = A; }
36
37void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; }
38
39void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; }
40
41void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; }
42
43void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; }
44
45void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; }
46
Rui Ueyamaf9904042016-10-11 19:43:12 +000047Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type,
48 ArrayRef<uint8_t> Data) {
49 if (DbgStreams[(int)Type].StreamNumber)
50 return make_error<RawError>(raw_error_code::duplicate_entry,
51 "The specified stream type already exists");
52 auto ExpectedIndex = Msf.addStream(Data.size());
53 if (!ExpectedIndex)
54 return ExpectedIndex.takeError();
55 uint32_t Index = std::move(*ExpectedIndex);
56 DbgStreams[(int)Type].Data = Data;
57 DbgStreams[(int)Type].StreamNumber = Index;
58 return Error::success();
59}
60
Zachary Turnerfaa554b2016-07-15 22:16:56 +000061uint32_t DbiStreamBuilder::calculateSerializedLength() const {
62 // For now we only support serializing the header.
Zachary Turnerb383d622016-07-22 15:46:46 +000063 return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() +
Rui Ueyama77be2402016-10-29 00:56:44 +000064 calculateModiSubstreamSize() + calculateDbgStreamsSize();
Zachary Turnerd218c262016-07-22 15:46:37 +000065}
66
67Error DbiStreamBuilder::addModuleInfo(StringRef ObjFile, StringRef Module) {
68 auto Entry = llvm::make_unique<ModuleInfo>();
69 ModuleInfo *M = Entry.get();
70 Entry->Mod = Module;
71 Entry->Obj = ObjFile;
72 auto Result = ModuleInfos.insert(std::make_pair(Module, std::move(Entry)));
73 if (!Result.second)
74 return make_error<RawError>(raw_error_code::duplicate_entry,
75 "The specified module already exists");
76 ModuleInfoList.push_back(M);
77 return Error::success();
78}
79
80Error DbiStreamBuilder::addModuleSourceFile(StringRef Module, StringRef File) {
81 auto ModIter = ModuleInfos.find(Module);
82 if (ModIter == ModuleInfos.end())
83 return make_error<RawError>(raw_error_code::no_entry,
84 "The specified module was not found");
85 uint32_t Index = SourceFileNames.size();
86 SourceFileNames.insert(std::make_pair(File, Index));
87 auto &ModEntry = *ModIter;
88 ModEntry.second->SourceFiles.push_back(File);
89 return Error::success();
90}
91
92uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const {
93 uint32_t Size = 0;
94 for (const auto &M : ModuleInfoList) {
Zachary Turnerb383d622016-07-22 15:46:46 +000095 Size += sizeof(ModuleInfoHeader);
Zachary Turnerd218c262016-07-22 15:46:37 +000096 Size += M->Mod.size() + 1;
97 Size += M->Obj.size() + 1;
98 }
99 return Size;
100}
101
102uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const {
Zachary Turnerd218c262016-07-22 15:46:37 +0000103 uint32_t Size = 0;
104 Size += sizeof(ulittle16_t); // NumModules
105 Size += sizeof(ulittle16_t); // NumSourceFiles
106 Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModIndices
107 Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModFileCounts
108 uint32_t NumFileInfos = 0;
109 for (const auto &M : ModuleInfoList)
110 NumFileInfos += M->SourceFiles.size();
111 Size += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets
112 Size += calculateNamesBufferSize();
113 return Size;
114}
115
116uint32_t DbiStreamBuilder::calculateNamesBufferSize() const {
117 uint32_t Size = 0;
118 for (const auto &F : SourceFileNames) {
119 Size += F.getKeyLength() + 1; // Names[I];
120 }
121 return Size;
122}
123
Rui Ueyama77be2402016-10-29 00:56:44 +0000124uint32_t DbiStreamBuilder::calculateDbgStreamsSize() const {
125 return DbgStreams.size() * sizeof(uint16_t);
126}
127
Zachary Turnerd218c262016-07-22 15:46:37 +0000128Error DbiStreamBuilder::generateModiSubstream() {
129 uint32_t Size = calculateModiSubstreamSize();
130 auto Data = Allocator.Allocate<uint8_t>(Size);
131
Zachary Turnerd66889c2016-07-28 19:12:28 +0000132 ModInfoBuffer = MutableByteStream(MutableArrayRef<uint8_t>(Data, Size));
Zachary Turnerd218c262016-07-22 15:46:37 +0000133
134 StreamWriter ModiWriter(ModInfoBuffer);
135 for (const auto &M : ModuleInfoList) {
Zachary Turnerb383d622016-07-22 15:46:46 +0000136 ModuleInfoHeader Layout = {};
137 Layout.ModDiStream = kInvalidStreamIndex;
Zachary Turnerd218c262016-07-22 15:46:37 +0000138 Layout.NumFiles = M->SourceFiles.size();
139 if (auto EC = ModiWriter.writeObject(Layout))
140 return EC;
141 if (auto EC = ModiWriter.writeZeroString(M->Mod))
142 return EC;
143 if (auto EC = ModiWriter.writeZeroString(M->Obj))
144 return EC;
145 }
146 if (ModiWriter.bytesRemaining() != 0)
147 return make_error<RawError>(raw_error_code::invalid_format,
148 "Unexpected bytes in Modi Stream Data");
149 return Error::success();
150}
151
152Error DbiStreamBuilder::generateFileInfoSubstream() {
153 uint32_t Size = calculateFileInfoSubstreamSize();
154 uint32_t NameSize = calculateNamesBufferSize();
155 auto Data = Allocator.Allocate<uint8_t>(Size);
156 uint32_t NamesOffset = Size - NameSize;
157
Zachary Turnerd66889c2016-07-28 19:12:28 +0000158 FileInfoBuffer = MutableByteStream(MutableArrayRef<uint8_t>(Data, Size));
Zachary Turnerd218c262016-07-22 15:46:37 +0000159
Zachary Turnerd66889c2016-07-28 19:12:28 +0000160 WritableStreamRef MetadataBuffer =
161 WritableStreamRef(FileInfoBuffer).keep_front(NamesOffset);
Zachary Turnerd218c262016-07-22 15:46:37 +0000162 StreamWriter MetadataWriter(MetadataBuffer);
163
164 uint16_t ModiCount = std::min<uint16_t>(UINT16_MAX, ModuleInfos.size());
165 uint16_t FileCount = std::min<uint16_t>(UINT16_MAX, SourceFileNames.size());
166 if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules
167 return EC;
168 if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles
169 return EC;
170 for (uint16_t I = 0; I < ModiCount; ++I) {
171 if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices
172 return EC;
173 }
174 for (const auto MI : ModuleInfoList) {
175 FileCount = static_cast<uint16_t>(MI->SourceFiles.size());
176 if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts
177 return EC;
178 }
179
180 // Before writing the FileNameOffsets array, write the NamesBuffer array.
181 // A side effect of this is that this will actually compute the various
182 // file name offsets, so we can then go back and write the FileNameOffsets
183 // array to the other substream.
Zachary Turnerd66889c2016-07-28 19:12:28 +0000184 NamesBuffer = WritableStreamRef(FileInfoBuffer).drop_front(NamesOffset);
Zachary Turnerd218c262016-07-22 15:46:37 +0000185 StreamWriter NameBufferWriter(NamesBuffer);
186 for (auto &Name : SourceFileNames) {
187 Name.second = NameBufferWriter.getOffset();
188 if (auto EC = NameBufferWriter.writeZeroString(Name.getKey()))
189 return EC;
190 }
191
192 for (const auto MI : ModuleInfoList) {
193 for (StringRef Name : MI->SourceFiles) {
194 auto Result = SourceFileNames.find(Name);
195 if (Result == SourceFileNames.end())
196 return make_error<RawError>(raw_error_code::no_entry,
197 "The source file was not found.");
198 if (auto EC = MetadataWriter.writeInteger(Result->second))
199 return EC;
200 }
201 }
202
203 if (NameBufferWriter.bytesRemaining() > 0)
204 return make_error<RawError>(raw_error_code::invalid_format,
205 "The names buffer contained unexpected data.");
206
207 if (MetadataWriter.bytesRemaining() > 0)
208 return make_error<RawError>(
209 raw_error_code::invalid_format,
210 "The metadata buffer contained unexpected data.");
211
212 return Error::success();
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000213}
214
Zachary Turnerd66889c2016-07-28 19:12:28 +0000215Error DbiStreamBuilder::finalize() {
216 if (Header)
217 return Error::success();
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000218
Zachary Turnerd66889c2016-07-28 19:12:28 +0000219 DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>();
Zachary Turnerd218c262016-07-22 15:46:37 +0000220
221 if (auto EC = generateModiSubstream())
Zachary Turnere98137c2016-07-28 19:18:02 +0000222 return EC;
Zachary Turnerd218c262016-07-22 15:46:37 +0000223 if (auto EC = generateFileInfoSubstream())
Zachary Turnere98137c2016-07-28 19:18:02 +0000224 return EC;
Zachary Turnerd218c262016-07-22 15:46:37 +0000225
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000226 H->VersionHeader = *VerHeader;
227 H->VersionSignature = -1;
228 H->Age = Age;
229 H->BuildNumber = BuildNumber;
230 H->Flags = Flags;
231 H->PdbDllRbld = PdbDllRbld;
232 H->PdbDllVersion = PdbDllVersion;
233 H->MachineType = static_cast<uint16_t>(MachineType);
234
235 H->ECSubstreamSize = 0;
Zachary Turnerd218c262016-07-22 15:46:37 +0000236 H->FileInfoSize = FileInfoBuffer.getLength();
237 H->ModiSubstreamSize = ModInfoBuffer.getLength();
Rui Ueyamaf9904042016-10-11 19:43:12 +0000238 H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t);
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000239 H->SecContrSubstreamSize = 0;
240 H->SectionMapSize = 0;
241 H->TypeServerSize = 0;
Zachary Turnerb383d622016-07-22 15:46:46 +0000242 H->SymRecordStreamIndex = kInvalidStreamIndex;
243 H->PublicSymbolStreamIndex = kInvalidStreamIndex;
244 H->MFCTypeServerIndex = kInvalidStreamIndex;
245 H->GlobalSymbolStreamIndex = kInvalidStreamIndex;
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000246
Zachary Turnerd66889c2016-07-28 19:12:28 +0000247 Header = H;
248 return Error::success();
249}
250
Zachary Turner620961d2016-09-14 23:00:02 +0000251Error DbiStreamBuilder::finalizeMsfLayout() {
252 uint32_t Length = calculateSerializedLength();
253 if (auto EC = Msf.setStreamSize(StreamDBI, Length))
254 return EC;
255 return Error::success();
256}
257
Zachary Turnerd66889c2016-07-28 19:12:28 +0000258Expected<std::unique_ptr<DbiStream>>
259DbiStreamBuilder::build(PDBFile &File, const msf::WritableStream &Buffer) {
260 if (!VerHeader.hasValue())
261 return make_error<RawError>(raw_error_code::unspecified,
262 "Missing DBI Stream Version");
263 if (auto EC = finalize())
264 return std::move(EC);
265
266 auto StreamData = MappedBlockStream::createIndexedStream(File.getMsfLayout(),
267 Buffer, StreamDBI);
268 auto Dbi = llvm::make_unique<DbiStream>(File, std::move(StreamData));
269 Dbi->Header = Header;
270 Dbi->FileInfoSubstream = ReadableStreamRef(FileInfoBuffer);
271 Dbi->ModInfoSubstream = ReadableStreamRef(ModInfoBuffer);
Zachary Turnerd218c262016-07-22 15:46:37 +0000272 if (auto EC = Dbi->initializeModInfoArray())
273 return std::move(EC);
274 if (auto EC = Dbi->initializeFileInfo())
275 return std::move(EC);
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000276 return std::move(Dbi);
277}
Zachary Turnerd66889c2016-07-28 19:12:28 +0000278
Zachary Turnera3225b02016-07-29 20:56:36 +0000279Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
Rui Ueyamad1d8c8312016-08-03 23:43:23 +0000280 const msf::WritableStream &Buffer) {
281 if (auto EC = finalize())
282 return EC;
283
Zachary Turnerd66889c2016-07-28 19:12:28 +0000284 auto InfoS =
285 WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamDBI);
286
287 StreamWriter Writer(*InfoS);
288 if (auto EC = Writer.writeObject(*Header))
289 return EC;
290
291 if (auto EC = Writer.writeStreamRef(ModInfoBuffer))
292 return EC;
293 if (auto EC = Writer.writeStreamRef(FileInfoBuffer))
294 return EC;
Rui Ueyamaf9904042016-10-11 19:43:12 +0000295 for (auto &Stream : DbgStreams)
296 if (auto EC = Writer.writeInteger(Stream.StreamNumber))
297 return EC;
298
299 for (auto &Stream : DbgStreams) {
300 if (Stream.StreamNumber == kInvalidStreamIndex)
301 continue;
302 auto WritableStream = WritableMappedBlockStream::createIndexedStream(
303 Layout, Buffer, Stream.StreamNumber);
304 StreamWriter DbgStreamWriter(*WritableStream);
305 if (auto EC = DbgStreamWriter.writeArray(Stream.Data))
306 return EC;
307 }
Zachary Turnerd66889c2016-07-28 19:12:28 +0000308
309 if (Writer.bytesRemaining() > 0)
310 return make_error<RawError>(raw_error_code::invalid_format,
311 "Unexpected bytes found in DBI Stream");
312 return Error::success();
313}