blob: 6e4bb16479f1656e6be33490b91059f34e8bb656 [file] [log] [blame]
Zachary Turnerdbeaea72016-07-11 21:45:26 +00001//===- PDBFileBuilder.cpp - PDB File 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/PDBFileBuilder.h"
11
Zachary Turnerfaa554b2016-07-15 22:16:56 +000012#include "llvm/ADT/BitVector.h"
13
Zachary Turnera3225b02016-07-29 20:56:36 +000014#include "llvm/DebugInfo/MSF/MSFBuilder.h"
15#include "llvm/DebugInfo/MSF/StreamInterface.h"
16#include "llvm/DebugInfo/MSF/StreamWriter.h"
Zachary Turnerdbeaea72016-07-11 21:45:26 +000017#include "llvm/DebugInfo/PDB/Raw/DbiStream.h"
18#include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h"
19#include "llvm/DebugInfo/PDB/Raw/InfoStream.h"
20#include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h"
21#include "llvm/DebugInfo/PDB/Raw/RawError.h"
22
23using namespace llvm;
24using namespace llvm::codeview;
Zachary Turnerbac69d32016-07-22 19:56:05 +000025using namespace llvm::msf;
Zachary Turnerdbeaea72016-07-11 21:45:26 +000026using namespace llvm::pdb;
Zachary Turnerfaa554b2016-07-15 22:16:56 +000027using namespace llvm::support;
Zachary Turnerdbeaea72016-07-11 21:45:26 +000028
Zachary Turnere109dc62016-07-22 19:56:26 +000029PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
30 : Allocator(Allocator) {}
Zachary Turnerdbeaea72016-07-11 21:45:26 +000031
Zachary Turnerfaa554b2016-07-15 22:16:56 +000032Error PDBFileBuilder::initialize(const msf::SuperBlock &Super) {
33 auto ExpectedMsf =
Zachary Turnera3225b02016-07-29 20:56:36 +000034 MSFBuilder::create(Allocator, Super.BlockSize, Super.NumBlocks);
Zachary Turnerfaa554b2016-07-15 22:16:56 +000035 if (!ExpectedMsf)
36 return ExpectedMsf.takeError();
Zachary Turnerdbeaea72016-07-11 21:45:26 +000037
Zachary Turnerfaa554b2016-07-15 22:16:56 +000038 auto &MsfResult = *ExpectedMsf;
39 if (auto EC = MsfResult.setBlockMapAddr(Super.BlockMapAddr))
40 return EC;
Zachary Turnera3225b02016-07-29 20:56:36 +000041 Msf = llvm::make_unique<MSFBuilder>(std::move(MsfResult));
Zachary Turnerb927e022016-07-15 22:17:19 +000042 Msf->setFreePageMap(Super.FreeBlockMapBlock);
43 Msf->setUnknown1(Super.Unknown1);
Zachary Turnerdbeaea72016-07-11 21:45:26 +000044 return Error::success();
45}
46
Zachary Turnera3225b02016-07-29 20:56:36 +000047MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
Zachary Turnerfaa554b2016-07-15 22:16:56 +000048
Zachary Turnerdbeaea72016-07-11 21:45:26 +000049InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
50 if (!Info)
Zachary Turnerfaa554b2016-07-15 22:16:56 +000051 Info = llvm::make_unique<InfoStreamBuilder>();
Zachary Turnerdbeaea72016-07-11 21:45:26 +000052 return *Info;
53}
54
55DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
56 if (!Dbi)
Zachary Turnere109dc62016-07-22 19:56:26 +000057 Dbi = llvm::make_unique<DbiStreamBuilder>(Allocator);
Zachary Turnerdbeaea72016-07-11 21:45:26 +000058 return *Dbi;
59}
60
Zachary Turnera3225b02016-07-29 20:56:36 +000061Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() const {
Zachary Turnerdbeaea72016-07-11 21:45:26 +000062 if (Info) {
Zachary Turnerfaa554b2016-07-15 22:16:56 +000063 uint32_t Length = Info->calculateSerializedLength();
64 if (auto EC = Msf->setStreamSize(StreamPDB, Length))
65 return std::move(EC);
66 }
67 if (Dbi) {
68 uint32_t Length = Dbi->calculateSerializedLength();
69 if (auto EC = Msf->setStreamSize(StreamDBI, Length))
70 return std::move(EC);
71 }
72
Zachary Turner199f48a2016-07-28 19:11:09 +000073 return Msf->build();
74}
75
76Expected<std::unique_ptr<PDBFile>>
Zachary Turnerd66889c2016-07-28 19:12:28 +000077PDBFileBuilder::build(std::unique_ptr<msf::WritableStream> PdbFileBuffer) {
Zachary Turner199f48a2016-07-28 19:11:09 +000078 auto ExpectedLayout = finalizeMsfLayout();
Zachary Turnerfaa554b2016-07-15 22:16:56 +000079 if (!ExpectedLayout)
80 return ExpectedLayout.takeError();
81
Zachary Turnere109dc62016-07-22 19:56:26 +000082 auto File = llvm::make_unique<PDBFile>(std::move(PdbFileBuffer), Allocator);
Zachary Turnerd66889c2016-07-28 19:12:28 +000083 File->ContainerLayout = *ExpectedLayout;
Zachary Turnerfaa554b2016-07-15 22:16:56 +000084
85 if (Info) {
Zachary Turnerd66889c2016-07-28 19:12:28 +000086 auto ExpectedInfo = Info->build(*File, *PdbFileBuffer);
Zachary Turnerdbeaea72016-07-11 21:45:26 +000087 if (!ExpectedInfo)
88 return ExpectedInfo.takeError();
89 File->Info = std::move(*ExpectedInfo);
90 }
91
92 if (Dbi) {
Zachary Turnerd66889c2016-07-28 19:12:28 +000093 auto ExpectedDbi = Dbi->build(*File, *PdbFileBuffer);
Zachary Turnerdbeaea72016-07-11 21:45:26 +000094 if (!ExpectedDbi)
95 return ExpectedDbi.takeError();
96 File->Dbi = std::move(*ExpectedDbi);
97 }
98
99 if (File->Info && File->Dbi && File->Info->getAge() != File->Dbi->getAge())
100 return llvm::make_error<RawError>(
101 raw_error_code::corrupt_file,
102 "PDB Stream Age doesn't match Dbi Stream Age!");
103
104 return std::move(File);
105}
Zachary Turnerd66889c2016-07-28 19:12:28 +0000106
107Error PDBFileBuilder::commit(const msf::WritableStream &Buffer) {
108 StreamWriter Writer(Buffer);
109 auto ExpectedLayout = finalizeMsfLayout();
110 if (!ExpectedLayout)
111 return ExpectedLayout.takeError();
112 auto &Layout = *ExpectedLayout;
113
114 if (auto EC = Writer.writeObject(*Layout.SB))
115 return EC;
116 uint32_t BlockMapOffset =
117 msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize);
118 Writer.setOffset(BlockMapOffset);
119 if (auto EC = Writer.writeArray(Layout.DirectoryBlocks))
120 return EC;
121
122 auto DirStream =
123 WritableMappedBlockStream::createDirectoryStream(Layout, Buffer);
124 StreamWriter DW(*DirStream);
Zachary Turner9f73c202016-07-28 19:29:52 +0000125 if (auto EC =
126 DW.writeInteger(static_cast<uint32_t>(Layout.StreamSizes.size())))
Zachary Turnerd66889c2016-07-28 19:12:28 +0000127 return EC;
128
129 if (auto EC = DW.writeArray(Layout.StreamSizes))
130 return EC;
131
132 for (const auto &Blocks : Layout.StreamMap) {
133 if (auto EC = DW.writeArray(Blocks))
134 return EC;
135 }
136
137 if (Info) {
138 if (auto EC = Info->commit(Layout, Buffer))
139 return EC;
140 }
141
142 if (Dbi) {
143 if (auto EC = Dbi->commit(Layout, Buffer))
144 return EC;
145 }
146
147 return Buffer.commit();
148}