LCOV - code coverage report
Current view: top level - lib/DebugInfo/PDB/Native - PDBFileBuilder.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 120 168 71.4 %
Date: 2018-06-17 00:07:59 Functions: 16 19 84.2 %
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 : Expected<msf::MSFLayout> 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 std::move(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 std::move(EC);
     154             :   }
     155          90 :   if (Dbi) {
     156         174 :     if (auto EC = Dbi->finalizeMsfLayout())
     157             :       return std::move(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 std::move(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 std::move(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 std::move(EC);
     214             :   }
     215             : 
     216          90 :   return Msf->build();
     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          90 : void PDBFileBuilder::commitFpm(WritableBinaryStream &MsfBuffer,
     227             :                                const MSFLayout &Layout) {
     228             :   auto FpmStream =
     229         180 :       WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator);
     230             : 
     231             :   // We only need to create the alt fpm stream so that it gets initialized.
     232         270 :   WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator,
     233             :                                              true);
     234             : 
     235             :   uint32_t BI = 0;
     236          90 :   BinaryStreamWriter FpmWriter(*FpmStream);
     237         831 :   while (BI < Layout.SB->NumBlocks) {
     238         217 :     uint8_t ThisByte = 0;
     239        3689 :     for (uint32_t I = 0; I < 8; ++I) {
     240             :       bool IsFree =
     241        3194 :           (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI) : true;
     242        1736 :       uint8_t Mask = uint8_t(IsFree) << I;
     243        1736 :       ThisByte |= Mask;
     244        1736 :       ++BI;
     245             :     }
     246         217 :     cantFail(FpmWriter.writeObject(ThisByte));
     247             :   }
     248             :   assert(FpmWriter.bytesRemaining() == 0);
     249          90 : }
     250             : 
     251           0 : void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer,
     252             :                                           const msf::MSFLayout &Layout) {
     253             :   assert(!InjectedSourceTable.empty());
     254             : 
     255           0 :   uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock"));
     256             :   auto Stream = WritableMappedBlockStream::createIndexedStream(
     257           0 :       Layout, MsfBuffer, SN, Allocator);
     258           0 :   BinaryStreamWriter Writer(*Stream);
     259             : 
     260             :   SrcHeaderBlockHeader Header;
     261           0 :   ::memset(&Header, 0, sizeof(Header));
     262             :   Header.Version = static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
     263             :   Header.Size = Writer.bytesRemaining();
     264             : 
     265           0 :   cantFail(Writer.writeObject(Header));
     266           0 :   cantFail(InjectedSourceTable.commit(Writer));
     267             : 
     268             :   assert(Writer.bytesRemaining() == 0);
     269           0 : }
     270             : 
     271          90 : void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer,
     272             :                                            const msf::MSFLayout &Layout) {
     273          90 :   if (InjectedSourceTable.empty())
     274             :     return;
     275             : 
     276           0 :   commitSrcHeaderBlock(MsfBuffer, Layout);
     277             : 
     278           0 :   for (const auto &IS : InjectedSources) {
     279           0 :     uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName));
     280             : 
     281             :     auto SourceStream = WritableMappedBlockStream::createIndexedStream(
     282           0 :         Layout, MsfBuffer, SN, Allocator);
     283           0 :     BinaryStreamWriter SourceWriter(*SourceStream);
     284             :     assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize());
     285           0 :     cantFail(SourceWriter.writeBytes(
     286             :         arrayRefFromStringRef(IS.Content->getBuffer())));
     287             :   }
     288             : }
     289             : 
     290          90 : Error PDBFileBuilder::commit(StringRef Filename) {
     291             :   assert(!Filename.empty());
     292         180 :   auto ExpectedLayout = finalizeMsfLayout();
     293          90 :   if (!ExpectedLayout)
     294             :     return ExpectedLayout.takeError();
     295             :   auto &Layout = *ExpectedLayout;
     296             : 
     297         180 :   uint64_t Filesize = Layout.SB->BlockSize * Layout.SB->NumBlocks;
     298         180 :   auto OutFileOrError = FileOutputBuffer::create(Filename, Filesize);
     299          90 :   if (auto E = OutFileOrError.takeError())
     300             :     return E;
     301             :   FileOutputBuffer *FOB = OutFileOrError->get();
     302             : 
     303             :   FileBufferByteStream Buffer(std::move(*OutFileOrError),
     304         180 :                               llvm::support::little);
     305          90 :   BinaryStreamWriter Writer(Buffer);
     306             : 
     307         180 :   if (auto EC = Writer.writeObject(*Layout.SB))
     308             :     return EC;
     309             : 
     310          90 :   commitFpm(Buffer, Layout);
     311             : 
     312             :   uint32_t BlockMapOffset =
     313         360 :       msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize);
     314             :   Writer.setOffset(BlockMapOffset);
     315         180 :   if (auto EC = Writer.writeArray(Layout.DirectoryBlocks))
     316             :     return EC;
     317             : 
     318             :   auto DirStream = WritableMappedBlockStream::createDirectoryStream(
     319         180 :       Layout, Buffer, Allocator);
     320          90 :   BinaryStreamWriter DW(*DirStream);
     321         180 :   if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size()))
     322             :     return EC;
     323             : 
     324         180 :   if (auto EC = DW.writeArray(Layout.StreamSizes))
     325             :     return EC;
     326             : 
     327        1244 :   for (const auto &Blocks : Layout.StreamMap) {
     328        2308 :     if (auto EC = DW.writeArray(Blocks))
     329             :       return EC;
     330             :   }
     331             : 
     332          90 :   auto ExpectedSN = getNamedStreamIndex("/names");
     333          90 :   if (!ExpectedSN)
     334             :     return ExpectedSN.takeError();
     335             : 
     336             :   auto NS = WritableMappedBlockStream::createIndexedStream(
     337         180 :       Layout, Buffer, *ExpectedSN, Allocator);
     338          90 :   BinaryStreamWriter NSWriter(*NS);
     339         180 :   if (auto EC = Strings.commit(NSWriter))
     340             :     return EC;
     341             : 
     342         180 :   for (const auto &NSE : NamedStreamData) {
     343           0 :     if (NSE.second.empty())
     344           0 :       continue;
     345             : 
     346             :     auto NS = WritableMappedBlockStream::createIndexedStream(
     347           0 :         Layout, Buffer, NSE.first, Allocator);
     348           0 :     BinaryStreamWriter NSW(*NS);
     349           0 :     if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second)))
     350             :       return EC;
     351             :   }
     352             : 
     353          90 :   if (Info) {
     354         270 :     if (auto EC = Info->commit(Layout, Buffer))
     355             :       return EC;
     356             :   }
     357             : 
     358          90 :   if (Dbi) {
     359         261 :     if (auto EC = Dbi->commit(Layout, Buffer))
     360             :       return EC;
     361             :   }
     362             : 
     363          90 :   if (Tpi) {
     364         270 :     if (auto EC = Tpi->commit(Layout, Buffer))
     365             :       return EC;
     366             :   }
     367             : 
     368          90 :   if (Ipi) {
     369         270 :     if (auto EC = Ipi->commit(Layout, Buffer))
     370             :       return EC;
     371             :   }
     372             : 
     373          90 :   if (Gsi) {
     374         207 :     if (auto EC = Gsi->commit(Layout, Buffer))
     375             :       return EC;
     376             :   }
     377             : 
     378          90 :   auto InfoStreamBlocks = Layout.StreamMap[StreamPDB];
     379             :   assert(!InfoStreamBlocks.empty());
     380             :   uint64_t InfoStreamFileOffset =
     381         270 :       blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize);
     382             :   InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>(
     383          90 :       FOB->getBufferStart() + InfoStreamFileOffset);
     384             : 
     385          90 :   commitInjectedSources(Buffer, Layout);
     386             : 
     387             :   // Set the build id at the very end, after every other byte of the PDB
     388             :   // has been written.
     389             :   // FIXME: Use a hash of the PDB rather than time(nullptr) for the signature.
     390          90 :   H->Age = Info->getAge();
     391          90 :   H->Guid = Info->getGuid();
     392             :   Optional<uint32_t> Sig = Info->getSignature();
     393          90 :   H->Signature = Sig.hasValue() ? *Sig : time(nullptr);
     394             : 
     395             :   return Buffer.commit();
     396             : }

Generated by: LCOV version 1.13