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