blob: bbb0876380db8ebb1bebaa7b339551e10977622d [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 Turnerd218c262016-07-22 15:46:37 +000045 return sizeof(DbiStream::HeaderInfo) + calculateFileInfoSubstreamSize() +
46 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) {
77 Size += sizeof(ModInfo::FileLayout);
78 Size += M->Mod.size() + 1;
79 Size += M->Obj.size() + 1;
80 }
81 return Size;
82}
83
84uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const {
85 // ulittle16_t NumModules;
86 // ulittle16_t NumSourceFiles;
87 // ulittle16_t ModIndices[NumModules];
88 // ulittle16_t ModFileCounts[NumModules];
89 // ulittle32_t FileNameOffsets[NumSourceFiles];
90 // char Names[NumSourceFiles][];
91 uint32_t Size = 0;
92 Size += sizeof(ulittle16_t); // NumModules
93 Size += sizeof(ulittle16_t); // NumSourceFiles
94 Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModIndices
95 Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModFileCounts
96 uint32_t NumFileInfos = 0;
97 for (const auto &M : ModuleInfoList)
98 NumFileInfos += M->SourceFiles.size();
99 Size += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets
100 Size += calculateNamesBufferSize();
101 return Size;
102}
103
104uint32_t DbiStreamBuilder::calculateNamesBufferSize() const {
105 uint32_t Size = 0;
106 for (const auto &F : SourceFileNames) {
107 Size += F.getKeyLength() + 1; // Names[I];
108 }
109 return Size;
110}
111
112Error DbiStreamBuilder::generateModiSubstream() {
113 uint32_t Size = calculateModiSubstreamSize();
114 auto Data = Allocator.Allocate<uint8_t>(Size);
115
116 ModInfoBuffer = ByteStream<true>(MutableArrayRef<uint8_t>(Data, Size));
117
118 StreamWriter ModiWriter(ModInfoBuffer);
119 for (const auto &M : ModuleInfoList) {
120 ModInfo::FileLayout Layout = {};
121 Layout.ModDiStream = DbiStream::InvalidStreamIndex;
122 Layout.NumFiles = M->SourceFiles.size();
123 if (auto EC = ModiWriter.writeObject(Layout))
124 return EC;
125 if (auto EC = ModiWriter.writeZeroString(M->Mod))
126 return EC;
127 if (auto EC = ModiWriter.writeZeroString(M->Obj))
128 return EC;
129 }
130 if (ModiWriter.bytesRemaining() != 0)
131 return make_error<RawError>(raw_error_code::invalid_format,
132 "Unexpected bytes in Modi Stream Data");
133 return Error::success();
134}
135
136Error DbiStreamBuilder::generateFileInfoSubstream() {
137 uint32_t Size = calculateFileInfoSubstreamSize();
138 uint32_t NameSize = calculateNamesBufferSize();
139 auto Data = Allocator.Allocate<uint8_t>(Size);
140 uint32_t NamesOffset = Size - NameSize;
141
142 FileInfoBuffer = ByteStream<true>(MutableArrayRef<uint8_t>(Data, Size));
143
144 StreamRef MetadataBuffer = StreamRef(FileInfoBuffer).keep_front(NamesOffset);
145 StreamWriter MetadataWriter(MetadataBuffer);
146
147 uint16_t ModiCount = std::min<uint16_t>(UINT16_MAX, ModuleInfos.size());
148 uint16_t FileCount = std::min<uint16_t>(UINT16_MAX, SourceFileNames.size());
149 if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules
150 return EC;
151 if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles
152 return EC;
153 for (uint16_t I = 0; I < ModiCount; ++I) {
154 if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices
155 return EC;
156 }
157 for (const auto MI : ModuleInfoList) {
158 FileCount = static_cast<uint16_t>(MI->SourceFiles.size());
159 if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts
160 return EC;
161 }
162
163 // Before writing the FileNameOffsets array, write the NamesBuffer array.
164 // A side effect of this is that this will actually compute the various
165 // file name offsets, so we can then go back and write the FileNameOffsets
166 // array to the other substream.
167 NamesBuffer = StreamRef(FileInfoBuffer).drop_front(NamesOffset);
168 StreamWriter NameBufferWriter(NamesBuffer);
169 for (auto &Name : SourceFileNames) {
170 Name.second = NameBufferWriter.getOffset();
171 if (auto EC = NameBufferWriter.writeZeroString(Name.getKey()))
172 return EC;
173 }
174
175 for (const auto MI : ModuleInfoList) {
176 for (StringRef Name : MI->SourceFiles) {
177 auto Result = SourceFileNames.find(Name);
178 if (Result == SourceFileNames.end())
179 return make_error<RawError>(raw_error_code::no_entry,
180 "The source file was not found.");
181 if (auto EC = MetadataWriter.writeInteger(Result->second))
182 return EC;
183 }
184 }
185
186 if (NameBufferWriter.bytesRemaining() > 0)
187 return make_error<RawError>(raw_error_code::invalid_format,
188 "The names buffer contained unexpected data.");
189
190 if (MetadataWriter.bytesRemaining() > 0)
191 return make_error<RawError>(
192 raw_error_code::invalid_format,
193 "The metadata buffer contained unexpected data.");
194
195 return Error::success();
Zachary Turnerfaa554b2016-07-15 22:16:56 +0000196}
197
198Expected<std::unique_ptr<DbiStream>> DbiStreamBuilder::build(PDBFile &File) {
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000199 if (!VerHeader.hasValue())
200 return make_error<RawError>(raw_error_code::unspecified,
201 "Missing DBI Stream Version");
202
203 auto DbiS = MappedBlockStream::createIndexedStream(StreamDBI, File);
204 if (!DbiS)
205 return DbiS.takeError();
206 auto DS = std::move(*DbiS);
207 DbiStream::HeaderInfo *H =
208 static_cast<DbiStream::HeaderInfo *>(DS->getAllocator().Allocate(
209 sizeof(DbiStream::HeaderInfo),
210 llvm::AlignOf<DbiStream::HeaderInfo>::Alignment));
Zachary Turnerd218c262016-07-22 15:46:37 +0000211
212 if (auto EC = generateModiSubstream())
213 return std::move(EC);
214 if (auto EC = generateFileInfoSubstream())
215 return std::move(EC);
216
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000217 H->VersionHeader = *VerHeader;
218 H->VersionSignature = -1;
219 H->Age = Age;
220 H->BuildNumber = BuildNumber;
221 H->Flags = Flags;
222 H->PdbDllRbld = PdbDllRbld;
223 H->PdbDllVersion = PdbDllVersion;
224 H->MachineType = static_cast<uint16_t>(MachineType);
225
226 H->ECSubstreamSize = 0;
Zachary Turnerd218c262016-07-22 15:46:37 +0000227 H->FileInfoSize = FileInfoBuffer.getLength();
228 H->ModiSubstreamSize = ModInfoBuffer.getLength();
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000229 H->OptionalDbgHdrSize = 0;
230 H->SecContrSubstreamSize = 0;
231 H->SectionMapSize = 0;
232 H->TypeServerSize = 0;
233 H->SymRecordStreamIndex = DbiStream::InvalidStreamIndex;
234 H->PublicSymbolStreamIndex = DbiStream::InvalidStreamIndex;
235 H->MFCTypeServerIndex = DbiStream::InvalidStreamIndex;
236 H->GlobalSymbolStreamIndex = DbiStream::InvalidStreamIndex;
237
238 auto Dbi = llvm::make_unique<DbiStream>(File, std::move(DS));
239 Dbi->Header = H;
Zachary Turnerd218c262016-07-22 15:46:37 +0000240 Dbi->FileInfoSubstream = StreamRef(FileInfoBuffer);
241 Dbi->ModInfoSubstream = StreamRef(ModInfoBuffer);
242 if (auto EC = Dbi->initializeModInfoArray())
243 return std::move(EC);
244 if (auto EC = Dbi->initializeFileInfo())
245 return std::move(EC);
Zachary Turnerdbeaea72016-07-11 21:45:26 +0000246 return std::move(Dbi);
247}