LLVM  15.0.0git
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 
24 #include "llvm/Support/CRC.h"
25 #include "llvm/Support/Path.h"
26 #include "llvm/Support/xxhash.h"
27 
28 #include <ctime>
29 
30 using namespace llvm;
31 using namespace llvm::codeview;
32 using namespace llvm::msf;
33 using namespace llvm::pdb;
34 using namespace llvm::support;
35 
36 namespace llvm {
38 }
39 
40 PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
41  : Allocator(Allocator), InjectedSourceHashTraits(Strings),
42  InjectedSourceTable(2) {}
43 
45 
47  auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize);
48  if (!ExpectedMsf)
49  return ExpectedMsf.takeError();
50  Msf = std::make_unique<MSFBuilder>(std::move(*ExpectedMsf));
51  return Error::success();
52 }
53 
55 
57  if (!Info)
58  Info = std::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
59  return *Info;
60 }
61 
63  if (!Dbi)
64  Dbi = std::make_unique<DbiStreamBuilder>(*Msf);
65  return *Dbi;
66 }
67 
69  if (!Tpi)
70  Tpi = std::make_unique<TpiStreamBuilder>(*Msf, StreamTPI);
71  return *Tpi;
72 }
73 
75  if (!Ipi)
76  Ipi = std::make_unique<TpiStreamBuilder>(*Msf, StreamIPI);
77  return *Ipi;
78 }
79 
81  return Strings;
82 }
83 
85  if (!Gsi)
86  Gsi = std::make_unique<GSIStreamBuilder>(*Msf);
87  return *Gsi;
88 }
89 
90 Expected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name,
91  uint32_t Size) {
92  auto ExpectedStream = Msf->addStream(Size);
93  if (ExpectedStream)
94  NamedStreams.set(Name, *ExpectedStream);
95  return ExpectedStream;
96 }
97 
99  Expected<uint32_t> ExpectedIndex = allocateNamedStream(Name, Data.size());
100  if (!ExpectedIndex)
101  return ExpectedIndex.takeError();
102  assert(NamedStreamData.count(*ExpectedIndex) == 0);
103  NamedStreamData[*ExpectedIndex] = std::string(Data);
104  return Error::success();
105 }
106 
108  std::unique_ptr<MemoryBuffer> Buffer) {
109  // Stream names must be exact matches, since they get looked up in a hash
110  // table and the hash value is dependent on the exact contents of the string.
111  // link.exe lowercases a path and converts / to \, so we must do the same.
112  SmallString<64> VName;
114 
116  uint32_t VNI = getStringTableBuilder().insert(VName);
117 
118  InjectedSourceDescriptor Desc;
119  Desc.Content = std::move(Buffer);
120  Desc.NameIndex = NI;
121  Desc.VNameIndex = VNI;
122  Desc.StreamName = "/src/files/";
123 
124  Desc.StreamName += VName;
125 
126  InjectedSources.push_back(std::move(Desc));
127 }
128 
129 Error PDBFileBuilder::finalizeMsfLayout() {
130 
131  if (Ipi && Ipi->getRecordCount() > 0) {
132  // In theory newer PDBs always have an ID stream, but by saying that we're
133  // only going to *really* have an ID stream if there is at least one ID
134  // record, we leave open the opportunity to test older PDBs such as those
135  // that don't have an ID stream.
136  auto &Info = getInfoBuilder();
137  Info.addFeature(PdbRaw_FeatureSig::VC140);
138  }
139 
140  uint32_t StringsLen = Strings.calculateSerializedSize();
141 
142  Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0);
143  if (!SN)
144  return SN.takeError();
145 
146  if (Gsi) {
147  if (auto EC = Gsi->finalizeMsfLayout())
148  return EC;
149  if (Dbi) {
150  Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex());
151  Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex());
152  Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIndex());
153  }
154  }
155  if (Tpi) {
156  if (auto EC = Tpi->finalizeMsfLayout())
157  return EC;
158  }
159  if (Dbi) {
160  if (auto EC = Dbi->finalizeMsfLayout())
161  return EC;
162  }
163  SN = allocateNamedStream("/names", StringsLen);
164  if (!SN)
165  return SN.takeError();
166 
167  if (Ipi) {
168  if (auto EC = Ipi->finalizeMsfLayout())
169  return EC;
170  }
171 
172  // Do this last, since it relies on the named stream map being complete, and
173  // that can be updated by previous steps in the finalization.
174  if (Info) {
175  if (auto EC = Info->finalizeMsfLayout())
176  return EC;
177  }
178 
179  if (!InjectedSources.empty()) {
180  for (const auto &IS : InjectedSources) {
181  JamCRC CRC(0);
182  CRC.update(arrayRefFromStringRef(IS.Content->getBuffer()));
183 
184  SrcHeaderBlockEntry Entry;
185  ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry));
186  Entry.Size = sizeof(SrcHeaderBlockEntry);
187  Entry.FileSize = IS.Content->getBufferSize();
188  Entry.FileNI = IS.NameIndex;
189  Entry.VFileNI = IS.VNameIndex;
190  Entry.ObjNI = 1;
191  Entry.IsVirtual = 0;
192  Entry.Version =
194  Entry.CRC = CRC.getCRC();
195  StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex);
196  InjectedSourceTable.set_as(VName, std::move(Entry),
197  InjectedSourceHashTraits);
198  }
199 
200  uint32_t SrcHeaderBlockSize =
201  sizeof(SrcHeaderBlockHeader) +
202  InjectedSourceTable.calculateSerializedLength();
203  SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize);
204  if (!SN)
205  return SN.takeError();
206  for (const auto &IS : InjectedSources) {
207  SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize());
208  if (!SN)
209  return SN.takeError();
210  }
211  }
212 
213  // Do this last, since it relies on the named stream map being complete, and
214  // that can be updated by previous steps in the finalization.
215  if (Info) {
216  if (auto EC = Info->finalizeMsfLayout())
217  return EC;
218  }
219 
220  return Error::success();
221 }
222 
224  uint32_t SN = 0;
225  if (!NamedStreams.get(Name, SN))
226  return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
227  return SN;
228 }
229 
230 void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer,
231  const msf::MSFLayout &Layout) {
232  assert(!InjectedSourceTable.empty());
233 
234  uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock"));
235  auto Stream = WritableMappedBlockStream::createIndexedStream(
236  Layout, MsfBuffer, SN, Allocator);
237  BinaryStreamWriter Writer(*Stream);
238 
239  SrcHeaderBlockHeader Header;
240  ::memset(&Header, 0, sizeof(Header));
242  Header.Size = Writer.bytesRemaining();
243 
244  cantFail(Writer.writeObject(Header));
245  cantFail(InjectedSourceTable.commit(Writer));
246 
247  assert(Writer.bytesRemaining() == 0);
248 }
249 
250 void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer,
251  const msf::MSFLayout &Layout) {
252  if (InjectedSourceTable.empty())
253  return;
254 
255  commitSrcHeaderBlock(MsfBuffer, Layout);
256 
257  for (const auto &IS : InjectedSources) {
258  uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName));
259 
260  auto SourceStream = WritableMappedBlockStream::createIndexedStream(
261  Layout, MsfBuffer, SN, Allocator);
262  BinaryStreamWriter SourceWriter(*SourceStream);
263  assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize());
264  cantFail(SourceWriter.writeBytes(
265  arrayRefFromStringRef(IS.Content->getBuffer())));
266  }
267 }
268 
270  assert(!Filename.empty());
271  if (auto EC = finalizeMsfLayout())
272  return EC;
273 
274  MSFLayout Layout;
275  Expected<FileBufferByteStream> ExpectedMsfBuffer =
276  Msf->commit(Filename, Layout);
277  if (!ExpectedMsfBuffer)
278  return ExpectedMsfBuffer.takeError();
279  FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer);
280 
281  auto ExpectedSN = getNamedStreamIndex("/names");
282  if (!ExpectedSN)
283  return ExpectedSN.takeError();
284 
285  auto NS = WritableMappedBlockStream::createIndexedStream(
286  Layout, Buffer, *ExpectedSN, Allocator);
287  BinaryStreamWriter NSWriter(*NS);
288  if (auto EC = Strings.commit(NSWriter))
289  return EC;
290 
291  for (const auto &NSE : NamedStreamData) {
292  if (NSE.second.empty())
293  continue;
294 
295  auto NS = WritableMappedBlockStream::createIndexedStream(
296  Layout, Buffer, NSE.first, Allocator);
297  BinaryStreamWriter NSW(*NS);
298  if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second)))
299  return EC;
300  }
301 
302  if (Info) {
303  if (auto EC = Info->commit(Layout, Buffer))
304  return EC;
305  }
306 
307  if (Dbi) {
308  if (auto EC = Dbi->commit(Layout, Buffer))
309  return EC;
310  }
311 
312  if (Tpi) {
313  if (auto EC = Tpi->commit(Layout, Buffer))
314  return EC;
315  }
316 
317  if (Ipi) {
318  if (auto EC = Ipi->commit(Layout, Buffer))
319  return EC;
320  }
321 
322  if (Gsi) {
323  if (auto EC = Gsi->commit(Layout, Buffer))
324  return EC;
325  }
326 
327  auto InfoStreamBlocks = Layout.StreamMap[StreamPDB];
328  assert(!InfoStreamBlocks.empty());
329  uint64_t InfoStreamFileOffset =
330  blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize);
331  InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>(
332  Buffer.getBufferStart() + InfoStreamFileOffset);
333 
334  commitInjectedSources(Buffer, Layout);
335 
336  // Set the build id at the very end, after every other byte of the PDB
337  // has been written.
338  if (Info->hashPDBContentsToGUID()) {
339  // Compute a hash of all sections of the output file.
340  uint64_t Digest =
341  xxHash64({Buffer.getBufferStart(), Buffer.getBufferEnd()});
342 
343  H->Age = 1;
344 
345  memcpy(H->Guid.Guid, &Digest, 8);
346  // xxhash only gives us 8 bytes, so put some fixed data in the other half.
347  memcpy(H->Guid.Guid + 8, "LLD PDB.", 8);
348 
349  // Put the hash in the Signature field too.
350  H->Signature = static_cast<uint32_t>(Digest);
351 
352  // Return GUID to caller.
353  memcpy(Guid, H->Guid.Guid, 16);
354  } else {
355  H->Age = Info->getAge();
356  H->Guid = Info->getGuid();
357  Optional<uint32_t> Sig = Info->getSignature();
358  H->Signature = Sig ? *Sig : time(nullptr);
359  }
360 
361  return Buffer.commit();
362 }
llvm::Check::Size
@ Size
Definition: FileCheck.h:77
llvm::pdb::NamedStreamMap::set
void set(StringRef Stream, uint32_t StreamNo)
Definition: NamedStreamMap.cpp:122
llvm::pdb::raw_error_code::no_stream
@ no_stream
RawConstants.h
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
GUID.h
BlockSize
static const int BlockSize
Definition: TarWriter.cpp:33
llvm::pdb::PDBStringTableBuilder::getStringForId
StringRef getStringForId(uint32_t Id) const
Definition: PDBStringTableBuilder.cpp:54
llvm::pdb::SrcHeaderBlockEntry::VFileNI
support::ulittle32_t VFileNI
Definition: RawTypes.h:338
llvm::pdb::PDBFileBuilder::getInfoBuilder
InfoStreamBuilder & getInfoBuilder()
Definition: PDBFileBuilder.cpp:56
RawTypes.h
llvm::BinaryStreamWriter
Provides write only access to a subclass of WritableBinaryStream.
Definition: BinaryStreamWriter.h:30
Path.h
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:329
llvm::msf::blockToOffset
uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize)
Definition: MSFCommon.h:135
llvm::codeview::GUID
This represents the 'GUID' type from windows.h.
Definition: GUID.h:21
llvm::sys::path::native
void native(const Twine &path, SmallVectorImpl< char > &result, Style style=Style::native)
Convert path to the native form.
Definition: Path.cpp:540
llvm::Optional< uint32_t >
llvm::DenseMapBase::count
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:147
GSIStreamBuilder.h
llvm::sys::path::Style::windows_backslash
@ windows_backslash
llvm::JamCRC
Definition: CRC.h:45
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:41
llvm::pdb::PDBFileBuilder::getStringTableBuilder
PDBStringTableBuilder & getStringTableBuilder()
Definition: PDBFileBuilder.cpp:80
RawError.h
llvm::pdb::PDBFileBuilder::getMsfBuilder
msf::MSFBuilder & getMsfBuilder()
Definition: PDBFileBuilder.cpp:54
llvm::Data
@ Data
Definition: SIMachineScheduler.h:55
llvm::pdb::PdbRaw_SrcHeaderBlockVer::SrcVerOne
@ SrcVerOne
llvm::msf
Definition: IMSFFile.h:18
llvm::pdb::PDBStringTableBuilder::commit
Error commit(BinaryStreamWriter &Writer) const
Definition: PDBStringTableBuilder.cpp:209
llvm::msf::MSFBuilder
Definition: MSFBuilder.h:27
llvm::pdb::HashTable::commit
Error commit(BinaryStreamWriter &Writer) const
Definition: HashTable.h:180
llvm::pdb::PDBStringTableBuilder::insert
uint32_t insert(StringRef S)
Definition: PDBStringTableBuilder.cpp:46
llvm::pdb::StreamTPI
@ StreamTPI
Definition: RawConstants.h:79
llvm::pdb::SrcHeaderBlockHeader
The header preceding the /src/headerblock stream.
Definition: RawTypes.h:321
llvm::pdb::PDBFileBuilder::commit
Error commit(StringRef Filename, codeview::GUID *Guid)
Definition: PDBFileBuilder.cpp:269
llvm::pdb::PDBFileBuilder::addNamedStream
Error addNamedStream(StringRef Name, StringRef Data)
Definition: PDBFileBuilder.cpp:98
llvm::pdb::DbiStreamBuilder
Definition: DbiStreamBuilder.h:41
llvm::msf::MSFLayout
Definition: MSFCommon.h:51
PDBFileBuilder.h
llvm::pdb::PDBFileBuilder::getDbiBuilder
DbiStreamBuilder & getDbiBuilder()
Definition: PDBFileBuilder.cpp:62
llvm::pdb::InfoStreamHeader
The header preceding the global PDB Stream (Stream 1)
Definition: RawTypes.h:304
CRC.h
llvm::pdb::HashTable::calculateSerializedLength
uint32_t calculateSerializedLength() const
Definition: HashTable.h:153
llvm::pdb::InfoStreamBuilder
Definition: InfoStreamBuilder.h:28
Info
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
MSFBuilder.h
CodeView.h
llvm::pdb::PDBFileBuilder::~PDBFileBuilder
~PDBFileBuilder()
llvm::pdb::PDBFileBuilder::getNamedStreamIndex
Expected< uint32_t > getNamedStreamIndex(StringRef Name) const
Definition: PDBFileBuilder.cpp:223
llvm::SmallString< 64 >
llvm::pdb::PDBFileBuilder::getGsiBuilder
GSIStreamBuilder & getGsiBuilder()
Definition: PDBFileBuilder.cpp:84
llvm::pdb
Definition: ConcreteSymbolEnumerator.h:20
llvm::pdb::HashTable::set_as
bool set_as(const Key &K, ValueT V, TraitsT &Traits)
Set the entry using a key type that the specified Traits can convert from a real key to an internal k...
Definition: HashTable.h:250
llvm::pdb::SrcHeaderBlockEntry::CRC
support::ulittle32_t CRC
Definition: RawTypes.h:334
llvm::pdb::SrcHeaderBlockHeader::Size
support::ulittle32_t Size
Definition: RawTypes.h:323
llvm::pdb::GSIStreamBuilder
Definition: GSIStreamBuilder.h:46
llvm::StringRef::empty
constexpr LLVM_NODISCARD bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:153
uint64_t
llvm::BumpPtrAllocatorImpl
Allocate memory in an ever growing pool, as if by bump-pointer.
Definition: Allocator.h:63
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::pdb::NamedStreamMap::get
bool get(StringRef Stream, uint32_t &StreamNo) const
Definition: NamedStreamMap.cpp:98
llvm::pdb::PdbRaw_FeatureSig::VC140
@ VC140
llvm::pdb::TpiStreamBuilder
Definition: TpiStreamBuilder.h:40
MappedBlockStream.h
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::pdb::SrcHeaderBlockEntry::ObjNI
support::ulittle32_t ObjNI
Definition: RawTypes.h:337
TpiStreamBuilder.h
memcpy
<%struct.s * > cast struct s *S to sbyte *< sbyte * > sbyte uint cast struct s *agg result to sbyte *< sbyte * > sbyte uint cast struct s *memtmp to sbyte *< sbyte * > sbyte uint ret void llc ends up issuing two memcpy or custom lower memcpy(of small size) to be ldmia/stmia. I think option 2 is better but the current register allocator cannot allocate a chunk of registers at a time. A feasible temporary solution is to use specific physical registers at the lowering time for small(<
llvm::codeview::CompileSym2Flags::EC
@ EC
llvm::pdb::SrcHeaderBlockEntry::FileSize
support::ulittle32_t FileSize
Definition: RawTypes.h:335
xxhash.h
llvm::BinaryStreamWriter::writeBytes
Error writeBytes(ArrayRef< uint8_t > Buffer)
Write the bytes specified in Buffer to the underlying stream.
Definition: BinaryStreamWriter.cpp:27
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
DbiStreamBuilder.h
llvm::cantFail
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Definition: Error.h:745
uint32_t
MSFCommon.h
llvm::pdb::PDBStringTableBuilder::calculateSerializedSize
uint32_t calculateSerializedSize() const
Definition: PDBStringTableBuilder.cpp:140
llvm::pdb::PDBFileBuilder::initialize
Error initialize(uint32_t BlockSize)
Definition: PDBFileBuilder.cpp:46
llvm::pdb::PDBFileBuilder::getTpiBuilder
TpiStreamBuilder & getTpiBuilder()
Definition: PDBFileBuilder.cpp:68
llvm::FileBufferByteStream::commit
Error commit() override
For buffered streams, commits changes to the backing store.
Definition: BinaryByteStream.h:258
llvm::FileBufferByteStream
An implementation of WritableBinaryStream backed by an llvm FileOutputBuffer.
Definition: BinaryByteStream.h:204
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:50
llvm::msf::SuperBlock::BlockSize
support::ulittle32_t BlockSize
Definition: MSFCommon.h:36
H
#define H(x, y, z)
Definition: MD5.cpp:57
llvm::pdb::HashTable::empty
bool empty() const
Definition: HashTable.h:208
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:155
llvm::support
Definition: Endian.h:25
llvm::pdb::SrcHeaderBlockEntry
A single file record entry within the /src/headerblock stream.
Definition: RawTypes.h:331
llvm::FileBufferByteStream::getBufferEnd
uint8_t * getBufferEnd() const
Returns a pointer to the end of the buffer.
Definition: BinaryByteStream.h:264
llvm::msf::MSFLayout::StreamMap
std::vector< ArrayRef< support::ulittle32_t > > StreamMap
Definition: MSFCommon.h:68
PDBStringTableBuilder.h
llvm::pdb::SrcHeaderBlockEntry::IsVirtual
uint8_t IsVirtual
Definition: RawTypes.h:340
llvm::codeview
Definition: AppendingTypeTableBuilder.h:22
llvm::Expected::takeError
Error takeError()
Take ownership of the stored error.
Definition: Error.h:597
llvm::pdb::SrcHeaderBlockHeader::Version
support::ulittle32_t Version
Definition: RawTypes.h:322
Allocator
Basic Register Allocator
Definition: RegAllocBasic.cpp:142
llvm::FileBufferByteStream::getBufferStart
uint8_t * getBufferStart() const
Returns a pointer to the start of the buffer.
Definition: BinaryByteStream.h:261
llvm::pdb::StreamPDB
@ StreamPDB
Definition: RawConstants.h:78
llvm::pdb::SrcHeaderBlockEntry::FileNI
support::ulittle32_t FileNI
Definition: RawTypes.h:336
llvm::msf::MSFLayout::SB
const SuperBlock * SB
Definition: MSFCommon.h:64
BinaryStreamWriter.h
llvm::pdb::PDBStringTableBuilder
Definition: PDBStringTableBuilder.h:43
llvm::WritableBinaryStream
A BinaryStream which can be read from as well as written to.
Definition: BinaryStream.h:73
llvm::pdb::SrcHeaderBlockEntry::Size
support::ulittle32_t Size
Definition: RawTypes.h:332
llvm::pdb::SrcHeaderBlockEntry::Version
support::ulittle32_t Version
Definition: RawTypes.h:333
llvm::xxHash64
uint64_t xxHash64(llvm::StringRef Data)
Definition: xxhash.cpp:70
llvm::pdb::PDBFileBuilder::getIpiBuilder
TpiStreamBuilder & getIpiBuilder()
Definition: PDBFileBuilder.cpp:74
InfoStreamBuilder.h
llvm::pdb::PDBFileBuilder::addInjectedSource
void addInjectedSource(StringRef Name, std::unique_ptr< MemoryBuffer > Buffer)
Definition: PDBFileBuilder.cpp:107
llvm::pdb::StreamIPI
@ StreamIPI
Definition: RawConstants.h:81