LCOV - code coverage report
Current view: top level - lib/DebugInfo/PDB/Native - PDBFileBuilder.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 101 149 67.8 %
Date: 2018-10-20 13:21:21 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/Native/DbiStream.h"
      16             : #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
      17             : #include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
      18             : #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
      19             : #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
      20             : #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
      21             : #include "llvm/DebugInfo/PDB/Native/RawError.h"
      22             : #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
      23             : #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
      24             : #include "llvm/Support/BinaryStream.h"
      25             : #include "llvm/Support/BinaryStreamWriter.h"
      26             : #include "llvm/Support/JamCRC.h"
      27             : #include "llvm/Support/Path.h"
      28             : #include "llvm/Support/xxhash.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         111 : PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
      37         111 :     : Allocator(Allocator), InjectedSourceHashTraits(Strings),
      38         222 :       InjectedSourceTable(2, InjectedSourceHashTraits) {}
      39             : 
      40         444 : PDBFileBuilder::~PDBFileBuilder() {}
      41             : 
      42         111 : Error PDBFileBuilder::initialize(uint32_t BlockSize) {
      43         222 :   auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize);
      44         111 :   if (!ExpectedMsf)
      45             :     return ExpectedMsf.takeError();
      46         111 :   Msf = llvm::make_unique<MSFBuilder>(std::move(*ExpectedMsf));
      47             :   return Error::success();
      48             : }
      49             : 
      50        1110 : MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
      51             : 
      52         152 : InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
      53         152 :   if (!Info)
      54         111 :     Info = llvm::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
      55         152 :   return *Info;
      56             : }
      57             : 
      58        1038 : DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
      59        1038 :   if (!Dbi)
      60         108 :     Dbi = llvm::make_unique<DbiStreamBuilder>(*Msf);
      61        1038 :   return *Dbi;
      62             : }
      63             : 
      64         111 : TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() {
      65         111 :   if (!Tpi)
      66         111 :     Tpi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamTPI);
      67         111 :   return *Tpi;
      68             : }
      69             : 
      70         111 : TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() {
      71         111 :   if (!Ipi)
      72         111 :     Ipi = llvm::make_unique<TpiStreamBuilder>(*Msf, StreamIPI);
      73         111 :   return *Ipi;
      74             : }
      75             : 
      76         108 : PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() {
      77         108 :   return Strings;
      78             : }
      79             : 
      80         282 : GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() {
      81         282 :   if (!Gsi)
      82          88 :     Gsi = llvm::make_unique<GSIStreamBuilder>(*Msf);
      83         282 :   return *Gsi;
      84             : }
      85             : 
      86         222 : Expected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name,
      87             :                                                        uint32_t Size) {
      88         222 :   auto ExpectedStream = Msf->addStream(Size);
      89         222 :   if (ExpectedStream)
      90         222 :     NamedStreams.set(Name, *ExpectedStream);
      91         222 :   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         111 : Error PDBFileBuilder::finalizeMsfLayout() {
     126             : 
     127         111 :   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          41 :     auto &Info = getInfoBuilder();
     133          41 :     Info.addFeature(PdbRaw_FeatureSig::VC140);
     134             :   }
     135             : 
     136         111 :   uint32_t StringsLen = Strings.calculateSerializedSize();
     137             : 
     138         111 :   Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0);
     139         111 :   if (!SN)
     140             :     return SN.takeError();
     141             : 
     142         111 :   if (Gsi) {
     143         176 :     if (auto EC = Gsi->finalizeMsfLayout())
     144             :       return EC;
     145          88 :     if (Dbi) {
     146          88 :       Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex());
     147          88 :       Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex());
     148          88 :       Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIdx());
     149             :     }
     150             :   }
     151         111 :   if (Tpi) {
     152         222 :     if (auto EC = Tpi->finalizeMsfLayout())
     153             :       return EC;
     154             :   }
     155         111 :   if (Dbi) {
     156         216 :     if (auto EC = Dbi->finalizeMsfLayout())
     157             :       return EC;
     158             :   }
     159         222 :   SN = allocateNamedStream("/names", StringsLen);
     160         111 :   if (!SN)
     161             :     return SN.takeError();
     162             : 
     163         111 :   if (Ipi) {
     164         222 :     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         111 :   if (Info) {
     171         222 :     if (auto EC = Info->finalizeMsfLayout())
     172             :       return EC;
     173             :   }
     174             : 
     175         111 :   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           0 :       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         111 :   if (Info) {
     212         222 :     if (auto EC = Info->finalizeMsfLayout())
     213             :       return EC;
     214             :   }
     215             : 
     216             :   return Error::success();
     217             : }
     218             : 
     219         111 : Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
     220         111 :   uint32_t SN = 0;
     221         111 :   if (!NamedStreams.get(Name, SN))
     222             :     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         111 : void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer,
     247             :                                            const msf::MSFLayout &Layout) {
     248         111 :   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         111 : Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) {
     266             :   assert(!Filename.empty());
     267         222 :   if (auto EC = finalizeMsfLayout())
     268             :     return EC;
     269             : 
     270         111 :   MSFLayout Layout;
     271             :   Expected<FileBufferByteStream> ExpectedMsfBuffer =
     272         222 :       Msf->commit(Filename, Layout);
     273         111 :   if (!ExpectedMsfBuffer)
     274             :     return ExpectedMsfBuffer.takeError();
     275             :   FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer);
     276             : 
     277         111 :   auto ExpectedSN = getNamedStreamIndex("/names");
     278         111 :   if (!ExpectedSN)
     279             :     return ExpectedSN.takeError();
     280             : 
     281             :   auto NS = WritableMappedBlockStream::createIndexedStream(
     282         222 :       Layout, Buffer, *ExpectedSN, Allocator);
     283         111 :   BinaryStreamWriter NSWriter(*NS);
     284         222 :   if (auto EC = Strings.commit(NSWriter))
     285             :     return EC;
     286             : 
     287         111 :   for (const auto &NSE : NamedStreamData) {
     288           0 :     if (NSE.second.empty())
     289           0 :       continue;
     290             : 
     291             :     auto NS = WritableMappedBlockStream::createIndexedStream(
     292           0 :         Layout, Buffer, NSE.first, Allocator);
     293           0 :     BinaryStreamWriter NSW(*NS);
     294           0 :     if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second)))
     295             :       return EC;
     296             :   }
     297             : 
     298         111 :   if (Info) {
     299         222 :     if (auto EC = Info->commit(Layout, Buffer))
     300             :       return EC;
     301             :   }
     302             : 
     303         111 :   if (Dbi) {
     304         216 :     if (auto EC = Dbi->commit(Layout, Buffer))
     305             :       return EC;
     306             :   }
     307             : 
     308         111 :   if (Tpi) {
     309         222 :     if (auto EC = Tpi->commit(Layout, Buffer))
     310             :       return EC;
     311             :   }
     312             : 
     313         111 :   if (Ipi) {
     314         222 :     if (auto EC = Ipi->commit(Layout, Buffer))
     315             :       return EC;
     316             :   }
     317             : 
     318         111 :   if (Gsi) {
     319         176 :     if (auto EC = Gsi->commit(Layout, Buffer))
     320             :       return EC;
     321             :   }
     322             : 
     323         111 :   auto InfoStreamBlocks = Layout.StreamMap[StreamPDB];
     324             :   assert(!InfoStreamBlocks.empty());
     325             :   uint64_t InfoStreamFileOffset =
     326         333 :       blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize);
     327             :   InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>(
     328         111 :       Buffer.getBufferStart() + InfoStreamFileOffset);
     329             : 
     330         111 :   commitInjectedSources(Buffer, Layout);
     331             : 
     332             :   // Set the build id at the very end, after every other byte of the PDB
     333             :   // has been written.
     334         111 :   if (Info->hashPDBContentsToGUID()) {
     335             :     // Compute a hash of all sections of the output file.
     336             :     uint64_t Digest =
     337          88 :         xxHash64({Buffer.getBufferStart(), Buffer.getBufferEnd()});
     338             : 
     339             :     H->Age = 1;
     340             : 
     341          88 :     memcpy(H->Guid.Guid, &Digest, 8);
     342             :     // xxhash only gives us 8 bytes, so put some fixed data in the other half.
     343          88 :     memcpy(H->Guid.Guid + 8, "LLD PDB.", 8);
     344             : 
     345             :     // Put the hash in the Signature field too.
     346          88 :     H->Signature = static_cast<uint32_t>(Digest);
     347             : 
     348             :     // Return GUID to caller.
     349          88 :     memcpy(Guid, H->Guid.Guid, 16);
     350             :   } else {
     351          23 :     H->Age = Info->getAge();
     352          23 :     H->Guid = Info->getGuid();
     353             :     Optional<uint32_t> Sig = Info->getSignature();
     354          23 :     H->Signature = Sig.hasValue() ? *Sig : time(nullptr);
     355             :   }
     356             : 
     357             :   return Buffer.commit();
     358             : }

Generated by: LCOV version 1.13