1 //===- 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/Native/PDBFileBuilder.h"
11 
12 #include "llvm/ADT/BitVector.h"
13 
14 #include "llvm/DebugInfo/MSF/MSFBuilder.h"
15 #include "llvm/DebugInfo/PDB/GenericError.h"
16 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
17 #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
18 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
19 #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
20 #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
21 #include "llvm/DebugInfo/PDB/Native/RawError.h"
22 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
23 #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
24 #include "llvm/Support/BinaryStream.h"
25 #include "llvm/Support/BinaryStreamWriter.h"
26 
27 using namespace llvm;
28 using namespace llvm::codeview;
29 using namespace llvm::msf;
30 using namespace llvm::pdb;
31 using namespace llvm::support;
32 
33 PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
34     : Allocator(Allocator) {}
35 
36 Error PDBFileBuilder::initialize(uint32_t BlockSize) {
37   auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize);
38   if (!ExpectedMsf)
39     return ExpectedMsf.takeError();
40   Msf = llvm::make_unique<MSFBuilder>(std::move(*ExpectedMsf));
41   return Error::success();
42 }
43 
44 MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
45 
46 InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
47   if (!Info)
48     Info = llvm::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
49   return *Info;
50 }
51 
52 DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
53   if (!Dbi)
54     Dbi = llvm::make_unique<DbiStreamBuilder>(*Msf);
55   return *Dbi;
56 }
57 
58 TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() {
59   if (!Tpi)
60     Tpi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamTPI);
61   return *Tpi;
62 }
63 
64 TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() {
65   if (!Ipi)
66     Ipi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamIPI);
67   return *Ipi;
68 }
69 
70 PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() {
71   return Strings;
72 }
73 
74 Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) {
75   auto ExpectedStream = Msf->addStream(Size);
76   if (!ExpectedStream)
77     return ExpectedStream.takeError();
78   NamedStreams.set(Name, *ExpectedStream);
79   return Error::success();
80 }
81 
82 Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() {
83 
84   if (Ipi && Ipi->getRecordCount() > 0) {
85     // In theory newer PDBs always have an ID stream, but by saying that we're
86     // only going to *really* have an ID stream if there is at least one ID
87     // record, we leave open the opportunity to test older PDBs such as those
88     // that don't have an ID stream.
89     auto &Info = getInfoBuilder();
90     Info.addFeature(PdbRaw_FeatureSig::VC140);
91   }
92 
93   uint32_t StringsLen = Strings.calculateSerializedSize();
94 
95   if (auto EC = addNamedStream("/names", StringsLen))
96     return std::move(EC);
97   if (auto EC = addNamedStream("/LinkInfo", 0))
98     return std::move(EC);
99   if (auto EC = addNamedStream("/src/headerblock", 0))
100     return std::move(EC);
101 
102   if (Info) {
103     if (auto EC = Info->finalizeMsfLayout())
104       return std::move(EC);
105   }
106   if (Dbi) {
107     if (auto EC = Dbi->finalizeMsfLayout())
108       return std::move(EC);
109   }
110   if (Tpi) {
111     if (auto EC = Tpi->finalizeMsfLayout())
112       return std::move(EC);
113   }
114   if (Ipi) {
115     if (auto EC = Ipi->finalizeMsfLayout())
116       return std::move(EC);
117   }
118 
119   return Msf->build();
120 }
121 
122 Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
123   uint32_t SN = 0;
124   if (!NamedStreams.get(Name, SN))
125     return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
126   return SN;
127 }
128 
129 Error PDBFileBuilder::commit(StringRef Filename) {
130   assert(!Filename.empty());
131   auto ExpectedLayout = finalizeMsfLayout();
132   if (!ExpectedLayout)
133     return ExpectedLayout.takeError();
134   auto &Layout = *ExpectedLayout;
135 
136   uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks;
137   auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize);
138   if (OutFileOrError.getError())
139     return llvm::make_error<pdb::GenericError>(generic_error_code::invalid_path,
140                                                Filename);
141   FileBufferByteStream Buffer(std::move(*OutFileOrError),
142                               llvm::support::little);
143   BinaryStreamWriter Writer(Buffer);
144 
145   if (auto EC = Writer.writeObject(*Layout.SB))
146     return EC;
147   uint32_t BlockMapOffset =
148       msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize);
149   Writer.setOffset(BlockMapOffset);
150   if (auto EC = Writer.writeArray(Layout.DirectoryBlocks))
151     return EC;
152 
153   auto DirStream = WritableMappedBlockStream::createDirectoryStream(
154       Layout, Buffer, Allocator);
155   BinaryStreamWriter DW(*DirStream);
156   if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size()))
157     return EC;
158 
159   if (auto EC = DW.writeArray(Layout.StreamSizes))
160     return EC;
161 
162   for (const auto &Blocks : Layout.StreamMap) {
163     if (auto EC = DW.writeArray(Blocks))
164       return EC;
165   }
166 
167   auto ExpectedSN = getNamedStreamIndex("/names");
168   if (!ExpectedSN)
169     return ExpectedSN.takeError();
170 
171   auto NS = WritableMappedBlockStream::createIndexedStream(
172       Layout, Buffer, *ExpectedSN, Allocator);
173   BinaryStreamWriter NSWriter(*NS);
174   if (auto EC = Strings.commit(NSWriter))
175     return EC;
176 
177   if (Info) {
178     if (auto EC = Info->commit(Layout, Buffer))
179       return EC;
180   }
181 
182   if (Dbi) {
183     if (auto EC = Dbi->commit(Layout, Buffer))
184       return EC;
185   }
186 
187   if (Tpi) {
188     if (auto EC = Tpi->commit(Layout, Buffer))
189       return EC;
190   }
191 
192   if (Ipi) {
193     if (auto EC = Ipi->commit(Layout, Buffer))
194       return EC;
195   }
196 
197   return Buffer.commit();
198 }
199