LCOV - code coverage report
Current view: top level - lib/DebugInfo/PDB/Native - GlobalsStream.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 38 58 65.5 %
Date: 2018-10-20 13:21:21 Functions: 7 8 87.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- GlobalsStream.cpp - PDB Index of Symbols by Name ---------*- 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             : // The on-disk structores used in this file are based on the reference
      11             : // implementation which is available at
      12             : // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h
      13             : //
      14             : // When you are reading the reference source code, you'd find the
      15             : // information below useful.
      16             : //
      17             : //  - ppdb1->m_fMinimalDbgInfo seems to be always true.
      18             : //  - SMALLBUCKETS macro is defined.
      19             : //
      20             : //===----------------------------------------------------------------------===//
      21             : 
      22             : #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
      23             : 
      24             : #include "llvm/DebugInfo/CodeView/RecordName.h"
      25             : #include "llvm/DebugInfo/PDB/Native/Hash.h"
      26             : #include "llvm/DebugInfo/PDB/Native/RawError.h"
      27             : #include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
      28             : #include "llvm/Support/BinaryStreamReader.h"
      29             : #include "llvm/Support/Error.h"
      30             : #include <algorithm>
      31             : 
      32             : using namespace llvm;
      33             : using namespace llvm::msf;
      34             : using namespace llvm::pdb;
      35             : 
      36          15 : GlobalsStream::GlobalsStream(std::unique_ptr<MappedBlockStream> Stream)
      37          15 :     : Stream(std::move(Stream)) {}
      38             : 
      39             : GlobalsStream::~GlobalsStream() = default;
      40             : 
      41          15 : Error GlobalsStream::reload() {
      42          15 :   BinaryStreamReader Reader(*Stream);
      43          30 :   if (auto E = GlobalsTable.read(Reader))
      44             :     return E;
      45             :   return Error::success();
      46             : }
      47             : 
      48             : std::vector<std::pair<uint32_t, codeview::CVSymbol>>
      49           4 : GlobalsStream::findRecordsByName(StringRef Name,
      50             :                                  const SymbolStream &Symbols) const {
      51             :   std::vector<std::pair<uint32_t, codeview::CVSymbol>> Result;
      52             : 
      53             :   // Hash the name to figure out which bucket this goes into.
      54           4 :   size_t ExpandedBucketIndex = hashStringV1(Name) % IPHR_HASH;
      55           4 :   int32_t CompressedBucketIndex = GlobalsTable.BucketMap[ExpandedBucketIndex];
      56           4 :   if (CompressedBucketIndex == -1)
      57             :     return Result;
      58             : 
      59           3 :   uint32_t LastBucketIndex = GlobalsTable.HashBuckets.size() - 1;
      60             :   uint32_t StartRecordIndex =
      61           3 :       GlobalsTable.HashBuckets[CompressedBucketIndex] / 12;
      62             :   uint32_t EndRecordIndex = 0;
      63           3 :   if (LLVM_LIKELY(uint32_t(CompressedBucketIndex) < LastBucketIndex)) {
      64           2 :     EndRecordIndex = GlobalsTable.HashBuckets[CompressedBucketIndex + 1];
      65             :   } else {
      66             :     // If this is the last bucket, it consists of all hash records until the end
      67             :     // of the HashRecords array.
      68           1 :     EndRecordIndex = GlobalsTable.HashRecords.size() * 12;
      69             :   }
      70             : 
      71           3 :   EndRecordIndex /= 12;
      72             : 
      73             :   assert(EndRecordIndex <= GlobalsTable.HashRecords.size());
      74           9 :   while (StartRecordIndex < EndRecordIndex) {
      75           6 :     PSHashRecord PSH = GlobalsTable.HashRecords[StartRecordIndex];
      76           6 :     uint32_t Off = PSH.Off - 1;
      77           6 :     codeview::CVSymbol Record = Symbols.readRecord(Off);
      78          12 :     if (codeview::getSymbolName(Record) == Name)
      79           6 :       Result.push_back(std::make_pair(Off, std::move(Record)));
      80           6 :     ++StartRecordIndex;
      81             :   }
      82             :   return Result;
      83             : }
      84             : 
      85          35 : static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) {
      86          35 :   if (HashHdr->VerHdr != GSIHashHeader::HdrVersion)
      87             :     return make_error<RawError>(
      88             :         raw_error_code::feature_unsupported,
      89             :         "Encountered unsupported globals stream version.");
      90             : 
      91             :   return Error::success();
      92             : }
      93             : 
      94          18 : static Error readGSIHashHeader(const GSIHashHeader *&HashHdr,
      95             :                                BinaryStreamReader &Reader) {
      96          36 :   if (Reader.readObject(HashHdr))
      97             :     return make_error<RawError>(raw_error_code::corrupt_file,
      98             :                                 "Stream does not contain a GSIHashHeader.");
      99             : 
     100          36 :   if (HashHdr->VerSignature != GSIHashHeader::HdrSignature)
     101             :     return make_error<RawError>(
     102             :         raw_error_code::feature_unsupported,
     103             :         "GSIHashHeader signature (0xffffffff) not found.");
     104             : 
     105             :   return Error::success();
     106             : }
     107             : 
     108          18 : static Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords,
     109             :                                 const GSIHashHeader *HashHdr,
     110             :                                 BinaryStreamReader &Reader) {
     111          36 :   if (auto EC = checkHashHdrVersion(HashHdr))
     112             :     return EC;
     113             : 
     114             :   // HashHdr->HrSize specifies the number of bytes of PSHashRecords we have.
     115             :   // Verify that we can read them all.
     116          18 :   if (HashHdr->HrSize % sizeof(PSHashRecord))
     117             :     return make_error<RawError>(raw_error_code::corrupt_file,
     118             :                                 "Invalid HR array size.");
     119          18 :   uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord);
     120          36 :   if (auto EC = Reader.readArray(HashRecords, NumHashRecords))
     121             :     return joinErrors(std::move(EC),
     122           0 :                       make_error<RawError>(raw_error_code::corrupt_file,
     123           0 :                                            "Error reading hash records."));
     124             : 
     125             :   return Error::success();
     126             : }
     127             : 
     128             : static Error
     129           0 : readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets,
     130             :                    FixedStreamArray<support::ulittle32_t> &HashBitmap,
     131             :                    const GSIHashHeader *HashHdr,
     132             :                    MutableArrayRef<int32_t> BucketMap,
     133             :                    BinaryStreamReader &Reader) {
     134           0 :   if (auto EC = checkHashHdrVersion(HashHdr))
     135             :     return EC;
     136             : 
     137             :   // Before the actual hash buckets, there is a bitmap of length determined by
     138             :   // IPHR_HASH.
     139             :   size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32);
     140             :   uint32_t NumBitmapEntries = BitmapSizeInBits / 32;
     141           0 :   if (auto EC = Reader.readArray(HashBitmap, NumBitmapEntries))
     142             :     return joinErrors(std::move(EC),
     143           0 :                       make_error<RawError>(raw_error_code::corrupt_file,
     144           0 :                                            "Could not read a bitmap."));
     145             :   uint32_t NumBuckets1 = 0;
     146             :   uint32_t CompressedBucketIdx = 0;
     147           0 :   for (uint32_t I = 0; I <= IPHR_HASH; ++I) {
     148           0 :     uint8_t WordIdx = I / 32;
     149           0 :     uint8_t BitIdx = I % 32;
     150           0 :     bool IsSet = HashBitmap[WordIdx] & (1U << BitIdx);
     151           0 :     if (IsSet) {
     152           0 :       ++NumBuckets1;
     153           0 :       BucketMap[I] = CompressedBucketIdx++;
     154             :     } else {
     155           0 :       BucketMap[I] = -1;
     156             :     }
     157             :   }
     158             : 
     159             :   uint32_t NumBuckets = 0;
     160           0 :   for (uint32_t B : HashBitmap)
     161           0 :     NumBuckets += countPopulation(B);
     162             : 
     163             :   // Hash buckets follow.
     164           0 :   if (auto EC = Reader.readArray(HashBuckets, NumBuckets))
     165             :     return joinErrors(std::move(EC),
     166           0 :                       make_error<RawError>(raw_error_code::corrupt_file,
     167           0 :                                            "Hash buckets corrupted."));
     168             : 
     169             :   return Error::success();
     170             : }
     171             : 
     172          18 : Error GSIHashTable::read(BinaryStreamReader &Reader) {
     173          36 :   if (auto EC = readGSIHashHeader(HashHdr, Reader))
     174             :     return EC;
     175          36 :   if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader))
     176             :     return EC;
     177          36 :   if (HashHdr->HrSize > 0)
     178          17 :     if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr,
     179          17 :                                      BucketMap, Reader))
     180             :       return EC;
     181             :   return Error::success();
     182             : }

Generated by: LCOV version 1.13