blob: b0bb4a0e1646a6d83db9217cd70496b70f23416b [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 Turnera3225b02016-07-29 20:56:36 +000012#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
13#include "llvm/DebugInfo/MSF/StreamWriter.h"
Zachary Turnerdbeaea72016-07-11 21:45:26 +000014#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
Zachary Turnerdbeaea72016-07-11 21:45:26 +000015#include "llvm/DebugInfo/PDB/Raw/RawError.h"
16
17using namespace llvm;
18using namespace llvm::codeview;
Zachary Turnerbac69d32016-07-22 19:56:05 +000019using namespace llvm::msf;
Zachary Turnerdbeaea72016-07-11 21:45:26 +000020using namespace llvm::pdb;
21
Zachary Turnerd218c262016-07-22 15:46:37 +000022namespace {
23class ModiSubstreamBuilder {};
24}
25
26DbiStreamBuilder::DbiStreamBuilder(BumpPtrAllocator &Allocator)
27 : Allocator(Allocator), Age(1), BuildNumber(0), PdbDllVersion(0),
Zachary Turnerd66889c2016-07-28 19:12:28 +000028 PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86), Header(nullptr) {}
Zachary Turnerdbeaea72016-07-11 21:45:26 +000029
30void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; }
31
32void DbiStreamBuilder::setAge(uint32_t A) { Age = A; }
33
34void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; }
35
36void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; }
37
38void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; }
39
40void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; }
41
42void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; }
43
Zachary Turnerfaa554b2016-07-15 22:16:56 +000044uint32_t DbiStreamBuilder::calculateSerializedLength() const {
45 // For now we only support serializing the header.
Zachary Turnerb383d622016-07-22 15:46:46 +000046 return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() +
Zachary Turnerd218c262016-07-22 15:46:37 +000047 calculateModiSubstreamSize();
48}
49
50Error DbiStreamBuilder::addModuleInfo(StringRef ObjFile, StringRef Module) {
51 auto Entry = llvm::make_unique<ModuleInfo>();
52 ModuleInfo *M = Entry.get();
53 Entry->Mod = Module;
54 Entry->Obj = ObjFile;
55 auto Result = ModuleInfos.insert(std::make_pair(Module, std::move(Entry)));
56 if (!Result.second)
57 return make_error<RawError>(raw_error_code::duplicate_entry,
58 "The specified module already exists");
59 ModuleInfoList.push_back(M);
60 return Error::success();
61}
62
63Error DbiStreamBuilder::addModuleSourceFile(StringRef Module, StringRef File) {
64 auto ModIter = ModuleInfos.find(Module);
65 if (ModIter == ModuleInfos.end())
66 return make_error<RawError>(raw_error_code::no_entry,
67 "The specified module was not found");
68 uint32_t Index = SourceFileNames.size();
69 SourceFileNames.insert(std::make_pair(File, Index));
70 auto &ModEntry = *ModIter;
71 ModEntry.second->SourceFiles.push_back(File);
72 return Error::success();
73}
74
75uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const {
76 uint32_t Size = 0;
77 for (const auto &M : ModuleInfoList) {
Zachary Turnerb383d622016-07-22 15:46:46 +000078 Size += sizeof(ModuleInfoHeader);
Zachary Turnerd218c262016-07-22 15:46:37 +000079 Size += M->Mod.size() + 1;
80 Size += M->Obj.size() + 1;
81 }
82 return Size;
83}
84
85uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const {
Zachary Turnerd218c262016-07-22 15:46:37 +000086 uint32_t Size = 0;
87 Size += sizeof(ulittle16_t); // NumModules
88 Size += sizeof(ulittle16_t); // NumSourceFiles
89 Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModIndices
90 Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModFileCounts
91 uint32_t NumFileInfos = 0;
92 for (const auto &M : ModuleInfoList)
93 NumFileInfos += M->SourceFiles.size();
94 Size += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets
95 Size += calculateNamesBufferSize();
96 return Size;
97}
98
99uint32_t DbiStreamBuilder::calculateNamesBufferSize() const {
100 uint32_t Size = 0;
101 for (const auto &F : SourceFileNames) {
102 Size += F.getKeyLength() + 1; // Names[I];
103 }
104 return Size;
105}
106
107Error DbiStreamBuilder::generateModiSubstream() {
108 uint32_t Size = calculateModiSubstreamSize();
109 auto Data = Allocator.Allocate<uint8_t>(Size);
110
Zachary Turnerd66889c2016-07-28 19:12:28 +0000111 ModInfoBuffer = MutableByteStream(MutableArrayRef<uint8_t>(Data, Size));
Zachary Turnerd218c262016-07-22 15:46:37 +0000112
113 StreamWriter ModiWriter(ModInfoBuffer);
114 for (const auto &M : ModuleInfoList) {
Zachary Turnerb383d622016-07-22 15:46:46 +0000115 ModuleInfoHeader Layout = {};
116 Layout.ModDiStream = kInvalidStreamIndex;
Zachary Turnerd218c262016-07-22 15:46:37 +0000117 Layout.NumFiles = M->SourceFiles.size();
118 if (auto EC = ModiWriter.writeObject(Layout))
119 return EC;
120 if (auto EC = ModiWriter.writeZeroString(M->Mod))
121 return EC;
122 if (auto EC = ModiWriter.writeZeroString(M->Obj))
123 return EC;
124 }
125 if (ModiWriter.bytesRemaining() != 0)
126 return make_error<RawError>(raw_error_code::invalid_format,
127 "Unexpected bytes in Modi Stream Data");
128 return Error::success();
129}
130
131Error DbiStreamBuilder::generateFileInfoSubstream() {
132 uint32_t Size = calculateFileInfoSubstreamSize();
133 uint32_t NameSize = calculateNamesBufferSize();
134 auto Data = Allocator.Allocate<uint8_t>(Size);
135 uint32_t NamesOffset = Size - NameSize;
136
Zachary Turnerd66889c2016-07-28 19:12:28 +0000137 FileInfoBuffer = MutableByteStream(MutableArrayRef<uint8_t>(Data, Size));
Zachary Turnerd218c262016-07-22 15:46:37 +0000138
Zachary Turnerd66889c2016-07-28 19:12:28 +0000139 WritableStreamRef MetadataBuffer =
140 WritableStreamRef(FileInfoBuffer).keep_front(NamesOffset);
Zachary Turnerd218c262016-07-22 15:46:37 +0000141 StreamWriter MetadataWriter(MetadataBuffer);
142
143 uint16_t ModiCount = std::min<uint16_t>(UINT16_MAX, ModuleInfos.size());
144 uint16_t FileCount = std::min<uint16_t>(UINT16_MAX, SourceFileNames.size());
145 if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules
146 return EC;
147 if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles
148 return EC;
149 for (uint16_t I = 0; I < ModiCount; ++I) {
150 if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices
151 return EC;
152 }
153 for (const auto MI : ModuleInfoList) {
154 FileCount = static_cast<uint16_t>(MI->SourceFiles.size());
155 if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts
156 return EC;
157 }
158
159 // Before writing the FileNameOffsets array, write the NamesBuffer array.
160 // A side effect of this is that this will actually compute the various
161 // file name offsets, so we can then go back and write the FileNameOffsets
162 // array to the other substream.
Zachary Turnerd66889c2016-07-28 19:12:28 +0000163 NamesBuffer = WritableStreamRef(FileInfoBuffer).drop_front(NamesOffset);
Zachary Turnerd218c262016-07-22 15:46:37 +0000164 StreamWriter NameBufferWriter(NamesBuffer);
165 for (auto &Name : SourceFileNames) {
166 Name.second = NameBufferWriter.getOffset();
167 if (auto EC = NameBufferWriter.writeZeroString(Name.getKey()))
168 return EC;
169 }
170
171 for (const auto MI : ModuleInfoList) {
172 for (StringRef Name : MI->SourceFiles) {
173 auto Result = SourceFileNames.find(Name);
174 if (Result == SourceFileNames.end())
175 return make_error<RawError>(raw_error_code::no_entry,
176 "The source file was not found.");
177 if (auto EC = MetadataWriter.writeInteger(Result->second))
178 return EC;
179 }
180 }
181
182 if (NameBufferWriter.bytesRemaining() > 0)
183 return make_error<RawError>(raw_error_code::invalid_format,
184 "The names buffer contained unexpected data.");
185
186 if (MetadataWriter.bytesRemaining() > 0)
187 return make_error<RawError>(
188 raw_error_code::invalid_format,
189 "The metadata buffer contained unexpected data.");
190
191 return Error::success();
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000192}
193
Zachary Turnerd66889c2016-07-28 19:12:28 +0000194Error DbiStreamBuilder::finalize() {
195 if (Header)
196 return Error::success();
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000197
Zachary Turnerd66889c2016-07-28 19:12:28 +0000198 DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>();
Zachary Turnerd218c262016-07-22 15:46:37 +0000199
200 if (auto EC = generateModiSubstream())
Zachary Turnere98137c2016-07-28 19:18:02 +0000201 return EC;
Zachary Turnerd218c262016-07-22 15:46:37 +0000202 if (auto EC = generateFileInfoSubstream())
Zachary Turnere98137c2016-07-28 19:18:02 +0000203 return EC;
Zachary Turnerd218c262016-07-22 15:46:37 +0000204
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000205 H->VersionHeader = *VerHeader;
206 H->VersionSignature = -1;
207 H->Age = Age;
208 H->BuildNumber = BuildNumber;
209 H->Flags = Flags;
210 H->PdbDllRbld = PdbDllRbld;
211 H->PdbDllVersion = PdbDllVersion;
212 H->MachineType = static_cast<uint16_t>(MachineType);
213
214 H->ECSubstreamSize = 0;
Zachary Turnerd218c262016-07-22 15:46:37 +0000215 H->FileInfoSize = FileInfoBuffer.getLength();
216 H->ModiSubstreamSize = ModInfoBuffer.getLength();
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000217 H->OptionalDbgHdrSize = 0;
218 H->SecContrSubstreamSize = 0;
219 H->SectionMapSize = 0;
220 H->TypeServerSize = 0;
Zachary Turnerb383d622016-07-22 15:46:46 +0000221 H->SymRecordStreamIndex = kInvalidStreamIndex;
222 H->PublicSymbolStreamIndex = kInvalidStreamIndex;
223 H->MFCTypeServerIndex = kInvalidStreamIndex;
224 H->GlobalSymbolStreamIndex = kInvalidStreamIndex;
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000225
Zachary Turnerd66889c2016-07-28 19:12:28 +0000226 Header = H;
227 return Error::success();
228}
229
230Expected<std::unique_ptr<DbiStream>>
231DbiStreamBuilder::build(PDBFile &File, const msf::WritableStream &Buffer) {
232 if (!VerHeader.hasValue())
233 return make_error<RawError>(raw_error_code::unspecified,
234 "Missing DBI Stream Version");
235 if (auto EC = finalize())
236 return std::move(EC);
237
238 auto StreamData = MappedBlockStream::createIndexedStream(File.getMsfLayout(),
239 Buffer, StreamDBI);
240 auto Dbi = llvm::make_unique<DbiStream>(File, std::move(StreamData));
241 Dbi->Header = Header;
242 Dbi->FileInfoSubstream = ReadableStreamRef(FileInfoBuffer);
243 Dbi->ModInfoSubstream = ReadableStreamRef(ModInfoBuffer);
Zachary Turnerd218c262016-07-22 15:46:37 +0000244 if (auto EC = Dbi->initializeModInfoArray())
245 return std::move(EC);
246 if (auto EC = Dbi->initializeFileInfo())
247 return std::move(EC);
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000248 return std::move(Dbi);
249}
Zachary Turnerd66889c2016-07-28 19:12:28 +0000250
Zachary Turnera3225b02016-07-29 20:56:36 +0000251Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
Rui Ueyamad1d8c8312016-08-03 23:43:23 +0000252 const msf::WritableStream &Buffer) {
253 if (auto EC = finalize())
254 return EC;
255
Zachary Turnerd66889c2016-07-28 19:12:28 +0000256 auto InfoS =
257 WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamDBI);
258
259 StreamWriter Writer(*InfoS);
260 if (auto EC = Writer.writeObject(*Header))
261 return EC;
262
263 if (auto EC = Writer.writeStreamRef(ModInfoBuffer))
264 return EC;
265 if (auto EC = Writer.writeStreamRef(FileInfoBuffer))
266 return EC;
267
268 if (Writer.bytesRemaining() > 0)
269 return make_error<RawError>(raw_error_code::invalid_format,
270 "Unexpected bytes found in DBI Stream");
271 return Error::success();
272}