LCOV - code coverage report
Current view: top level - lib/DebugInfo/PDB/Native - GSIStreamBuilder.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 153 174 87.9 %
Date: 2017-09-14 15:23:50 Functions: 24 30 80.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- DbiStreamBuilder.cpp - PDB Dbi Stream 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/GSIStreamBuilder.h"
      11             : 
      12             : #include "llvm/DebugInfo/CodeView/RecordName.h"
      13             : #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
      14             : #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
      15             : #include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
      16             : #include "llvm/DebugInfo/MSF/MSFBuilder.h"
      17             : #include "llvm/DebugInfo/MSF/MSFCommon.h"
      18             : #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
      19             : #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
      20             : #include "llvm/DebugInfo/PDB/Native/Hash.h"
      21             : #include "llvm/Support/BinaryItemStream.h"
      22             : #include "llvm/Support/BinaryStreamWriter.h"
      23             : #include <algorithm>
      24             : #include <vector>
      25             : 
      26             : using namespace llvm;
      27             : using namespace llvm::msf;
      28             : using namespace llvm::pdb;
      29             : using namespace llvm::codeview;
      30             : 
      31         640 : struct llvm::pdb::GSIHashStreamBuilder {
      32             :   std::vector<CVSymbol> Records;
      33             :   uint32_t StreamIndex;
      34             :   std::vector<PSHashRecord> HashRecords;
      35             :   std::array<support::ulittle32_t, (IPHR_HASH + 32) / 32> HashBitmap;
      36             :   std::vector<support::ulittle32_t> HashBuckets;
      37             : 
      38             :   uint32_t calculateSerializedLength() const;
      39             :   uint32_t calculateRecordByteSize() const;
      40             :   Error commit(BinaryStreamWriter &Writer);
      41             :   void finalizeBuckets(uint32_t RecordZeroOffset);
      42             : 
      43         126 :   template <typename T> void addSymbol(const T &Symbol, MSFBuilder &Msf) {
      44         126 :     T Copy(Symbol);
      45         378 :     Records.push_back(SymbolSerializer::writeOneSymbol(Copy, Msf.getAllocator(),
      46             :                                                        CodeViewContainer::Pdb));
      47         126 :   }
      48          14 :   void addSymbol(const CVSymbol &Symbol) { Records.push_back(Symbol); }
      49             : };
      50             : 
      51         120 : uint32_t GSIHashStreamBuilder::calculateSerializedLength() const {
      52         120 :   uint32_t Size = sizeof(GSIHashHeader);
      53         240 :   Size += HashRecords.size() * sizeof(PSHashRecord);
      54         120 :   Size += HashBitmap.size() * sizeof(uint32_t);
      55         240 :   Size += HashBuckets.size() * sizeof(uint32_t);
      56         120 :   return Size;
      57             : }
      58             : 
      59         120 : uint32_t GSIHashStreamBuilder::calculateRecordByteSize() const {
      60         120 :   uint32_t Size = 0;
      61         709 :   for (const auto &Sym : Records)
      62         229 :     Size += Sym.length();
      63         120 :   return Size;
      64             : }
      65             : 
      66          80 : Error GSIHashStreamBuilder::commit(BinaryStreamWriter &Writer) {
      67             :   GSIHashHeader Header;
      68          80 :   Header.VerSignature = GSIHashHeader::HdrSignature;
      69          80 :   Header.VerHdr = GSIHashHeader::HdrVersion;
      70         240 :   Header.HrSize = HashRecords.size() * sizeof(PSHashRecord);
      71         240 :   Header.NumBuckets = HashBitmap.size() * 4 + HashBuckets.size() * 4;
      72             : 
      73         240 :   if (auto EC = Writer.writeObject(Header))
      74           0 :     return EC;
      75             : 
      76         320 :   if (auto EC = Writer.writeArray(makeArrayRef(HashRecords)))
      77           0 :     return EC;
      78         320 :   if (auto EC = Writer.writeArray(makeArrayRef(HashBitmap)))
      79           0 :     return EC;
      80         320 :   if (auto EC = Writer.writeArray(makeArrayRef(HashBuckets)))
      81           0 :     return EC;
      82         240 :   return Error::success();
      83             : }
      84             : 
      85          80 : void GSIHashStreamBuilder::finalizeBuckets(uint32_t RecordZeroOffset) {
      86         160 :   std::array<std::vector<PSHashRecord>, IPHR_HASH + 1> TmpBuckets;
      87          80 :   uint32_t SymOffset = RecordZeroOffset;
      88         460 :   for (const CVSymbol &Sym : Records) {
      89             :     PSHashRecord HR;
      90             :     // Add one when writing symbol offsets to disk. See GSI1::fixSymRecs.
      91         280 :     HR.Off = SymOffset + 1;
      92         140 :     HR.CRef = 1; // Always use a refcount of 1.
      93             : 
      94             :     // Hash the name to figure out which bucket this goes into.
      95         280 :     StringRef Name = getSymbolName(Sym);
      96         140 :     size_t BucketIdx = hashStringV1(Name) % IPHR_HASH;
      97         140 :     TmpBuckets[BucketIdx].push_back(HR); // FIXME: Does order matter?
      98             : 
      99         140 :     SymOffset += Sym.length();
     100             :   }
     101             : 
     102             :   // Compute the three tables: the hash records in bucket and chain order, the
     103             :   // bucket presence bitmap, and the bucket chain start offsets.
     104         160 :   HashRecords.reserve(Records.size());
     105       10560 :   for (ulittle32_t &Word : HashBitmap)
     106       10320 :     Word = 0;
     107      655600 :   for (size_t BucketIdx = 0; BucketIdx < IPHR_HASH + 1; ++BucketIdx) {
     108      327760 :     auto &Bucket = TmpBuckets[BucketIdx];
     109      327760 :     if (Bucket.empty())
     110      327642 :       continue;
     111         354 :     HashBitmap[BucketIdx / 32] |= 1U << (BucketIdx % 32);
     112             : 
     113             :     // Calculate what the offset of the first hash record in the chain would
     114             :     // be if it were inflated to contain 32-bit pointers. On a 32-bit system,
     115             :     // each record would be 12 bytes. See HROffsetCalc in gsi.h.
     116         118 :     const int SizeOfHROffsetCalc = 12;
     117             :     ulittle32_t ChainStartOff =
     118         354 :         ulittle32_t(HashRecords.size() * SizeOfHROffsetCalc);
     119         118 :     HashBuckets.push_back(ChainStartOff);
     120         612 :     for (const auto &HR : Bucket)
     121         140 :       HashRecords.push_back(HR);
     122             :   }
     123          80 : }
     124             : 
     125          40 : GSIStreamBuilder::GSIStreamBuilder(msf::MSFBuilder &Msf)
     126             :     : Msf(Msf), PSH(llvm::make_unique<GSIHashStreamBuilder>()),
     127          40 :       GSH(llvm::make_unique<GSIHashStreamBuilder>()) {}
     128             : 
     129          40 : GSIStreamBuilder::~GSIStreamBuilder() {}
     130             : 
     131          40 : uint32_t GSIStreamBuilder::calculatePublicsHashStreamSize() const {
     132          40 :   uint32_t Size = 0;
     133          40 :   Size += sizeof(PublicsStreamHeader);
     134          80 :   Size += PSH->calculateSerializedLength();
     135         120 :   Size += PSH->Records.size() * sizeof(uint32_t); // AddrMap
     136             :   // FIXME: Add thunk map and section offsets for incremental linking.
     137             : 
     138          40 :   return Size;
     139             : }
     140             : 
     141          40 : uint32_t GSIStreamBuilder::calculateGlobalsHashStreamSize() const {
     142          80 :   return GSH->calculateSerializedLength();
     143             : }
     144             : 
     145          40 : Error GSIStreamBuilder::finalizeMsfLayout() {
     146             :   // First we write public symbol records, then we write global symbol records.
     147          40 :   uint32_t PSHZero = 0;
     148          80 :   uint32_t GSHZero = PSH->calculateRecordByteSize();
     149             : 
     150          80 :   PSH->finalizeBuckets(PSHZero);
     151          80 :   GSH->finalizeBuckets(GSHZero);
     152             : 
     153          80 :   Expected<uint32_t> Idx = Msf.addStream(calculatePublicsHashStreamSize());
     154          40 :   if (!Idx)
     155             :     return Idx.takeError();
     156          80 :   PSH->StreamIndex = *Idx;
     157         120 :   Idx = Msf.addStream(calculateGlobalsHashStreamSize());
     158          40 :   if (!Idx)
     159             :     return Idx.takeError();
     160          80 :   GSH->StreamIndex = *Idx;
     161             : 
     162             :   uint32_t RecordBytes =
     163         120 :       GSH->calculateRecordByteSize() + PSH->calculateRecordByteSize();
     164             : 
     165         120 :   Idx = Msf.addStream(RecordBytes);
     166          40 :   if (!Idx)
     167             :     return Idx.takeError();
     168          40 :   RecordStreamIdx = *Idx;
     169         120 :   return Error::success();
     170             : }
     171             : 
     172          86 : static bool comparePubSymByAddrAndName(
     173             :     const std::pair<const CVSymbol *, const PublicSym32 *> &LS,
     174             :     const std::pair<const CVSymbol *, const PublicSym32 *> &RS) {
     175          86 :   if (LS.second->Segment != RS.second->Segment)
     176          35 :     return LS.second->Segment < RS.second->Segment;
     177          51 :   if (LS.second->Offset != RS.second->Offset)
     178          49 :     return LS.second->Offset < RS.second->Offset;
     179             : 
     180           2 :   return LS.second->Name < RS.second->Name;
     181             : }
     182             : 
     183             : /// Compute the address map. The address map is an array of symbol offsets
     184             : /// sorted so that it can be binary searched by address.
     185          40 : static std::vector<ulittle32_t> computeAddrMap(ArrayRef<CVSymbol> Records) {
     186             :   // Make a vector of pointers to the symbols so we can sort it by address.
     187             :   // Also gather the symbol offsets while we're at it.
     188             : 
     189          80 :   std::vector<PublicSym32> DeserializedPublics;
     190          80 :   std::vector<std::pair<const CVSymbol *, const PublicSym32 *>> PublicsByAddr;
     191          80 :   std::vector<uint32_t> SymOffsets;
     192          40 :   DeserializedPublics.reserve(Records.size());
     193          40 :   PublicsByAddr.reserve(Records.size());
     194          40 :   SymOffsets.reserve(Records.size());
     195             : 
     196          40 :   uint32_t SymOffset = 0;
     197         169 :   for (const CVSymbol &Sym : Records) {
     198             :     assert(Sym.kind() == SymbolKind::S_PUB32);
     199          89 :     DeserializedPublics.push_back(
     200         445 :         cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(Sym)));
     201          89 :     PublicsByAddr.emplace_back(&Sym, &DeserializedPublics.back());
     202          89 :     SymOffsets.push_back(SymOffset);
     203          89 :     SymOffset += Sym.length();
     204             :   }
     205         120 :   std::stable_sort(PublicsByAddr.begin(), PublicsByAddr.end(),
     206             :                    comparePubSymByAddrAndName);
     207             : 
     208             :   // Fill in the symbol offsets in the appropriate order.
     209          40 :   std::vector<ulittle32_t> AddrMap;
     210          40 :   AddrMap.reserve(Records.size());
     211         249 :   for (auto &Sym : PublicsByAddr) {
     212         178 :     ptrdiff_t Idx = std::distance(Records.data(), Sym.first);
     213             :     assert(Idx >= 0 && size_t(Idx) < Records.size());
     214         356 :     AddrMap.push_back(ulittle32_t(SymOffsets[Idx]));
     215             :   }
     216          40 :   return AddrMap;
     217             : }
     218             : 
     219          80 : uint32_t GSIStreamBuilder::getPublicsStreamIndex() const {
     220         160 :   return PSH->StreamIndex;
     221             : }
     222             : 
     223          80 : uint32_t GSIStreamBuilder::getGlobalsStreamIndex() const {
     224         160 :   return GSH->StreamIndex;
     225             : }
     226             : 
     227          89 : void GSIStreamBuilder::addPublicSymbol(const PublicSym32 &Pub) {
     228         178 :   PSH->addSymbol(Pub, Msf);
     229          89 : }
     230             : 
     231          37 : void GSIStreamBuilder::addGlobalSymbol(const ProcRefSym &Sym) {
     232          74 :   GSH->addSymbol(Sym, Msf);
     233          37 : }
     234             : 
     235           0 : void GSIStreamBuilder::addGlobalSymbol(const DataSym &Sym) {
     236           0 :   GSH->addSymbol(Sym, Msf);
     237           0 : }
     238             : 
     239           0 : void GSIStreamBuilder::addGlobalSymbol(const ConstantSym &Sym) {
     240           0 :   GSH->addSymbol(Sym, Msf);
     241           0 : }
     242             : 
     243           0 : void GSIStreamBuilder::addGlobalSymbol(const UDTSym &Sym) {
     244           0 :   GSH->addSymbol(Sym, Msf);
     245           0 : }
     246             : 
     247          14 : void GSIStreamBuilder::addGlobalSymbol(const codeview::CVSymbol &Sym) {
     248          42 :   GSH->addSymbol(Sym);
     249          14 : }
     250             : 
     251          80 : static Error writeRecords(BinaryStreamWriter &Writer,
     252             :                           ArrayRef<CVSymbol> Records) {
     253         160 :   BinaryItemStream<CVSymbol> ItemStream(support::endianness::little);
     254          80 :   ItemStream.setItems(Records);
     255         160 :   BinaryStreamRef RecordsRef(ItemStream);
     256         240 :   return Writer.writeStreamRef(RecordsRef);
     257             : }
     258             : 
     259          40 : Error GSIStreamBuilder::commitSymbolRecordStream(
     260             :     WritableBinaryStreamRef Stream) {
     261         120 :   BinaryStreamWriter Writer(Stream);
     262             : 
     263             :   // Write public symbol records first, followed by global symbol records.  This
     264             :   // must match the order that we assume in finalizeMsfLayout when computing
     265             :   // PSHZero and GSHZero.
     266         200 :   if (auto EC = writeRecords(Writer, PSH->Records))
     267           0 :     return EC;
     268         200 :   if (auto EC = writeRecords(Writer, GSH->Records))
     269           0 :     return EC;
     270             : 
     271         120 :   return Error::success();
     272             : }
     273             : 
     274          40 : Error GSIStreamBuilder::commitPublicsHashStream(
     275             :     WritableBinaryStreamRef Stream) {
     276         120 :   BinaryStreamWriter Writer(Stream);
     277             :   PublicsStreamHeader Header;
     278             : 
     279             :   // FIXME: Fill these in. They are for incremental linking.
     280          40 :   Header.NumThunks = 0;
     281          40 :   Header.SizeOfThunk = 0;
     282          40 :   Header.ISectThunkTable = 0;
     283          40 :   Header.OffThunkTable = 0;
     284          40 :   Header.NumSections = 0;
     285         120 :   Header.SymHash = PSH->calculateSerializedLength();
     286         160 :   Header.AddrMap = PSH->Records.size() * 4;
     287         120 :   if (auto EC = Writer.writeObject(Header))
     288           0 :     return EC;
     289             : 
     290         160 :   if (auto EC = PSH->commit(Writer))
     291           0 :     return EC;
     292             : 
     293         120 :   std::vector<ulittle32_t> AddrMap = computeAddrMap(PSH->Records);
     294         120 :   if (auto EC = Writer.writeArray(makeArrayRef(AddrMap)))
     295           0 :     return EC;
     296             : 
     297         120 :   return Error::success();
     298             : }
     299             : 
     300          40 : Error GSIStreamBuilder::commitGlobalsHashStream(
     301             :     WritableBinaryStreamRef Stream) {
     302         120 :   BinaryStreamWriter Writer(Stream);
     303         120 :   return GSH->commit(Writer);
     304             : }
     305             : 
     306          40 : Error GSIStreamBuilder::commit(const msf::MSFLayout &Layout,
     307             :                                WritableBinaryStreamRef Buffer) {
     308             :   auto GS = WritableMappedBlockStream::createIndexedStream(
     309         160 :       Layout, Buffer, getGlobalsStreamIndex(), Msf.getAllocator());
     310             :   auto PS = WritableMappedBlockStream::createIndexedStream(
     311         160 :       Layout, Buffer, getPublicsStreamIndex(), Msf.getAllocator());
     312             :   auto PRS = WritableMappedBlockStream::createIndexedStream(
     313         160 :       Layout, Buffer, getRecordStreamIdx(), Msf.getAllocator());
     314             : 
     315         160 :   if (auto EC = commitSymbolRecordStream(*PRS))
     316           0 :     return EC;
     317         160 :   if (auto EC = commitGlobalsHashStream(*GS))
     318           0 :     return EC;
     319         160 :   if (auto EC = commitPublicsHashStream(*PS))
     320           0 :     return EC;
     321         120 :   return Error::success();
     322             : }

Generated by: LCOV version 1.13