blob: bb0e730edd3ce2a45e9adda251918b0cd1a5ba92 [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
Zachary Turner620961d2016-09-14 23:00:02 +000012#include "llvm/DebugInfo/MSF/MSFBuilder.h"
Zachary Turnera3225b02016-07-29 20:56:36 +000013#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
14#include "llvm/DebugInfo/MSF/StreamWriter.h"
Zachary Turnerdbeaea72016-07-11 21:45:26 +000015#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
Zachary Turnerdbeaea72016-07-11 21:45:26 +000016#include "llvm/DebugInfo/PDB/Raw/RawError.h"
17
18using namespace llvm;
19using namespace llvm::codeview;
Zachary Turnerbac69d32016-07-22 19:56:05 +000020using namespace llvm::msf;
Zachary Turnerdbeaea72016-07-11 21:45:26 +000021using namespace llvm::pdb;
22
Zachary Turnerd218c262016-07-22 15:46:37 +000023namespace {
24class ModiSubstreamBuilder {};
25}
26
Zachary Turner620961d2016-09-14 23:00:02 +000027DbiStreamBuilder::DbiStreamBuilder(msf::MSFBuilder &Msf)
28 : Msf(Msf), Allocator(Msf.getAllocator()), Age(1), BuildNumber(0),
29 PdbDllVersion(0), PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86),
30 Header(nullptr) {}
Zachary Turnerdbeaea72016-07-11 21:45:26 +000031
32void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; }
33
34void DbiStreamBuilder::setAge(uint32_t A) { Age = A; }
35
36void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; }
37
38void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; }
39
40void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; }
41
42void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; }
43
44void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; }
45
Zachary Turnerfaa554b2016-07-15 22:16:56 +000046uint32_t DbiStreamBuilder::calculateSerializedLength() const {
47 // For now we only support serializing the header.
Zachary Turnerb383d622016-07-22 15:46:46 +000048 return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() +
Zachary Turnerd218c262016-07-22 15:46:37 +000049 calculateModiSubstreamSize();
50}
51
52Error DbiStreamBuilder::addModuleInfo(StringRef ObjFile, StringRef Module) {
53 auto Entry = llvm::make_unique<ModuleInfo>();
54 ModuleInfo *M = Entry.get();
55 Entry->Mod = Module;
56 Entry->Obj = ObjFile;
57 auto Result = ModuleInfos.insert(std::make_pair(Module, std::move(Entry)));
58 if (!Result.second)
59 return make_error<RawError>(raw_error_code::duplicate_entry,
60 "The specified module already exists");
61 ModuleInfoList.push_back(M);
62 return Error::success();
63}
64
65Error DbiStreamBuilder::addModuleSourceFile(StringRef Module, StringRef File) {
66 auto ModIter = ModuleInfos.find(Module);
67 if (ModIter == ModuleInfos.end())
68 return make_error<RawError>(raw_error_code::no_entry,
69 "The specified module was not found");
70 uint32_t Index = SourceFileNames.size();
71 SourceFileNames.insert(std::make_pair(File, Index));
72 auto &ModEntry = *ModIter;
73 ModEntry.second->SourceFiles.push_back(File);
74 return Error::success();
75}
76
77uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const {
78 uint32_t Size = 0;
79 for (const auto &M : ModuleInfoList) {
Zachary Turnerb383d622016-07-22 15:46:46 +000080 Size += sizeof(ModuleInfoHeader);
Zachary Turnerd218c262016-07-22 15:46:37 +000081 Size += M->Mod.size() + 1;
82 Size += M->Obj.size() + 1;
83 }
84 return Size;
85}
86
87uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const {
Zachary Turnerd218c262016-07-22 15:46:37 +000088 uint32_t Size = 0;
89 Size += sizeof(ulittle16_t); // NumModules
90 Size += sizeof(ulittle16_t); // NumSourceFiles
91 Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModIndices
92 Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModFileCounts
93 uint32_t NumFileInfos = 0;
94 for (const auto &M : ModuleInfoList)
95 NumFileInfos += M->SourceFiles.size();
96 Size += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets
97 Size += calculateNamesBufferSize();
98 return Size;
99}
100
101uint32_t DbiStreamBuilder::calculateNamesBufferSize() const {
102 uint32_t Size = 0;
103 for (const auto &F : SourceFileNames) {
104 Size += F.getKeyLength() + 1; // Names[I];
105 }
106 return Size;
107}
108
109Error DbiStreamBuilder::generateModiSubstream() {
110 uint32_t Size = calculateModiSubstreamSize();
111 auto Data = Allocator.Allocate<uint8_t>(Size);
112
Zachary Turnerd66889c2016-07-28 19:12:28 +0000113 ModInfoBuffer = MutableByteStream(MutableArrayRef<uint8_t>(Data, Size));
Zachary Turnerd218c262016-07-22 15:46:37 +0000114
115 StreamWriter ModiWriter(ModInfoBuffer);
116 for (const auto &M : ModuleInfoList) {
Zachary Turnerb383d622016-07-22 15:46:46 +0000117 ModuleInfoHeader Layout = {};
118 Layout.ModDiStream = kInvalidStreamIndex;
Zachary Turnerd218c262016-07-22 15:46:37 +0000119 Layout.NumFiles = M->SourceFiles.size();
120 if (auto EC = ModiWriter.writeObject(Layout))
121 return EC;
122 if (auto EC = ModiWriter.writeZeroString(M->Mod))
123 return EC;
124 if (auto EC = ModiWriter.writeZeroString(M->Obj))
125 return EC;
126 }
127 if (ModiWriter.bytesRemaining() != 0)
128 return make_error<RawError>(raw_error_code::invalid_format,
129 "Unexpected bytes in Modi Stream Data");
130 return Error::success();
131}
132
133Error DbiStreamBuilder::generateFileInfoSubstream() {
134 uint32_t Size = calculateFileInfoSubstreamSize();
135 uint32_t NameSize = calculateNamesBufferSize();
136 auto Data = Allocator.Allocate<uint8_t>(Size);
137 uint32_t NamesOffset = Size - NameSize;
138
Zachary Turnerd66889c2016-07-28 19:12:28 +0000139 FileInfoBuffer = MutableByteStream(MutableArrayRef<uint8_t>(Data, Size));
Zachary Turnerd218c262016-07-22 15:46:37 +0000140
Zachary Turnerd66889c2016-07-28 19:12:28 +0000141 WritableStreamRef MetadataBuffer =
142 WritableStreamRef(FileInfoBuffer).keep_front(NamesOffset);
Zachary Turnerd218c262016-07-22 15:46:37 +0000143 StreamWriter MetadataWriter(MetadataBuffer);
144
145 uint16_t ModiCount = std::min<uint16_t>(UINT16_MAX, ModuleInfos.size());
146 uint16_t FileCount = std::min<uint16_t>(UINT16_MAX, SourceFileNames.size());
147 if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules
148 return EC;
149 if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles
150 return EC;
151 for (uint16_t I = 0; I < ModiCount; ++I) {
152 if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices
153 return EC;
154 }
155 for (const auto MI : ModuleInfoList) {
156 FileCount = static_cast<uint16_t>(MI->SourceFiles.size());
157 if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts
158 return EC;
159 }
160
161 // Before writing the FileNameOffsets array, write the NamesBuffer array.
162 // A side effect of this is that this will actually compute the various
163 // file name offsets, so we can then go back and write the FileNameOffsets
164 // array to the other substream.
Zachary Turnerd66889c2016-07-28 19:12:28 +0000165 NamesBuffer = WritableStreamRef(FileInfoBuffer).drop_front(NamesOffset);
Zachary Turnerd218c262016-07-22 15:46:37 +0000166 StreamWriter NameBufferWriter(NamesBuffer);
167 for (auto &Name : SourceFileNames) {
168 Name.second = NameBufferWriter.getOffset();
169 if (auto EC = NameBufferWriter.writeZeroString(Name.getKey()))
170 return EC;
171 }
172
173 for (const auto MI : ModuleInfoList) {
174 for (StringRef Name : MI->SourceFiles) {
175 auto Result = SourceFileNames.find(Name);
176 if (Result == SourceFileNames.end())
177 return make_error<RawError>(raw_error_code::no_entry,
178 "The source file was not found.");
179 if (auto EC = MetadataWriter.writeInteger(Result->second))
180 return EC;
181 }
182 }
183
184 if (NameBufferWriter.bytesRemaining() > 0)
185 return make_error<RawError>(raw_error_code::invalid_format,
186 "The names buffer contained unexpected data.");
187
188 if (MetadataWriter.bytesRemaining() > 0)
189 return make_error<RawError>(
190 raw_error_code::invalid_format,
191 "The metadata buffer contained unexpected data.");
192
193 return Error::success();
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000194}
195
Zachary Turnerd66889c2016-07-28 19:12:28 +0000196Error DbiStreamBuilder::finalize() {
197 if (Header)
198 return Error::success();
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000199
Zachary Turnerd66889c2016-07-28 19:12:28 +0000200 DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>();
Zachary Turnerd218c262016-07-22 15:46:37 +0000201
202 if (auto EC = generateModiSubstream())
Zachary Turnere98137c2016-07-28 19:18:02 +0000203 return EC;
Zachary Turnerd218c262016-07-22 15:46:37 +0000204 if (auto EC = generateFileInfoSubstream())
Zachary Turnere98137c2016-07-28 19:18:02 +0000205 return EC;
Zachary Turnerd218c262016-07-22 15:46:37 +0000206
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000207 H->VersionHeader = *VerHeader;
208 H->VersionSignature = -1;
209 H->Age = Age;
210 H->BuildNumber = BuildNumber;
211 H->Flags = Flags;
212 H->PdbDllRbld = PdbDllRbld;
213 H->PdbDllVersion = PdbDllVersion;
214 H->MachineType = static_cast<uint16_t>(MachineType);
215
216 H->ECSubstreamSize = 0;
Zachary Turnerd218c262016-07-22 15:46:37 +0000217 H->FileInfoSize = FileInfoBuffer.getLength();
218 H->ModiSubstreamSize = ModInfoBuffer.getLength();
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000219 H->OptionalDbgHdrSize = 0;
220 H->SecContrSubstreamSize = 0;
221 H->SectionMapSize = 0;
222 H->TypeServerSize = 0;
Zachary Turnerb383d622016-07-22 15:46:46 +0000223 H->SymRecordStreamIndex = kInvalidStreamIndex;
224 H->PublicSymbolStreamIndex = kInvalidStreamIndex;
225 H->MFCTypeServerIndex = kInvalidStreamIndex;
226 H->GlobalSymbolStreamIndex = kInvalidStreamIndex;
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000227
Zachary Turnerd66889c2016-07-28 19:12:28 +0000228 Header = H;
229 return Error::success();
230}
231
Zachary Turner620961d2016-09-14 23:00:02 +0000232Error DbiStreamBuilder::finalizeMsfLayout() {
233 uint32_t Length = calculateSerializedLength();
234 if (auto EC = Msf.setStreamSize(StreamDBI, Length))
235 return EC;
236 return Error::success();
237}
238
Zachary Turnerd66889c2016-07-28 19:12:28 +0000239Expected<std::unique_ptr<DbiStream>>
240DbiStreamBuilder::build(PDBFile &File, const msf::WritableStream &Buffer) {
241 if (!VerHeader.hasValue())
242 return make_error<RawError>(raw_error_code::unspecified,
243 "Missing DBI Stream Version");
244 if (auto EC = finalize())
245 return std::move(EC);
246
247 auto StreamData = MappedBlockStream::createIndexedStream(File.getMsfLayout(),
248 Buffer, StreamDBI);
249 auto Dbi = llvm::make_unique<DbiStream>(File, std::move(StreamData));
250 Dbi->Header = Header;
251 Dbi->FileInfoSubstream = ReadableStreamRef(FileInfoBuffer);
252 Dbi->ModInfoSubstream = ReadableStreamRef(ModInfoBuffer);
Zachary Turnerd218c262016-07-22 15:46:37 +0000253 if (auto EC = Dbi->initializeModInfoArray())
254 return std::move(EC);
255 if (auto EC = Dbi->initializeFileInfo())
256 return std::move(EC);
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000257 return std::move(Dbi);
258}
Zachary Turnerd66889c2016-07-28 19:12:28 +0000259
Zachary Turnera3225b02016-07-29 20:56:36 +0000260Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
Rui Ueyamad1d8c8312016-08-03 23:43:23 +0000261 const msf::WritableStream &Buffer) {
262 if (auto EC = finalize())
263 return EC;
264
Zachary Turnerd66889c2016-07-28 19:12:28 +0000265 auto InfoS =
266 WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamDBI);
267
268 StreamWriter Writer(*InfoS);
269 if (auto EC = Writer.writeObject(*Header))
270 return EC;
271
272 if (auto EC = Writer.writeStreamRef(ModInfoBuffer))
273 return EC;
274 if (auto EC = Writer.writeStreamRef(FileInfoBuffer))
275 return EC;
276
277 if (Writer.bytesRemaining() > 0)
278 return make_error<RawError>(raw_error_code::invalid_format,
279 "Unexpected bytes found in DBI Stream");
280 return Error::success();
281}