PDBFileBuilder.cpp 11 KB

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