LLVM  9.0.0svn
PDBFileBuilder.cpp
Go to the documentation of this file.
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 
10 
11 #include "llvm/ADT/BitVector.h"
12 
25 #include "llvm/Support/JamCRC.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 PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
36  : Allocator(Allocator), InjectedSourceHashTraits(Strings),
37  InjectedSourceTable(2, InjectedSourceHashTraits) {}
38 
40 
42  auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize);
43  if (!ExpectedMsf)
44  return ExpectedMsf.takeError();
45  Msf = llvm::make_unique<MSFBuilder>(std::move(*ExpectedMsf));
46  return Error::success();
47 }
48 
50 
52  if (!Info)
53  Info = llvm::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
54  return *Info;
55 }
56 
58  if (!Dbi)
59  Dbi = llvm::make_unique<DbiStreamBuilder>(*Msf);
60  return *Dbi;
61 }
62 
64  if (!Tpi)
65  Tpi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamTPI);
66  return *Tpi;
67 }
68 
70  if (!Ipi)
71  Ipi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamIPI);
72  return *Ipi;
73 }
74 
76  return Strings;
77 }
78 
80  if (!Gsi)
81  Gsi = llvm::make_unique<GSIStreamBuilder>(*Msf);
82  return *Gsi;
83 }
84 
85 Expected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name,
86  uint32_t Size) {
87  auto ExpectedStream = Msf->addStream(Size);
88  if (ExpectedStream)
89  NamedStreams.set(Name, *ExpectedStream);
90  return ExpectedStream;
91 }
92 
94  Expected<uint32_t> ExpectedIndex = allocateNamedStream(Name, Data.size());
95  if (!ExpectedIndex)
96  return ExpectedIndex.takeError();
97  assert(NamedStreamData.count(*ExpectedIndex) == 0);
98  NamedStreamData[*ExpectedIndex] = Data;
99  return Error::success();
100 }
101 
103  std::unique_ptr<MemoryBuffer> Buffer) {
104  // Stream names must be exact matches, since they get looked up in a hash
105  // table and the hash value is dependent on the exact contents of the string.
106  // link.exe lowercases a path and converts / to \, so we must do the same.
107  SmallString<64> VName;
108  sys::path::native(Name.lower(), VName);
109 
111  uint32_t VNI = getStringTableBuilder().insert(VName);
112 
113  InjectedSourceDescriptor Desc;
114  Desc.Content = std::move(Buffer);
115  Desc.NameIndex = NI;
116  Desc.VNameIndex = VNI;
117  Desc.StreamName = "/src/files/";
118 
119  Desc.StreamName += VName;
120 
121  InjectedSources.push_back(std::move(Desc));
122 }
123 
124 Error PDBFileBuilder::finalizeMsfLayout() {
125 
126  if (Ipi && Ipi->getRecordCount() > 0) {
127  // In theory newer PDBs always have an ID stream, but by saying that we're
128  // only going to *really* have an ID stream if there is at least one ID
129  // record, we leave open the opportunity to test older PDBs such as those
130  // that don't have an ID stream.
131  auto &Info = getInfoBuilder();
132  Info.addFeature(PdbRaw_FeatureSig::VC140);
133  }
134 
135  uint32_t StringsLen = Strings.calculateSerializedSize();
136 
137  Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0);
138  if (!SN)
139  return SN.takeError();
140 
141  if (Gsi) {
142  if (auto EC = Gsi->finalizeMsfLayout())
143  return EC;
144  if (Dbi) {
145  Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex());
146  Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex());
147  Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx());
148  }
149  }
150  if (Tpi) {
151  if (auto EC = Tpi->finalizeMsfLayout())
152  return EC;
153  }
154  if (Dbi) {
155  if (auto EC = Dbi->finalizeMsfLayout())
156  return EC;
157  }
158  SN = allocateNamedStream("/names", StringsLen);
159  if (!SN)
160  return SN.takeError();
161 
162  if (Ipi) {
163  if (auto EC = Ipi->finalizeMsfLayout())
164  return EC;
165  }
166 
167  // Do this last, since it relies on the named stream map being complete, and
168  // that can be updated by previous steps in the finalization.
169  if (Info) {
170  if (auto EC = Info->finalizeMsfLayout())
171  return EC;
172  }
173 
174  if (!InjectedSources.empty()) {
175  for (const auto &IS : InjectedSources) {
176  JamCRC CRC(0);
177  CRC.update(makeArrayRef(IS.Content->getBufferStart(),
178  IS.Content->getBufferSize()));
179 
180  SrcHeaderBlockEntry Entry;
181  ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry));
182  Entry.Size = sizeof(SrcHeaderBlockEntry);
183  Entry.FileSize = IS.Content->getBufferSize();
184  Entry.FileNI = IS.NameIndex;
185  Entry.VFileNI = IS.VNameIndex;
186  Entry.ObjNI = 1;
187  Entry.IsVirtual = 0;
188  Entry.Version =
190  Entry.CRC = CRC.getCRC();
191  StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex);
192  InjectedSourceTable.set_as(VName, std::move(Entry));
193  }
194 
195  uint32_t SrcHeaderBlockSize =
196  sizeof(SrcHeaderBlockHeader) +
197  InjectedSourceTable.calculateSerializedLength();
198  SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize);
199  if (!SN)
200  return SN.takeError();
201  for (const auto &IS : InjectedSources) {
202  SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize());
203  if (!SN)
204  return SN.takeError();
205  }
206  }
207 
208  // Do this last, since it relies on the named stream map being complete, and
209  // that can be updated by previous steps in the finalization.
210  if (Info) {
211  if (auto EC = Info->finalizeMsfLayout())
212  return EC;
213  }
214 
215  return Error::success();
216 }
217 
219  uint32_t SN = 0;
220  if (!NamedStreams.get(Name, SN))
221  return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
222  return SN;
223 }
224 
225 void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer,
226  const msf::MSFLayout &Layout) {
227  assert(!InjectedSourceTable.empty());
228 
229  uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock"));
230  auto Stream = WritableMappedBlockStream::createIndexedStream(
231  Layout, MsfBuffer, SN, Allocator);
232  BinaryStreamWriter Writer(*Stream);
233 
234  SrcHeaderBlockHeader Header;
235  ::memset(&Header, 0, sizeof(Header));
237  Header.Size = Writer.bytesRemaining();
238 
239  cantFail(Writer.writeObject(Header));
240  cantFail(InjectedSourceTable.commit(Writer));
241 
242  assert(Writer.bytesRemaining() == 0);
243 }
244 
245 void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer,
246  const msf::MSFLayout &Layout) {
247  if (InjectedSourceTable.empty())
248  return;
249 
250  commitSrcHeaderBlock(MsfBuffer, Layout);
251 
252  for (const auto &IS : InjectedSources) {
253  uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName));
254 
255  auto SourceStream = WritableMappedBlockStream::createIndexedStream(
256  Layout, MsfBuffer, SN, Allocator);
257  BinaryStreamWriter SourceWriter(*SourceStream);
258  assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize());
259  cantFail(SourceWriter.writeBytes(
260  arrayRefFromStringRef(IS.Content->getBuffer())));
261  }
262 }
263 
265  assert(!Filename.empty());
266  if (auto EC = finalizeMsfLayout())
267  return EC;
268 
269  MSFLayout Layout;
270  Expected<FileBufferByteStream> ExpectedMsfBuffer =
271  Msf->commit(Filename, Layout);
272  if (!ExpectedMsfBuffer)
273  return ExpectedMsfBuffer.takeError();
274  FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer);
275 
276  auto ExpectedSN = getNamedStreamIndex("/names");
277  if (!ExpectedSN)
278  return ExpectedSN.takeError();
279 
280  auto NS = WritableMappedBlockStream::createIndexedStream(
281  Layout, Buffer, *ExpectedSN, Allocator);
282  BinaryStreamWriter NSWriter(*NS);
283  if (auto EC = Strings.commit(NSWriter))
284  return EC;
285 
286  for (const auto &NSE : NamedStreamData) {
287  if (NSE.second.empty())
288  continue;
289 
290  auto NS = WritableMappedBlockStream::createIndexedStream(
291  Layout, Buffer, NSE.first, Allocator);
292  BinaryStreamWriter NSW(*NS);
293  if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second)))
294  return EC;
295  }
296 
297  if (Info) {
298  if (auto EC = Info->commit(Layout, Buffer))
299  return EC;
300  }
301 
302  if (Dbi) {
303  if (auto EC = Dbi->commit(Layout, Buffer))
304  return EC;
305  }
306 
307  if (Tpi) {
308  if (auto EC = Tpi->commit(Layout, Buffer))
309  return EC;
310  }
311 
312  if (Ipi) {
313  if (auto EC = Ipi->commit(Layout, Buffer))
314  return EC;
315  }
316 
317  if (Gsi) {
318  if (auto EC = Gsi->commit(Layout, Buffer))
319  return EC;
320  }
321 
322  auto InfoStreamBlocks = Layout.StreamMap[StreamPDB];
323  assert(!InfoStreamBlocks.empty());
324  uint64_t InfoStreamFileOffset =
325  blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize);
326  InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>(
327  Buffer.getBufferStart() + InfoStreamFileOffset);
328 
329  commitInjectedSources(Buffer, Layout);
330 
331  // Set the build id at the very end, after every other byte of the PDB
332  // has been written.
333  if (Info->hashPDBContentsToGUID()) {
334  // Compute a hash of all sections of the output file.
335  uint64_t Digest =
336  xxHash64({Buffer.getBufferStart(), Buffer.getBufferEnd()});
337 
338  H->Age = 1;
339 
340  memcpy(H->Guid.Guid, &Digest, 8);
341  // xxhash only gives us 8 bytes, so put some fixed data in the other half.
342  memcpy(H->Guid.Guid + 8, "LLD PDB.", 8);
343 
344  // Put the hash in the Signature field too.
345  H->Signature = static_cast<uint32_t>(Digest);
346 
347  // Return GUID to caller.
348  memcpy(Guid, H->Guid.Guid, 16);
349  } else {
350  H->Age = Info->getAge();
351  H->Guid = Info->getGuid();
352  Optional<uint32_t> Sig = Info->getSignature();
353  H->Signature = Sig.hasValue() ? *Sig : time(nullptr);
354  }
355 
356  return Buffer.commit();
357 }
Error writeObject(const T &Obj)
Writes the object Obj to the underlying stream, as if by using memcpy.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Definition: Error.h:703
uint32_t getCRC() const
Definition: JamCRC.h:41
Error writeBytes(ArrayRef< uint8_t > Buffer)
Write the bytes specified in Buffer to the underlying stream.
void native(const Twine &path, SmallVectorImpl< char > &result, Style style=Style::native)
Convert path to the native form.
Definition: Path.cpp:521
StringRef getStringForId(uint32_t Id) const
This class represents lattice values for constants.
Definition: AllocatorList.h:23
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
void push_back(const T &Elt)
Definition: SmallVector.h:211
uint8_t * getBufferEnd() const
Returns a pointer to the end of the buffer.
uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize)
Definition: MSFCommon.h:112
uint64_t xxHash64(llvm::StringRef Data)
Definition: xxhash.cpp:71
PDBStringTableBuilder & getStringTableBuilder()
ArrayRef< uint8_t > arrayRefFromStringRef(StringRef Input)
Construct a string ref from an array ref of unsigned chars.
Definition: StringExtras.h:60
Error takeError()
Take ownership of the stored error.
Definition: Error.h:552
void set(StringRef Stream, uint32_t StreamNo)
DbiStreamBuilder & getDbiBuilder()
Error commit(BinaryStreamWriter &Writer) const
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
Definition: ArrayRef.h:450
Error addNamedStream(StringRef Name, StringRef Data)
This represents the &#39;GUID&#39; type from windows.h.
Definition: GUID.h:21
Tagged union holding either a T or a Error.
Definition: CachePruning.h:22
LLVM_NODISCARD bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:126
TpiStreamBuilder & getIpiBuilder()
The header preceding the /src/headerblock stream.
Definition: RawTypes.h:321
support::ulittle32_t Size
Definition: RawTypes.h:332
support::ulittle32_t Version
Definition: RawTypes.h:333
LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:130
support::ulittle32_t BlockSize
Definition: MSFCommon.h:36
support::ulittle32_t FileNI
Definition: RawTypes.h:336
uint8_t Guid[16]
Definition: GUID.h:22
Error commit() override
For buffered streams, commits changes to the backing store.
Error commit(StringRef Filename, codeview::GUID *Guid)
Error initialize(uint32_t BlockSize)
Allocate memory in an ever growing pool, as if by bump-pointer.
Definition: Allocator.h:140
#define H(x, y, z)
Definition: MD5.cpp:57
uint8_t * getBufferStart() const
Returns a pointer to the start of the buffer.
Provides write only access to a subclass of WritableBinaryStream.
support::ulittle32_t VFileNI
Definition: RawTypes.h:338
uint32_t bytesRemaining() const
support::ulittle32_t ObjNI
Definition: RawTypes.h:337
static const int BlockSize
Definition: TarWriter.cpp:33
Basic Register Allocator
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
support::ulittle32_t Size
Definition: RawTypes.h:323
GSIStreamBuilder & getGsiBuilder()
The header preceding the global PDB Stream (Stream 1)
Definition: RawTypes.h:304
InfoStreamBuilder & getInfoBuilder()
support::ulittle32_t Version
Definition: RawTypes.h:322
bool hasValue() const
Definition: Optional.h:259
LLVM_NODISCARD bool empty() const
Definition: SmallVector.h:55
A single file record entry within the /src/headerblock stream.
Definition: RawTypes.h:331
void addInjectedSource(StringRef Name, std::unique_ptr< MemoryBuffer > Buffer)
uint32_t Size
Definition: Profile.cpp:46
std::vector< ArrayRef< support::ulittle32_t > > StreamMap
Definition: MSFCommon.h:68
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition: DenseMap.h:171
bool get(StringRef Stream, uint32_t &StreamNo) const
LLVM_NODISCARD std::string lower() const
Definition: StringRef.cpp:107
msf::MSFBuilder & getMsfBuilder()
support::ulittle32_t CRC
Definition: RawTypes.h:334
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
void update(ArrayRef< char > Data)
Definition: JamCRC.cpp:91
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
An implementation of WritableBinaryStream backed by an llvm FileOutputBuffer.
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
const SuperBlock * SB
Definition: MSFCommon.h:64
support::ulittle32_t FileSize
Definition: RawTypes.h:335
Expected< uint32_t > getNamedStreamIndex(StringRef Name) const
TpiStreamBuilder & getTpiBuilder()
A BinaryStream which can be read from as well as written to.
Definition: BinaryStream.h:73