/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
Line | Count | Source (jump to first uncovered line) |
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/GSIStreamBuilder.h" |
19 | | #include "llvm/DebugInfo/PDB/Native/InfoStream.h" |
20 | | #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" |
21 | | #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" |
22 | | #include "llvm/DebugInfo/PDB/Native/RawError.h" |
23 | | #include "llvm/DebugInfo/PDB/Native/TpiStream.h" |
24 | | #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" |
25 | | #include "llvm/Support/BinaryStream.h" |
26 | | #include "llvm/Support/BinaryStreamWriter.h" |
27 | | |
28 | | using namespace llvm; |
29 | | using namespace llvm::codeview; |
30 | | using namespace llvm::msf; |
31 | | using namespace llvm::pdb; |
32 | | using namespace llvm::support; |
33 | | |
34 | | PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator) |
35 | 60 | : Allocator(Allocator) {} |
36 | | |
37 | 60 | PDBFileBuilder::~PDBFileBuilder() {} |
38 | | |
39 | 60 | Error PDBFileBuilder::initialize(uint32_t BlockSize) { |
40 | 60 | auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize); |
41 | 60 | if (!ExpectedMsf) |
42 | 0 | return ExpectedMsf.takeError(); |
43 | 60 | Msf = llvm::make_unique<MSFBuilder>(std::move(*ExpectedMsf)); |
44 | 60 | return Error::success(); |
45 | 60 | } |
46 | | |
47 | 300 | MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; } |
48 | | |
49 | 85 | InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() { |
50 | 85 | if (!Info) |
51 | 60 | Info = llvm::make_unique<InfoStreamBuilder>(*Msf, NamedStreams); |
52 | 85 | return *Info; |
53 | 85 | } |
54 | | |
55 | 466 | DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() { |
56 | 466 | if (!Dbi) |
57 | 57 | Dbi = llvm::make_unique<DbiStreamBuilder>(*Msf); |
58 | 466 | return *Dbi; |
59 | 466 | } |
60 | | |
61 | 60 | TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() { |
62 | 60 | if (!Tpi) |
63 | 60 | Tpi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamTPI); |
64 | 60 | return *Tpi; |
65 | 60 | } |
66 | | |
67 | 60 | TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() { |
68 | 60 | if (!Ipi) |
69 | 60 | Ipi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamIPI); |
70 | 60 | return *Ipi; |
71 | 60 | } |
72 | | |
73 | 57 | PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() { |
74 | 57 | return Strings; |
75 | 57 | } |
76 | | |
77 | 148 | GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() { |
78 | 148 | if (!Gsi) |
79 | 40 | Gsi = llvm::make_unique<GSIStreamBuilder>(*Msf); |
80 | 148 | return *Gsi; |
81 | 148 | } |
82 | | |
83 | 120 | Error PDBFileBuilder::addNamedStream(StringRef Name, uint32_t Size) { |
84 | 120 | auto ExpectedStream = Msf->addStream(Size); |
85 | 120 | if (!ExpectedStream) |
86 | 0 | return ExpectedStream.takeError(); |
87 | 120 | NamedStreams.set(Name, *ExpectedStream); |
88 | 120 | return Error::success(); |
89 | 120 | } |
90 | | |
91 | 60 | Expected<msf::MSFLayout> PDBFileBuilder::finalizeMsfLayout() { |
92 | 60 | |
93 | 60 | if (Ipi && 60 Ipi->getRecordCount() > 060 ) { |
94 | 25 | // In theory newer PDBs always have an ID stream, but by saying that we're |
95 | 25 | // only going to *really* have an ID stream if there is at least one ID |
96 | 25 | // record, we leave open the opportunity to test older PDBs such as those |
97 | 25 | // that don't have an ID stream. |
98 | 25 | auto &Info = getInfoBuilder(); |
99 | 25 | Info.addFeature(PdbRaw_FeatureSig::VC140); |
100 | 25 | } |
101 | 60 | |
102 | 60 | uint32_t StringsLen = Strings.calculateSerializedSize(); |
103 | 60 | |
104 | 60 | if (auto EC = addNamedStream("/names", StringsLen)) |
105 | 0 | return std::move(EC); |
106 | 60 | if (auto 60 EC60 = addNamedStream("/LinkInfo", 0)) |
107 | 0 | return std::move(EC); |
108 | 60 | |
109 | 60 | if (60 Info60 ) { |
110 | 60 | if (auto EC = Info->finalizeMsfLayout()) |
111 | 0 | return std::move(EC); |
112 | 60 | } |
113 | 60 | if (60 Dbi60 ) { |
114 | 57 | if (auto EC = Dbi->finalizeMsfLayout()) |
115 | 0 | return std::move(EC); |
116 | 60 | } |
117 | 60 | if (60 Tpi60 ) { |
118 | 60 | if (auto EC = Tpi->finalizeMsfLayout()) |
119 | 0 | return std::move(EC); |
120 | 60 | } |
121 | 60 | if (60 Ipi60 ) { |
122 | 60 | if (auto EC = Ipi->finalizeMsfLayout()) |
123 | 0 | return std::move(EC); |
124 | 60 | } |
125 | 60 | if (60 Gsi60 ) { |
126 | 40 | if (auto EC = Gsi->finalizeMsfLayout()) |
127 | 0 | return std::move(EC); |
128 | 40 | if (40 Dbi40 ) { |
129 | 40 | Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex()); |
130 | 40 | Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex()); |
131 | 40 | Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx()); |
132 | 40 | } |
133 | 40 | } |
134 | 60 | |
135 | 60 | return Msf->build(); |
136 | 60 | } |
137 | | |
138 | 60 | Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const { |
139 | 60 | uint32_t SN = 0; |
140 | 60 | if (!NamedStreams.get(Name, SN)) |
141 | 0 | return llvm::make_error<pdb::RawError>(raw_error_code::no_stream); |
142 | 60 | return SN; |
143 | 60 | } |
144 | | |
145 | | void PDBFileBuilder::commitFpm(WritableBinaryStream &MsfBuffer, |
146 | 60 | const MSFLayout &Layout) { |
147 | 60 | auto FpmStream = |
148 | 60 | WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator); |
149 | 60 | |
150 | 60 | // We only need to create the alt fpm stream so that it gets initialized. |
151 | 60 | WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator, |
152 | 60 | true); |
153 | 60 | |
154 | 60 | uint32_t BI = 0; |
155 | 60 | BinaryStreamWriter FpmWriter(*FpmStream); |
156 | 204 | while (BI < Layout.SB->NumBlocks204 ) { |
157 | 144 | uint8_t ThisByte = 0; |
158 | 1.29k | for (uint32_t I = 0; I < 81.29k ; ++I1.15k ) { |
159 | 1.15k | bool IsFree = |
160 | 1.15k | (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI)954 : true198 ; |
161 | 1.15k | uint8_t Mask = uint8_t(IsFree) << I; |
162 | 1.15k | ThisByte |= Mask; |
163 | 1.15k | ++BI; |
164 | 1.15k | } |
165 | 144 | cantFail(FpmWriter.writeObject(ThisByte)); |
166 | 144 | } |
167 | 60 | assert(FpmWriter.bytesRemaining() == 0); |
168 | 60 | } |
169 | | |
170 | 60 | Error PDBFileBuilder::commit(StringRef Filename) { |
171 | 60 | assert(!Filename.empty()); |
172 | 60 | auto ExpectedLayout = finalizeMsfLayout(); |
173 | 60 | if (!ExpectedLayout) |
174 | 0 | return ExpectedLayout.takeError(); |
175 | 60 | auto &Layout = *ExpectedLayout; |
176 | 60 | |
177 | 60 | uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks; |
178 | 60 | auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize); |
179 | 60 | if (OutFileOrError.getError()) |
180 | 0 | return llvm::make_error<pdb::GenericError>(generic_error_code::invalid_path, |
181 | 0 | Filename); |
182 | 60 | FileBufferByteStream Buffer(std::move(*OutFileOrError), |
183 | 60 | llvm::support::little); |
184 | 60 | BinaryStreamWriter Writer(Buffer); |
185 | 60 | |
186 | 60 | if (auto EC = Writer.writeObject(*Layout.SB)) |
187 | 0 | return EC; |
188 | 60 | |
189 | 60 | commitFpm(Buffer, Layout); |
190 | 60 | |
191 | 60 | uint32_t BlockMapOffset = |
192 | 60 | msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize); |
193 | 60 | Writer.setOffset(BlockMapOffset); |
194 | 60 | if (auto EC = Writer.writeArray(Layout.DirectoryBlocks)) |
195 | 0 | return EC; |
196 | 60 | |
197 | 60 | auto DirStream = WritableMappedBlockStream::createDirectoryStream( |
198 | 60 | Layout, Buffer, Allocator); |
199 | 60 | BinaryStreamWriter DW(*DirStream); |
200 | 60 | if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size())) |
201 | 0 | return EC; |
202 | 60 | |
203 | 60 | if (auto 60 EC60 = DW.writeArray(Layout.StreamSizes)) |
204 | 0 | return EC; |
205 | 60 | |
206 | 60 | for (const auto &Blocks : Layout.StreamMap) 60 { |
207 | 781 | if (auto EC = DW.writeArray(Blocks)) |
208 | 0 | return EC; |
209 | 60 | } |
210 | 60 | |
211 | 60 | auto ExpectedSN = getNamedStreamIndex("/names"); |
212 | 60 | if (!ExpectedSN) |
213 | 0 | return ExpectedSN.takeError(); |
214 | 60 | |
215 | 60 | auto NS = WritableMappedBlockStream::createIndexedStream( |
216 | 60 | Layout, Buffer, *ExpectedSN, Allocator); |
217 | 60 | BinaryStreamWriter NSWriter(*NS); |
218 | 60 | if (auto EC = Strings.commit(NSWriter)) |
219 | 0 | return EC; |
220 | 60 | |
221 | 60 | if (60 Info60 ) { |
222 | 60 | if (auto EC = Info->commit(Layout, Buffer)) |
223 | 0 | return EC; |
224 | 60 | } |
225 | 60 | |
226 | 60 | if (60 Dbi60 ) { |
227 | 57 | if (auto EC = Dbi->commit(Layout, Buffer)) |
228 | 0 | return EC; |
229 | 60 | } |
230 | 60 | |
231 | 60 | if (60 Tpi60 ) { |
232 | 60 | if (auto EC = Tpi->commit(Layout, Buffer)) |
233 | 0 | return EC; |
234 | 60 | } |
235 | 60 | |
236 | 60 | if (60 Ipi60 ) { |
237 | 60 | if (auto EC = Ipi->commit(Layout, Buffer)) |
238 | 0 | return EC; |
239 | 60 | } |
240 | 60 | |
241 | 60 | if (60 Gsi60 ) { |
242 | 40 | if (auto EC = Gsi->commit(Layout, Buffer)) |
243 | 0 | return EC; |
244 | 60 | } |
245 | 60 | |
246 | 60 | return Buffer.commit(); |
247 | 60 | } |