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