Line data Source code
1 : //===- 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/ADT/ArrayRef.h"
13 : #include "llvm/DebugInfo/MSF/MSFBuilder.h"
14 : #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
15 : #include "llvm/DebugInfo/MSF/StreamWriter.h"
16 : #include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
17 : #include "llvm/DebugInfo/PDB/Raw/RawError.h"
18 : #include "llvm/Object/COFF.h"
19 : #include "llvm/Support/COFF.h"
20 :
21 : using namespace llvm;
22 : using namespace llvm::codeview;
23 : using namespace llvm::msf;
24 : using namespace llvm::pdb;
25 :
26 : namespace {
27 : class ModiSubstreamBuilder {};
28 : }
29 :
30 3 : DbiStreamBuilder::DbiStreamBuilder(msf::MSFBuilder &Msf)
31 3 : : Msf(Msf), Allocator(Msf.getAllocator()), Age(1), BuildNumber(0),
32 : PdbDllVersion(0), PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86),
33 39 : Header(nullptr), DbgStreams((int)DbgHeaderType::Max) {}
34 :
35 6 : void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; }
36 :
37 1 : void DbiStreamBuilder::setAge(uint32_t A) { Age = A; }
38 :
39 1 : void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; }
40 :
41 1 : void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; }
42 :
43 1 : void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; }
44 :
45 1 : void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; }
46 :
47 1 : void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; }
48 :
49 2 : void DbiStreamBuilder::setSectionContribs(ArrayRef<SectionContrib> Arr) {
50 2 : SectionContribs = Arr;
51 2 : }
52 :
53 2 : void DbiStreamBuilder::setSectionMap(ArrayRef<SecMapEntry> SecMap) {
54 2 : SectionMap = SecMap;
55 2 : }
56 :
57 2 : Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type,
58 : ArrayRef<uint8_t> Data) {
59 4 : if (DbgStreams[(int)Type].StreamNumber)
60 : return make_error<RawError>(raw_error_code::duplicate_entry,
61 0 : "The specified stream type already exists");
62 2 : auto ExpectedIndex = Msf.addStream(Data.size());
63 2 : if (!ExpectedIndex)
64 0 : return ExpectedIndex.takeError();
65 2 : uint32_t Index = std::move(*ExpectedIndex);
66 4 : DbgStreams[(int)Type].Data = Data;
67 4 : DbgStreams[(int)Type].StreamNumber = Index;
68 6 : return Error::success();
69 : }
70 :
71 3 : uint32_t DbiStreamBuilder::calculateSerializedLength() const {
72 : // For now we only support serializing the header.
73 6 : return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() +
74 9 : calculateModiSubstreamSize() + calculateSectionContribsStreamSize() +
75 6 : calculateSectionMapStreamSize() + calculateDbgStreamsSize();
76 : }
77 :
78 4 : Error DbiStreamBuilder::addModuleInfo(StringRef ObjFile, StringRef Module) {
79 8 : auto Entry = llvm::make_unique<ModuleInfo>();
80 4 : ModuleInfo *M = Entry.get();
81 4 : Entry->Mod = Module;
82 4 : Entry->Obj = ObjFile;
83 16 : auto Result = ModuleInfos.insert(std::make_pair(Module, std::move(Entry)));
84 4 : if (!Result.second)
85 : return make_error<RawError>(raw_error_code::duplicate_entry,
86 0 : "The specified module already exists");
87 4 : ModuleInfoList.push_back(M);
88 12 : return Error::success();
89 : }
90 :
91 1 : Error DbiStreamBuilder::addModuleSourceFile(StringRef Module, StringRef File) {
92 1 : auto ModIter = ModuleInfos.find(Module);
93 2 : if (ModIter == ModuleInfos.end())
94 : return make_error<RawError>(raw_error_code::no_entry,
95 0 : "The specified module was not found");
96 1 : uint32_t Index = SourceFileNames.size();
97 3 : SourceFileNames.insert(std::make_pair(File, Index));
98 1 : auto &ModEntry = *ModIter;
99 2 : ModEntry.second->SourceFiles.push_back(File);
100 3 : return Error::success();
101 : }
102 :
103 6 : uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const {
104 6 : uint32_t Size = 0;
105 32 : for (const auto &M : ModuleInfoList) {
106 8 : Size += sizeof(ModuleInfoHeader);
107 16 : Size += M->Mod.size() + 1;
108 16 : Size += M->Obj.size() + 1;
109 : }
110 12 : return alignTo(Size, sizeof(uint32_t));
111 : }
112 :
113 6 : uint32_t DbiStreamBuilder::calculateSectionContribsStreamSize() const {
114 6 : if (SectionContribs.empty())
115 : return 0;
116 4 : return sizeof(enum PdbRaw_DbiSecContribVer) +
117 8 : sizeof(SectionContribs[0]) * SectionContribs.size();
118 : }
119 :
120 6 : uint32_t DbiStreamBuilder::calculateSectionMapStreamSize() const {
121 6 : if (SectionMap.empty())
122 : return 0;
123 4 : return sizeof(SecMapHeader) + sizeof(SecMapEntry) * SectionMap.size();
124 : }
125 :
126 6 : uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const {
127 6 : uint32_t Size = 0;
128 6 : Size += sizeof(ulittle16_t); // NumModules
129 6 : Size += sizeof(ulittle16_t); // NumSourceFiles
130 12 : Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModIndices
131 6 : Size += ModuleInfoList.size() * sizeof(ulittle16_t); // ModFileCounts
132 6 : uint32_t NumFileInfos = 0;
133 32 : for (const auto &M : ModuleInfoList)
134 16 : NumFileInfos += M->SourceFiles.size();
135 6 : Size += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets
136 6 : Size += calculateNamesBufferSize();
137 12 : return alignTo(Size, sizeof(uint32_t));
138 : }
139 :
140 9 : uint32_t DbiStreamBuilder::calculateNamesBufferSize() const {
141 9 : uint32_t Size = 0;
142 30 : for (const auto &F : SourceFileNames) {
143 6 : Size += F.getKeyLength() + 1; // Names[I];
144 : }
145 9 : return Size;
146 : }
147 :
148 3 : uint32_t DbiStreamBuilder::calculateDbgStreamsSize() const {
149 6 : return DbgStreams.size() * sizeof(uint16_t);
150 : }
151 :
152 3 : Error DbiStreamBuilder::generateModiSubstream() {
153 3 : uint32_t Size = calculateModiSubstreamSize();
154 6 : auto Data = Allocator.Allocate<uint8_t>(Size);
155 :
156 15 : ModInfoBuffer = MutableByteStream(MutableArrayRef<uint8_t>(Data, Size));
157 :
158 6 : StreamWriter ModiWriter(ModInfoBuffer);
159 16 : for (const auto &M : ModuleInfoList) {
160 4 : ModuleInfoHeader Layout = {};
161 4 : Layout.ModDiStream = kInvalidStreamIndex;
162 12 : Layout.NumFiles = M->SourceFiles.size();
163 12 : if (auto EC = ModiWriter.writeObject(Layout))
164 0 : return EC;
165 12 : if (auto EC = ModiWriter.writeZeroString(M->Mod))
166 0 : return EC;
167 12 : if (auto EC = ModiWriter.writeZeroString(M->Obj))
168 0 : return EC;
169 : }
170 3 : if (ModiWriter.bytesRemaining() > sizeof(uint32_t))
171 : return make_error<RawError>(raw_error_code::invalid_format,
172 0 : "Unexpected bytes in Modi Stream Data");
173 9 : return Error::success();
174 : }
175 :
176 3 : Error DbiStreamBuilder::generateFileInfoSubstream() {
177 3 : uint32_t Size = calculateFileInfoSubstreamSize();
178 3 : uint32_t NameSize = calculateNamesBufferSize();
179 6 : auto Data = Allocator.Allocate<uint8_t>(Size);
180 3 : uint32_t NamesOffset = Size - NameSize;
181 :
182 15 : FileInfoBuffer = MutableByteStream(MutableArrayRef<uint8_t>(Data, Size));
183 :
184 : WritableStreamRef MetadataBuffer =
185 9 : WritableStreamRef(FileInfoBuffer).keep_front(NamesOffset);
186 3 : StreamWriter MetadataWriter(MetadataBuffer);
187 :
188 6 : uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModuleInfos.size());
189 6 : uint16_t FileCount = std::min<uint32_t>(UINT16_MAX, SourceFileNames.size());
190 9 : if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules
191 0 : return EC;
192 9 : if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles
193 0 : return EC;
194 7 : for (uint16_t I = 0; I < ModiCount; ++I) {
195 12 : if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices
196 0 : return EC;
197 : }
198 16 : for (const auto MI : ModuleInfoList) {
199 8 : FileCount = static_cast<uint16_t>(MI->SourceFiles.size());
200 12 : if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts
201 0 : return EC;
202 : }
203 :
204 : // Before writing the FileNameOffsets array, write the NamesBuffer array.
205 : // A side effect of this is that this will actually compute the various
206 : // file name offsets, so we can then go back and write the FileNameOffsets
207 : // array to the other substream.
208 9 : NamesBuffer = WritableStreamRef(FileInfoBuffer).drop_front(NamesOffset);
209 3 : StreamWriter NameBufferWriter(NamesBuffer);
210 10 : for (auto &Name : SourceFileNames) {
211 1 : Name.second = NameBufferWriter.getOffset();
212 3 : if (auto EC = NameBufferWriter.writeZeroString(Name.getKey()))
213 0 : return EC;
214 : }
215 :
216 16 : for (const auto MI : ModuleInfoList) {
217 17 : for (StringRef Name : MI->SourceFiles) {
218 1 : auto Result = SourceFileNames.find(Name);
219 2 : if (Result == SourceFileNames.end())
220 : return make_error<RawError>(raw_error_code::no_entry,
221 0 : "The source file was not found.");
222 3 : if (auto EC = MetadataWriter.writeInteger(Result->second))
223 0 : return EC;
224 : }
225 : }
226 :
227 3 : if (NameBufferWriter.bytesRemaining() > 0)
228 : return make_error<RawError>(raw_error_code::invalid_format,
229 0 : "The names buffer contained unexpected data.");
230 :
231 3 : if (MetadataWriter.bytesRemaining() > sizeof(uint32_t))
232 : return make_error<RawError>(
233 : raw_error_code::invalid_format,
234 0 : "The metadata buffer contained unexpected data.");
235 :
236 9 : return Error::success();
237 : }
238 :
239 3 : Error DbiStreamBuilder::finalize() {
240 3 : if (Header)
241 0 : return Error::success();
242 :
243 6 : DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>();
244 :
245 9 : if (auto EC = generateModiSubstream())
246 0 : return EC;
247 9 : if (auto EC = generateFileInfoSubstream())
248 0 : return EC;
249 :
250 9 : H->VersionHeader = *VerHeader;
251 6 : H->VersionSignature = -1;
252 6 : H->Age = Age;
253 6 : H->BuildNumber = BuildNumber;
254 6 : H->Flags = Flags;
255 6 : H->PdbDllRbld = PdbDllRbld;
256 6 : H->PdbDllVersion = PdbDllVersion;
257 6 : H->MachineType = static_cast<uint16_t>(MachineType);
258 :
259 6 : H->ECSubstreamSize = 0;
260 9 : H->FileInfoSize = FileInfoBuffer.getLength();
261 9 : H->ModiSubstreamSize = ModInfoBuffer.getLength();
262 9 : H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t);
263 6 : H->SecContrSubstreamSize = calculateSectionContribsStreamSize();
264 6 : H->SectionMapSize = calculateSectionMapStreamSize();
265 6 : H->TypeServerSize = 0;
266 6 : H->SymRecordStreamIndex = kInvalidStreamIndex;
267 6 : H->PublicSymbolStreamIndex = kInvalidStreamIndex;
268 6 : H->MFCTypeServerIndex = kInvalidStreamIndex;
269 6 : H->GlobalSymbolStreamIndex = kInvalidStreamIndex;
270 :
271 3 : Header = H;
272 9 : return Error::success();
273 : }
274 :
275 3 : Error DbiStreamBuilder::finalizeMsfLayout() {
276 3 : uint32_t Length = calculateSerializedLength();
277 9 : if (auto EC = Msf.setStreamSize(StreamDBI, Length))
278 0 : return EC;
279 9 : return Error::success();
280 : }
281 :
282 6 : static uint16_t toSecMapFlags(uint32_t Flags) {
283 6 : uint16_t Ret = 0;
284 6 : if (Flags & COFF::IMAGE_SCN_MEM_READ)
285 6 : Ret |= static_cast<uint16_t>(OMFSegDescFlags::Read);
286 6 : if (Flags & COFF::IMAGE_SCN_MEM_WRITE)
287 0 : Ret |= static_cast<uint16_t>(OMFSegDescFlags::Write);
288 6 : if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
289 2 : Ret |= static_cast<uint16_t>(OMFSegDescFlags::Execute);
290 6 : if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
291 2 : Ret |= static_cast<uint16_t>(OMFSegDescFlags::Execute);
292 6 : if (!(Flags & COFF::IMAGE_SCN_MEM_16BIT))
293 6 : Ret |= static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit);
294 :
295 : // This seems always 1.
296 6 : Ret |= static_cast<uint16_t>(OMFSegDescFlags::IsSelector);
297 :
298 6 : return Ret;
299 : }
300 :
301 : // A utility function to create Section Contributions
302 : // for a given input sections.
303 2 : std::vector<SectionContrib> DbiStreamBuilder::createSectionContribs(
304 : ArrayRef<object::coff_section> SecHdrs) {
305 2 : std::vector<SectionContrib> Ret;
306 :
307 : // Create a SectionContrib for each input section.
308 11 : for (auto &Sec : SecHdrs) {
309 7 : Ret.emplace_back();
310 7 : auto &Entry = Ret.back();
311 7 : memset(&Entry, 0, sizeof(Entry));
312 :
313 21 : Entry.Off = Sec.PointerToRawData;
314 21 : Entry.Size = Sec.SizeOfRawData;
315 7 : Entry.Characteristics = Sec.Characteristics;
316 : }
317 2 : return Ret;
318 : }
319 :
320 : // A utility function to create a Section Map for a given list of COFF sections.
321 : //
322 : // A Section Map seem to be a copy of a COFF section list in other format.
323 : // I don't know why a PDB file contains both a COFF section header and
324 : // a Section Map, but it seems it must be present in a PDB.
325 2 : std::vector<SecMapEntry> DbiStreamBuilder::createSectionMap(
326 : ArrayRef<llvm::object::coff_section> SecHdrs) {
327 2 : std::vector<SecMapEntry> Ret;
328 2 : int Idx = 0;
329 :
330 8 : auto Add = [&]() -> SecMapEntry & {
331 8 : Ret.emplace_back();
332 8 : auto &Entry = Ret.back();
333 8 : memset(&Entry, 0, sizeof(Entry));
334 :
335 16 : Entry.Frame = Idx + 1;
336 :
337 : // We don't know the meaning of these fields yet.
338 16 : Entry.SecName = UINT16_MAX;
339 16 : Entry.ClassName = UINT16_MAX;
340 :
341 8 : return Entry;
342 2 : };
343 :
344 10 : for (auto &Hdr : SecHdrs) {
345 6 : auto &Entry = Add();
346 18 : Entry.Flags = toSecMapFlags(Hdr.Characteristics);
347 6 : Entry.SecByteLength = Hdr.VirtualSize;
348 6 : ++Idx;
349 : }
350 :
351 : // The last entry is for absolute symbols.
352 2 : auto &Entry = Add();
353 2 : Entry.Flags = static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit) |
354 2 : static_cast<uint16_t>(OMFSegDescFlags::IsAbsoluteAddress);
355 4 : Entry.SecByteLength = UINT32_MAX;
356 :
357 2 : return Ret;
358 : }
359 :
360 3 : Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
361 : const msf::WritableStream &Buffer) {
362 9 : if (auto EC = finalize())
363 0 : return EC;
364 :
365 : auto InfoS =
366 3 : WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamDBI);
367 :
368 6 : StreamWriter Writer(*InfoS);
369 12 : if (auto EC = Writer.writeObject(*Header))
370 0 : return EC;
371 :
372 12 : if (auto EC = Writer.writeStreamRef(ModInfoBuffer))
373 0 : return EC;
374 :
375 3 : if (!SectionContribs.empty()) {
376 6 : if (auto EC = Writer.writeEnum(DbiSecContribVer60))
377 0 : return EC;
378 6 : if (auto EC = Writer.writeArray(SectionContribs))
379 0 : return EC;
380 : }
381 :
382 3 : if (!SectionMap.empty()) {
383 4 : ulittle16_t Size = static_cast<ulittle16_t>(SectionMap.size());
384 2 : SecMapHeader SMHeader = {Size, Size};
385 6 : if (auto EC = Writer.writeObject(SMHeader))
386 0 : return EC;
387 6 : if (auto EC = Writer.writeArray(SectionMap))
388 0 : return EC;
389 : }
390 :
391 12 : if (auto EC = Writer.writeStreamRef(FileInfoBuffer))
392 0 : return EC;
393 :
394 42 : for (auto &Stream : DbgStreams)
395 99 : if (auto EC = Writer.writeInteger(Stream.StreamNumber))
396 0 : return EC;
397 :
398 42 : for (auto &Stream : DbgStreams) {
399 33 : if (Stream.StreamNumber == kInvalidStreamIndex)
400 0 : continue;
401 : auto WritableStream = WritableMappedBlockStream::createIndexedStream(
402 66 : Layout, Buffer, Stream.StreamNumber);
403 66 : StreamWriter DbgStreamWriter(*WritableStream);
404 99 : if (auto EC = DbgStreamWriter.writeArray(Stream.Data))
405 0 : return EC;
406 : }
407 :
408 3 : if (Writer.bytesRemaining() > 0)
409 : return make_error<RawError>(raw_error_code::invalid_format,
410 0 : "Unexpected bytes found in DBI Stream");
411 9 : return Error::success();
412 : }
|