blob: 829bb3d4b3cf103eb4e670df939e337767c7b7b8 [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 Ueyamaf9904042016-10-11 19:43:12 +000064 calculateModiSubstreamSize() + DbgStreams.size() * sizeof(uint16_t);
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
124Error DbiStreamBuilder::generateModiSubstream() {
125 uint32_t Size = calculateModiSubstreamSize();
126 auto Data = Allocator.Allocate<uint8_t>(Size);
127
Zachary Turnerd66889c2016-07-28 19:12:28 +0000128 ModInfoBuffer = MutableByteStream(MutableArrayRef<uint8_t>(Data, Size));
Zachary Turnerd218c262016-07-22 15:46:37 +0000129
130 StreamWriter ModiWriter(ModInfoBuffer);
131 for (const auto &M : ModuleInfoList) {
Zachary Turnerb383d622016-07-22 15:46:46 +0000132 ModuleInfoHeader Layout = {};
133 Layout.ModDiStream = kInvalidStreamIndex;
Zachary Turnerd218c262016-07-22 15:46:37 +0000134 Layout.NumFiles = M->SourceFiles.size();
135 if (auto EC = ModiWriter.writeObject(Layout))
136 return EC;
137 if (auto EC = ModiWriter.writeZeroString(M->Mod))
138 return EC;
139 if (auto EC = ModiWriter.writeZeroString(M->Obj))
140 return EC;
141 }
142 if (ModiWriter.bytesRemaining() != 0)
143 return make_error<RawError>(raw_error_code::invalid_format,
144 "Unexpected bytes in Modi Stream Data");
145 return Error::success();
146}
147
148Error DbiStreamBuilder::generateFileInfoSubstream() {
149 uint32_t Size = calculateFileInfoSubstreamSize();
150 uint32_t NameSize = calculateNamesBufferSize();
151 auto Data = Allocator.Allocate<uint8_t>(Size);
152 uint32_t NamesOffset = Size - NameSize;
153
Zachary Turnerd66889c2016-07-28 19:12:28 +0000154 FileInfoBuffer = MutableByteStream(MutableArrayRef<uint8_t>(Data, Size));
Zachary Turnerd218c262016-07-22 15:46:37 +0000155
Zachary Turnerd66889c2016-07-28 19:12:28 +0000156 WritableStreamRef MetadataBuffer =
157 WritableStreamRef(FileInfoBuffer).keep_front(NamesOffset);
Zachary Turnerd218c262016-07-22 15:46:37 +0000158 StreamWriter MetadataWriter(MetadataBuffer);
159
160 uint16_t ModiCount = std::min<uint16_t>(UINT16_MAX, ModuleInfos.size());
161 uint16_t FileCount = std::min<uint16_t>(UINT16_MAX, SourceFileNames.size());
162 if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules
163 return EC;
164 if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles
165 return EC;
166 for (uint16_t I = 0; I < ModiCount; ++I) {
167 if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices
168 return EC;
169 }
170 for (const auto MI : ModuleInfoList) {
171 FileCount = static_cast<uint16_t>(MI->SourceFiles.size());
172 if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts
173 return EC;
174 }
175
176 // Before writing the FileNameOffsets array, write the NamesBuffer array.
177 // A side effect of this is that this will actually compute the various
178 // file name offsets, so we can then go back and write the FileNameOffsets
179 // array to the other substream.
Zachary Turnerd66889c2016-07-28 19:12:28 +0000180 NamesBuffer = WritableStreamRef(FileInfoBuffer).drop_front(NamesOffset);
Zachary Turnerd218c262016-07-22 15:46:37 +0000181 StreamWriter NameBufferWriter(NamesBuffer);
182 for (auto &Name : SourceFileNames) {
183 Name.second = NameBufferWriter.getOffset();
184 if (auto EC = NameBufferWriter.writeZeroString(Name.getKey()))
185 return EC;
186 }
187
188 for (const auto MI : ModuleInfoList) {
189 for (StringRef Name : MI->SourceFiles) {
190 auto Result = SourceFileNames.find(Name);
191 if (Result == SourceFileNames.end())
192 return make_error<RawError>(raw_error_code::no_entry,
193 "The source file was not found.");
194 if (auto EC = MetadataWriter.writeInteger(Result->second))
195 return EC;
196 }
197 }
198
199 if (NameBufferWriter.bytesRemaining() > 0)
200 return make_error<RawError>(raw_error_code::invalid_format,
201 "The names buffer contained unexpected data.");
202
203 if (MetadataWriter.bytesRemaining() > 0)
204 return make_error<RawError>(
205 raw_error_code::invalid_format,
206 "The metadata buffer contained unexpected data.");
207
208 return Error::success();
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000209}
210
Zachary Turnerd66889c2016-07-28 19:12:28 +0000211Error DbiStreamBuilder::finalize() {
212 if (Header)
213 return Error::success();
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000214
Zachary Turnerd66889c2016-07-28 19:12:28 +0000215 DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>();
Zachary Turnerd218c262016-07-22 15:46:37 +0000216
217 if (auto EC = generateModiSubstream())
Zachary Turnere98137c2016-07-28 19:18:02 +0000218 return EC;
Zachary Turnerd218c262016-07-22 15:46:37 +0000219 if (auto EC = generateFileInfoSubstream())
Zachary Turnere98137c2016-07-28 19:18:02 +0000220 return EC;
Zachary Turnerd218c262016-07-22 15:46:37 +0000221
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000222 H->VersionHeader = *VerHeader;
223 H->VersionSignature = -1;
224 H->Age = Age;
225 H->BuildNumber = BuildNumber;
226 H->Flags = Flags;
227 H->PdbDllRbld = PdbDllRbld;
228 H->PdbDllVersion = PdbDllVersion;
229 H->MachineType = static_cast<uint16_t>(MachineType);
230
231 H->ECSubstreamSize = 0;
Zachary Turnerd218c262016-07-22 15:46:37 +0000232 H->FileInfoSize = FileInfoBuffer.getLength();
233 H->ModiSubstreamSize = ModInfoBuffer.getLength();
Rui Ueyamaf9904042016-10-11 19:43:12 +0000234 H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t);
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000235 H->SecContrSubstreamSize = 0;
236 H->SectionMapSize = 0;
237 H->TypeServerSize = 0;
Zachary Turnerb383d622016-07-22 15:46:46 +0000238 H->SymRecordStreamIndex = kInvalidStreamIndex;
239 H->PublicSymbolStreamIndex = kInvalidStreamIndex;
240 H->MFCTypeServerIndex = kInvalidStreamIndex;
241 H->GlobalSymbolStreamIndex = kInvalidStreamIndex;
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000242
Zachary Turnerd66889c2016-07-28 19:12:28 +0000243 Header = H;
244 return Error::success();
245}
246
Zachary Turner620961d2016-09-14 23:00:02 +0000247Error DbiStreamBuilder::finalizeMsfLayout() {
248 uint32_t Length = calculateSerializedLength();
249 if (auto EC = Msf.setStreamSize(StreamDBI, Length))
250 return EC;
251 return Error::success();
252}
253
Zachary Turnerd66889c2016-07-28 19:12:28 +0000254Expected<std::unique_ptr<DbiStream>>
255DbiStreamBuilder::build(PDBFile &File, const msf::WritableStream &Buffer) {
256 if (!VerHeader.hasValue())
257 return make_error<RawError>(raw_error_code::unspecified,
258 "Missing DBI Stream Version");
259 if (auto EC = finalize())
260 return std::move(EC);
261
262 auto StreamData = MappedBlockStream::createIndexedStream(File.getMsfLayout(),
263 Buffer, StreamDBI);
264 auto Dbi = llvm::make_unique<DbiStream>(File, std::move(StreamData));
265 Dbi->Header = Header;
266 Dbi->FileInfoSubstream = ReadableStreamRef(FileInfoBuffer);
267 Dbi->ModInfoSubstream = ReadableStreamRef(ModInfoBuffer);
Zachary Turnerd218c262016-07-22 15:46:37 +0000268 if (auto EC = Dbi->initializeModInfoArray())
269 return std::move(EC);
270 if (auto EC = Dbi->initializeFileInfo())
271 return std::move(EC);
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000272 return std::move(Dbi);
273}
Zachary Turnerd66889c2016-07-28 19:12:28 +0000274
Zachary Turnera3225b02016-07-29 20:56:36 +0000275Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
Rui Ueyamad1d8c8312016-08-03 23:43:23 +0000276 const msf::WritableStream &Buffer) {
277 if (auto EC = finalize())
278 return EC;
279
Zachary Turnerd66889c2016-07-28 19:12:28 +0000280 auto InfoS =
281 WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamDBI);
282
283 StreamWriter Writer(*InfoS);
284 if (auto EC = Writer.writeObject(*Header))
285 return EC;
286
287 if (auto EC = Writer.writeStreamRef(ModInfoBuffer))
288 return EC;
289 if (auto EC = Writer.writeStreamRef(FileInfoBuffer))
290 return EC;
Rui Ueyamaf9904042016-10-11 19:43:12 +0000291 for (auto &Stream : DbgStreams)
292 if (auto EC = Writer.writeInteger(Stream.StreamNumber))
293 return EC;
294
295 for (auto &Stream : DbgStreams) {
296 if (Stream.StreamNumber == kInvalidStreamIndex)
297 continue;
298 auto WritableStream = WritableMappedBlockStream::createIndexedStream(
299 Layout, Buffer, Stream.StreamNumber);
300 StreamWriter DbgStreamWriter(*WritableStream);
301 if (auto EC = DbgStreamWriter.writeArray(Stream.Data))
302 return EC;
303 }
Zachary Turnerd66889c2016-07-28 19:12:28 +0000304
305 if (Writer.bytesRemaining() > 0)
306 return make_error<RawError>(raw_error_code::invalid_format,
307 "Unexpected bytes found in DBI Stream");
308 return Error::success();
309}