xref: /llvm-project/llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp (revision eb4c8608115c1c9af0fc8cb5b1e9f2bc960014ef)
1 //===- PDBFileBuilder.cpp - PDB File Creation -------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
10 #include "llvm/DebugInfo/CodeView/CodeView.h"
11 #include "llvm/DebugInfo/CodeView/GUID.h"
12 #include "llvm/DebugInfo/MSF/IMSFFile.h"
13 #include "llvm/DebugInfo/MSF/MSFBuilder.h"
14 #include "llvm/DebugInfo/MSF/MSFCommon.h"
15 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
16 #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
17 #include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
18 #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
19 #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
20 #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
21 #include "llvm/DebugInfo/PDB/Native/RawError.h"
22 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
23 #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
24 #include "llvm/Support/BinaryStreamWriter.h"
25 #include "llvm/Support/CRC.h"
26 #include "llvm/Support/Path.h"
27 #include "llvm/Support/xxhash.h"
28 
29 using namespace llvm;
30 using namespace llvm::codeview;
31 using namespace llvm::msf;
32 using namespace llvm::pdb;
33 using namespace llvm::support;
34 
35 namespace llvm {
36 class WritableBinaryStream;
37 }
38 
39 PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
40     : Allocator(Allocator), InjectedSourceHashTraits(Strings),
41       InjectedSourceTable(2) {}
42 
43 PDBFileBuilder::~PDBFileBuilder() = default;
44 
45 Error PDBFileBuilder::initialize(uint32_t BlockSize) {
46   auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize);
47   if (!ExpectedMsf)
48     return ExpectedMsf.takeError();
49   Msf = std::make_unique<MSFBuilder>(std::move(*ExpectedMsf));
50   return Error::success();
51 }
52 
53 MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
54 
55 InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
56   if (!Info)
57     Info = std::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
58   return *Info;
59 }
60 
61 DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
62   if (!Dbi)
63     Dbi = std::make_unique<DbiStreamBuilder>(*Msf);
64   return *Dbi;
65 }
66 
67 TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() {
68   if (!Tpi)
69     Tpi = std::make_unique<TpiStreamBuilder>(*Msf, StreamTPI);
70   return *Tpi;
71 }
72 
73 TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() {
74   if (!Ipi)
75     Ipi = std::make_unique<TpiStreamBuilder>(*Msf, StreamIPI);
76   return *Ipi;
77 }
78 
79 PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() {
80   return Strings;
81 }
82 
83 GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() {
84   if (!Gsi)
85     Gsi = std::make_unique<GSIStreamBuilder>(*Msf);
86   return *Gsi;
87 }
88 
89 Expected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name,
90                                                        uint32_t Size) {
91   auto ExpectedStream = Msf->addStream(Size);
92   if (ExpectedStream)
93     NamedStreams.set(Name, *ExpectedStream);
94   return ExpectedStream;
95 }
96 
97 Error PDBFileBuilder::addNamedStream(StringRef Name, StringRef Data) {
98   Expected<uint32_t> ExpectedIndex = allocateNamedStream(Name, Data.size());
99   if (!ExpectedIndex)
100     return ExpectedIndex.takeError();
101   assert(NamedStreamData.count(*ExpectedIndex) == 0);
102   NamedStreamData[*ExpectedIndex] = std::string(Data);
103   return Error::success();
104 }
105 
106 void PDBFileBuilder::addInjectedSource(StringRef Name,
107                                        std::unique_ptr<MemoryBuffer> Buffer) {
108   // Stream names must be exact matches, since they get looked up in a hash
109   // table and the hash value is dependent on the exact contents of the string.
110   // link.exe lowercases a path and converts / to \, so we must do the same.
111   SmallString<64> VName;
112   sys::path::native(Name.lower(), VName, sys::path::Style::windows_backslash);
113 
114   uint32_t NI = getStringTableBuilder().insert(Name);
115   uint32_t VNI = getStringTableBuilder().insert(VName);
116 
117   InjectedSourceDescriptor Desc;
118   Desc.Content = std::move(Buffer);
119   Desc.NameIndex = NI;
120   Desc.VNameIndex = VNI;
121   Desc.StreamName = "/src/files/";
122 
123   Desc.StreamName += VName;
124 
125   InjectedSources.push_back(std::move(Desc));
126 }
127 
128 Error PDBFileBuilder::finalizeMsfLayout() {
129 
130   if (Ipi && Ipi->getRecordCount() > 0) {
131     // In theory newer PDBs always have an ID stream, but by saying that we're
132     // only going to *really* have an ID stream if there is at least one ID
133     // record, we leave open the opportunity to test older PDBs such as those
134     // that don't have an ID stream.
135     auto &Info = getInfoBuilder();
136     Info.addFeature(PdbRaw_FeatureSig::VC140);
137   }
138 
139   uint32_t StringsLen = Strings.calculateSerializedSize();
140 
141   Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0);
142   if (!SN)
143     return SN.takeError();
144 
145   if (Gsi) {
146     if (auto EC = Gsi->finalizeMsfLayout())
147       return EC;
148     if (Dbi) {
149       Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex());
150       Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex());
151       Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIndex());
152     }
153   }
154   if (Tpi) {
155     if (auto EC = Tpi->finalizeMsfLayout())
156       return EC;
157   }
158   if (Dbi) {
159     if (auto EC = Dbi->finalizeMsfLayout())
160       return EC;
161   }
162   SN = allocateNamedStream("/names", StringsLen);
163   if (!SN)
164     return SN.takeError();
165 
166   if (Ipi) {
167     if (auto EC = Ipi->finalizeMsfLayout())
168       return EC;
169   }
170 
171   // Do this last, since it relies on the named stream map being complete, and
172   // that can be updated by previous steps in the finalization.
173   if (Info) {
174     if (auto EC = Info->finalizeMsfLayout())
175       return EC;
176   }
177 
178   if (!InjectedSources.empty()) {
179     for (const auto &IS : InjectedSources) {
180       JamCRC CRC(0);
181       CRC.update(arrayRefFromStringRef(IS.Content->getBuffer()));
182 
183       SrcHeaderBlockEntry Entry;
184       ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry));
185       Entry.Size = sizeof(SrcHeaderBlockEntry);
186       Entry.FileSize = IS.Content->getBufferSize();
187       Entry.FileNI = IS.NameIndex;
188       Entry.VFileNI = IS.VNameIndex;
189       Entry.ObjNI = 1;
190       Entry.IsVirtual = 0;
191       Entry.Version =
192           static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
193       Entry.CRC = CRC.getCRC();
194       StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex);
195       InjectedSourceTable.set_as(VName, std::move(Entry),
196                                  InjectedSourceHashTraits);
197     }
198 
199     uint32_t SrcHeaderBlockSize =
200         sizeof(SrcHeaderBlockHeader) +
201         InjectedSourceTable.calculateSerializedLength();
202     SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize);
203     if (!SN)
204       return SN.takeError();
205     for (const auto &IS : InjectedSources) {
206       SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize());
207       if (!SN)
208         return SN.takeError();
209     }
210   }
211 
212   // Do this last, since it relies on the named stream map being complete, and
213   // that can be updated by previous steps in the finalization.
214   if (Info) {
215     if (auto EC = Info->finalizeMsfLayout())
216       return EC;
217   }
218 
219   return Error::success();
220 }
221 
222 Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
223   uint32_t SN = 0;
224   if (!NamedStreams.get(Name, SN))
225     return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
226   return SN;
227 }
228 
229 void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer,
230                                           const msf::MSFLayout &Layout) {
231   assert(!InjectedSourceTable.empty());
232 
233   uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock"));
234   auto Stream = WritableMappedBlockStream::createIndexedStream(
235       Layout, MsfBuffer, SN, Allocator);
236   BinaryStreamWriter Writer(*Stream);
237 
238   SrcHeaderBlockHeader Header;
239   ::memset(&Header, 0, sizeof(Header));
240   Header.Version = static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
241   Header.Size = Writer.bytesRemaining();
242 
243   cantFail(Writer.writeObject(Header));
244   cantFail(InjectedSourceTable.commit(Writer));
245 
246   assert(Writer.bytesRemaining() == 0);
247 }
248 
249 void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer,
250                                            const msf::MSFLayout &Layout) {
251   if (InjectedSourceTable.empty())
252     return;
253 
254   commitSrcHeaderBlock(MsfBuffer, Layout);
255 
256   for (const auto &IS : InjectedSources) {
257     uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName));
258 
259     auto SourceStream = WritableMappedBlockStream::createIndexedStream(
260         Layout, MsfBuffer, SN, Allocator);
261     BinaryStreamWriter SourceWriter(*SourceStream);
262     assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize());
263     cantFail(SourceWriter.writeBytes(
264         arrayRefFromStringRef(IS.Content->getBuffer())));
265   }
266 }
267 
268 Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) {
269   assert(!Filename.empty());
270   if (auto EC = finalizeMsfLayout())
271     return EC;
272 
273   MSFLayout Layout;
274   Expected<FileBufferByteStream> ExpectedMsfBuffer =
275       Msf->commit(Filename, Layout);
276   if (!ExpectedMsfBuffer)
277     return ExpectedMsfBuffer.takeError();
278   FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer);
279 
280   auto ExpectedSN = getNamedStreamIndex("/names");
281   if (!ExpectedSN)
282     return ExpectedSN.takeError();
283 
284   auto NS = WritableMappedBlockStream::createIndexedStream(
285       Layout, Buffer, *ExpectedSN, Allocator);
286   BinaryStreamWriter NSWriter(*NS);
287   if (auto EC = Strings.commit(NSWriter))
288     return EC;
289 
290   for (const auto &NSE : NamedStreamData) {
291     if (NSE.second.empty())
292       continue;
293 
294     auto NS = WritableMappedBlockStream::createIndexedStream(
295         Layout, Buffer, NSE.first, Allocator);
296     BinaryStreamWriter NSW(*NS);
297     if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second)))
298       return EC;
299   }
300 
301   if (Info) {
302     if (auto EC = Info->commit(Layout, Buffer))
303       return EC;
304   }
305 
306   if (Dbi) {
307     if (auto EC = Dbi->commit(Layout, Buffer))
308       return EC;
309   }
310 
311   if (Tpi) {
312     if (auto EC = Tpi->commit(Layout, Buffer))
313       return EC;
314   }
315 
316   if (Ipi) {
317     if (auto EC = Ipi->commit(Layout, Buffer))
318       return EC;
319   }
320 
321   if (Gsi) {
322     if (auto EC = Gsi->commit(Layout, Buffer))
323       return EC;
324   }
325 
326   auto InfoStreamBlocks = Layout.StreamMap[StreamPDB];
327   assert(!InfoStreamBlocks.empty());
328   uint64_t InfoStreamFileOffset =
329       blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize);
330   InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>(
331       Buffer.getBufferStart() + InfoStreamFileOffset);
332 
333   commitInjectedSources(Buffer, Layout);
334 
335   // Set the build id at the very end, after every other byte of the PDB
336   // has been written.
337   if (Info->hashPDBContentsToGUID()) {
338     // Compute a hash of all sections of the output file.
339     uint64_t Digest =
340         xxHash64({Buffer.getBufferStart(), Buffer.getBufferEnd()});
341 
342     H->Age = 1;
343 
344     memcpy(H->Guid.Guid, &Digest, 8);
345     // xxhash only gives us 8 bytes, so put some fixed data in the other half.
346     memcpy(H->Guid.Guid + 8, "LLD PDB.", 8);
347 
348     // Put the hash in the Signature field too.
349     H->Signature = static_cast<uint32_t>(Digest);
350 
351     // Return GUID to caller.
352     memcpy(Guid, H->Guid.Guid, 16);
353   } else {
354     H->Age = Info->getAge();
355     H->Guid = Info->getGuid();
356     Optional<uint32_t> Sig = Info->getSignature();
357     H->Signature = Sig.hasValue() ? *Sig : time(nullptr);
358   }
359 
360   return Buffer.commit();
361 }
362