blob: 751f869c52a054ff5cb436c6442ef2070aa3444d [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
12#include "llvm/DebugInfo/CodeView/StreamWriter.h"
13#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
14#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
15#include "llvm/DebugInfo/PDB/Raw/RawError.h"
16
17using namespace llvm;
18using namespace llvm::codeview;
19using namespace llvm::pdb;
20
Zachary Turnerd218c262016-07-22 15:46:37 +000021namespace {
22class ModiSubstreamBuilder {};
23}
24
25DbiStreamBuilder::DbiStreamBuilder(BumpPtrAllocator &Allocator)
26 : Allocator(Allocator), Age(1), BuildNumber(0), PdbDllVersion(0),
27 PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86) {}
Zachary Turnerdbeaea72016-07-11 21:45:26 +000028
29void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; }
30
31void DbiStreamBuilder::setAge(uint32_t A) { Age = A; }
32
33void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; }
34
35void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; }
36
37void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; }
38
39void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; }
40
41void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; }
42
Zachary Turnerfaa554b2016-07-15 22:16:56 +000043uint32_t DbiStreamBuilder::calculateSerializedLength() const {
44 // For now we only support serializing the header.
Zachary Turnerb383d622016-07-22 15:46:46 +000045 return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() +
Zachary Turnerd218c262016-07-22 15:46:37 +000046 calculateModiSubstreamSize();
47}
48
49Error DbiStreamBuilder::addModuleInfo(StringRef ObjFile, StringRef Module) {
50 auto Entry = llvm::make_unique<ModuleInfo>();
51 ModuleInfo *M = Entry.get();
52 Entry->Mod = Module;
53 Entry->Obj = ObjFile;
54 auto Result = ModuleInfos.insert(std::make_pair(Module, std::move(Entry)));
55 if (!Result.second)
56 return make_error<RawError>(raw_error_code::duplicate_entry,
57 "The specified module already exists");
58 ModuleInfoList.push_back(M);
59 return Error::success();
60}
61
62Error DbiStreamBuilder::addModuleSourceFile(StringRef Module, StringRef File) {
63 auto ModIter = ModuleInfos.find(Module);
64 if (ModIter == ModuleInfos.end())
65 return make_error<RawError>(raw_error_code::no_entry,
66 "The specified module was not found");
67 uint32_t Index = SourceFileNames.size();
68 SourceFileNames.insert(std::make_pair(File, Index));
69 auto &ModEntry = *ModIter;
70 ModEntry.second->SourceFiles.push_back(File);
71 return Error::success();
72}
73
74uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const {
75 uint32_t Size = 0;
76 for (const auto &M : ModuleInfoList) {
Zachary Turnerb383d622016-07-22 15:46:46 +000077 Size += sizeof(ModuleInfoHeader);
Zachary Turnerd218c262016-07-22 15:46:37 +000078 Size += M->Mod.size() + 1;
79 Size += M->Obj.size() + 1;
80 }
81 return Size;
82}
83
84uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const {
Zachary Turnerd218c262016-07-22 15:46:37 +000085 uint32_t Size = 0;
86 Size += sizeof(ulittle16_t); // NumModules
87 Size += sizeof(ulittle16_t); // NumSourceFiles
88 Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModIndices
89 Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModFileCounts
90 uint32_t NumFileInfos = 0;
91 for (const auto &M : ModuleInfoList)
92 NumFileInfos += M->SourceFiles.size();
93 Size += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets
94 Size += calculateNamesBufferSize();
95 return Size;
96}
97
98uint32_t DbiStreamBuilder::calculateNamesBufferSize() const {
99 uint32_t Size = 0;
100 for (const auto &F : SourceFileNames) {
101 Size += F.getKeyLength() + 1; // Names[I];
102 }
103 return Size;
104}
105
106Error DbiStreamBuilder::generateModiSubstream() {
107 uint32_t Size = calculateModiSubstreamSize();
108 auto Data = Allocator.Allocate<uint8_t>(Size);
109
110 ModInfoBuffer = ByteStream<true>(MutableArrayRef<uint8_t>(Data, Size));
111
112 StreamWriter ModiWriter(ModInfoBuffer);
113 for (const auto &M : ModuleInfoList) {
Zachary Turnerb383d622016-07-22 15:46:46 +0000114 ModuleInfoHeader Layout = {};
115 Layout.ModDiStream = kInvalidStreamIndex;
Zachary Turnerd218c262016-07-22 15:46:37 +0000116 Layout.NumFiles = M->SourceFiles.size();
117 if (auto EC = ModiWriter.writeObject(Layout))
118 return EC;
119 if (auto EC = ModiWriter.writeZeroString(M->Mod))
120 return EC;
121 if (auto EC = ModiWriter.writeZeroString(M->Obj))
122 return EC;
123 }
124 if (ModiWriter.bytesRemaining() != 0)
125 return make_error<RawError>(raw_error_code::invalid_format,
126 "Unexpected bytes in Modi Stream Data");
127 return Error::success();
128}
129
130Error DbiStreamBuilder::generateFileInfoSubstream() {
131 uint32_t Size = calculateFileInfoSubstreamSize();
132 uint32_t NameSize = calculateNamesBufferSize();
133 auto Data = Allocator.Allocate<uint8_t>(Size);
134 uint32_t NamesOffset = Size - NameSize;
135
136 FileInfoBuffer = ByteStream<true>(MutableArrayRef<uint8_t>(Data, Size));
137
138 StreamRef MetadataBuffer = StreamRef(FileInfoBuffer).keep_front(NamesOffset);
139 StreamWriter MetadataWriter(MetadataBuffer);
140
141 uint16_t ModiCount = std::min<uint16_t>(UINT16_MAX, ModuleInfos.size());
142 uint16_t FileCount = std::min<uint16_t>(UINT16_MAX, SourceFileNames.size());
143 if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules
144 return EC;
145 if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles
146 return EC;
147 for (uint16_t I = 0; I < ModiCount; ++I) {
148 if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices
149 return EC;
150 }
151 for (const auto MI : ModuleInfoList) {
152 FileCount = static_cast<uint16_t>(MI->SourceFiles.size());
153 if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts
154 return EC;
155 }
156
157 // Before writing the FileNameOffsets array, write the NamesBuffer array.
158 // A side effect of this is that this will actually compute the various
159 // file name offsets, so we can then go back and write the FileNameOffsets
160 // array to the other substream.
161 NamesBuffer = StreamRef(FileInfoBuffer).drop_front(NamesOffset);
162 StreamWriter NameBufferWriter(NamesBuffer);
163 for (auto &Name : SourceFileNames) {
164 Name.second = NameBufferWriter.getOffset();
165 if (auto EC = NameBufferWriter.writeZeroString(Name.getKey()))
166 return EC;
167 }
168
169 for (const auto MI : ModuleInfoList) {
170 for (StringRef Name : MI->SourceFiles) {
171 auto Result = SourceFileNames.find(Name);
172 if (Result == SourceFileNames.end())
173 return make_error<RawError>(raw_error_code::no_entry,
174 "The source file was not found.");
175 if (auto EC = MetadataWriter.writeInteger(Result->second))
176 return EC;
177 }
178 }
179
180 if (NameBufferWriter.bytesRemaining() > 0)
181 return make_error<RawError>(raw_error_code::invalid_format,
182 "The names buffer contained unexpected data.");
183
184 if (MetadataWriter.bytesRemaining() > 0)
185 return make_error<RawError>(
186 raw_error_code::invalid_format,
187 "The metadata buffer contained unexpected data.");
188
189 return Error::success();
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000190}
191
192Expected<std::unique_ptr<DbiStream>> DbiStreamBuilder::build(PDBFile &File) {
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000193 if (!VerHeader.hasValue())
194 return make_error<RawError>(raw_error_code::unspecified,
195 "Missing DBI Stream Version");
196
197 auto DbiS = MappedBlockStream::createIndexedStream(StreamDBI, File);
198 if (!DbiS)
199 return DbiS.takeError();
200 auto DS = std::move(*DbiS);
Zachary Turnerb383d622016-07-22 15:46:46 +0000201 DbiStreamHeader *H = DS->getAllocator().Allocate<DbiStreamHeader>(1);
Zachary Turnerd218c262016-07-22 15:46:37 +0000202
203 if (auto EC = generateModiSubstream())
204 return std::move(EC);
205 if (auto EC = generateFileInfoSubstream())
206 return std::move(EC);
207
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000208 H->VersionHeader = *VerHeader;
209 H->VersionSignature = -1;
210 H->Age = Age;
211 H->BuildNumber = BuildNumber;
212 H->Flags = Flags;
213 H->PdbDllRbld = PdbDllRbld;
214 H->PdbDllVersion = PdbDllVersion;
215 H->MachineType = static_cast<uint16_t>(MachineType);
216
217 H->ECSubstreamSize = 0;
Zachary Turnerd218c262016-07-22 15:46:37 +0000218 H->FileInfoSize = FileInfoBuffer.getLength();
219 H->ModiSubstreamSize = ModInfoBuffer.getLength();
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000220 H->OptionalDbgHdrSize = 0;
221 H->SecContrSubstreamSize = 0;
222 H->SectionMapSize = 0;
223 H->TypeServerSize = 0;
Zachary Turnerb383d622016-07-22 15:46:46 +0000224 H->SymRecordStreamIndex = kInvalidStreamIndex;
225 H->PublicSymbolStreamIndex = kInvalidStreamIndex;
226 H->MFCTypeServerIndex = kInvalidStreamIndex;
227 H->GlobalSymbolStreamIndex = kInvalidStreamIndex;
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000228
229 auto Dbi = llvm::make_unique<DbiStream>(File, std::move(DS));
230 Dbi->Header = H;
Zachary Turnerd218c262016-07-22 15:46:37 +0000231 Dbi->FileInfoSubstream = StreamRef(FileInfoBuffer);
232 Dbi->ModInfoSubstream = StreamRef(ModInfoBuffer);
233 if (auto EC = Dbi->initializeModInfoArray())
234 return std::move(EC);
235 if (auto EC = Dbi->initializeFileInfo())
236 return std::move(EC);
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000237 return std::move(Dbi);
238}