LCOV - code coverage report
Current view: top level - lib/DebugInfo/PDB/Native - PDBFileBuilder.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 93 141 66.0 %
Date: 2018-07-13 00:08:38 Functions: 15 18 83.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13