LCOV - code coverage report
Current view: top level - lib/DebugInfo/PDB/Native - TpiStream.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 77 80 96.2 %
Date: 2018-10-20 13:21:21 Functions: 17 19 89.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- TpiStream.cpp - PDB Type Info (TPI) Stream 2 Access ----------------===//
       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/TpiStream.h"
      11             : 
      12             : #include "llvm/ADT/iterator_range.h"
      13             : #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
      14             : #include "llvm/DebugInfo/CodeView/TypeRecord.h"
      15             : #include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
      16             : #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
      17             : #include "llvm/DebugInfo/PDB/Native/Hash.h"
      18             : #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
      19             : #include "llvm/DebugInfo/PDB/Native/RawConstants.h"
      20             : #include "llvm/DebugInfo/PDB/Native/RawError.h"
      21             : #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
      22             : #include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
      23             : #include "llvm/Support/BinaryStreamReader.h"
      24             : #include "llvm/Support/Endian.h"
      25             : #include "llvm/Support/Error.h"
      26             : #include <algorithm>
      27             : #include <cstdint>
      28             : #include <vector>
      29             : 
      30             : using namespace llvm;
      31             : using namespace llvm::codeview;
      32             : using namespace llvm::support;
      33             : using namespace llvm::msf;
      34             : using namespace llvm::pdb;
      35             : 
      36         167 : TpiStream::TpiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream)
      37         167 :     : Pdb(File), Stream(std::move(Stream)) {}
      38             : 
      39             : TpiStream::~TpiStream() = default;
      40             : 
      41         167 : Error TpiStream::reload() {
      42         167 :   BinaryStreamReader Reader(*Stream);
      43             : 
      44         167 :   if (Reader.bytesRemaining() < sizeof(TpiStreamHeader))
      45             :     return make_error<RawError>(raw_error_code::corrupt_file,
      46             :                                 "TPI Stream does not contain a header.");
      47             : 
      48         334 :   if (Reader.readObject(Header))
      49             :     return make_error<RawError>(raw_error_code::corrupt_file,
      50             :                                 "TPI Stream does not contain a header.");
      51             : 
      52         334 :   if (Header->Version != PdbTpiV80)
      53             :     return make_error<RawError>(raw_error_code::corrupt_file,
      54             :                                 "Unsupported TPI Version.");
      55             : 
      56         167 :   if (Header->HeaderSize != sizeof(TpiStreamHeader))
      57             :     return make_error<RawError>(raw_error_code::corrupt_file,
      58             :                                 "Corrupt TPI Header size.");
      59             : 
      60         167 :   if (Header->HashKeySize != sizeof(ulittle32_t))
      61             :     return make_error<RawError>(raw_error_code::corrupt_file,
      62             :                                 "TPI Stream expected 4 byte hash key size.");
      63             : 
      64         167 :   if (Header->NumHashBuckets < MinTpiHashBuckets ||
      65             :       Header->NumHashBuckets > MaxTpiHashBuckets)
      66             :     return make_error<RawError>(raw_error_code::corrupt_file,
      67             :                                 "TPI Stream Invalid number of hash buckets.");
      68             : 
      69             :   // The actual type records themselves come from this stream
      70         167 :   if (auto EC =
      71         167 :           Reader.readSubstream(TypeRecordsSubstream, Header->TypeRecordBytes))
      72             :     return EC;
      73             : 
      74         334 :   BinaryStreamReader RecordReader(TypeRecordsSubstream.StreamData);
      75         167 :   if (auto EC =
      76         167 :           RecordReader.readArray(TypeRecords, TypeRecordsSubstream.size()))
      77             :     return EC;
      78             : 
      79             :   // Hash indices, hash values, etc come from the hash stream.
      80         334 :   if (Header->HashStreamIndex != kInvalidStreamIndex) {
      81         149 :     if (Header->HashStreamIndex >= Pdb.getNumStreams())
      82             :       return make_error<RawError>(raw_error_code::corrupt_file,
      83             :                                   "Invalid TPI hash stream index.");
      84             : 
      85             :     auto HS = MappedBlockStream::createIndexedStream(
      86         298 :         Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex,
      87         298 :         Pdb.getAllocator());
      88         149 :     BinaryStreamReader HSR(*HS);
      89             : 
      90             :     // There should be a hash value for every type record, or no hashes at all.
      91             :     uint32_t NumHashValues =
      92         149 :         Header->HashValueBuffer.Length / sizeof(ulittle32_t);
      93         149 :     if (NumHashValues != getNumTypeRecords() && NumHashValues != 0)
      94             :       return make_error<RawError>(
      95             :           raw_error_code::corrupt_file,
      96             :           "TPI hash count does not match with the number of type records.");
      97         149 :     HSR.setOffset(Header->HashValueBuffer.Off);
      98         298 :     if (auto EC = HSR.readArray(HashValues, NumHashValues))
      99             :       return EC;
     100             : 
     101         149 :     HSR.setOffset(Header->IndexOffsetBuffer.Off);
     102             :     uint32_t NumTypeIndexOffsets =
     103         149 :         Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset);
     104         298 :     if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets))
     105             :       return EC;
     106             : 
     107         298 :     if (Header->HashAdjBuffer.Length > 0) {
     108             :       HSR.setOffset(Header->HashAdjBuffer.Off);
     109           0 :       if (auto EC = HashAdjusters.load(HSR))
     110             :         return EC;
     111             :     }
     112             : 
     113             :     HashStream = std::move(HS);
     114             :   }
     115             : 
     116         334 :   Types = llvm::make_unique<LazyRandomTypeCollection>(
     117         334 :       TypeRecords, getNumTypeRecords(), getTypeIndexOffsets());
     118             :   return Error::success();
     119             : }
     120             : 
     121          10 : PdbRaw_TpiVer TpiStream::getTpiVersion() const {
     122          10 :   uint32_t Value = Header->Version;
     123          10 :   return static_cast<PdbRaw_TpiVer>(Value);
     124             : }
     125             : 
     126         792 : uint32_t TpiStream::TypeIndexBegin() const { return Header->TypeIndexBegin; }
     127             : 
     128         792 : uint32_t TpiStream::TypeIndexEnd() const { return Header->TypeIndexEnd; }
     129             : 
     130         396 : uint32_t TpiStream::getNumTypeRecords() const {
     131         396 :   return TypeIndexEnd() - TypeIndexBegin();
     132             : }
     133             : 
     134         153 : uint16_t TpiStream::getTypeHashStreamIndex() const {
     135         306 :   return Header->HashStreamIndex;
     136             : }
     137             : 
     138         135 : uint16_t TpiStream::getTypeHashStreamAuxIndex() const {
     139         270 :   return Header->HashAuxStreamIndex;
     140             : }
     141             : 
     142          44 : uint32_t TpiStream::getNumHashBuckets() const { return Header->NumHashBuckets; }
     143           0 : uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; }
     144             : 
     145         149 : void TpiStream::buildHashMap() {
     146         149 :   if (!HashMap.empty())
     147          48 :     return;
     148         101 :   if (HashValues.empty())
     149          39 :     return;
     150             : 
     151         202 :   HashMap.resize(Header->NumHashBuckets);
     152             : 
     153         101 :   TypeIndex TIB{Header->TypeIndexBegin};
     154             :   TypeIndex TIE{Header->TypeIndexEnd};
     155       10304 :   while (TIB < TIE) {
     156       10203 :     uint32_t HV = HashValues[TIB.toArrayIndex()];
     157       20406 :     HashMap[HV].push_back(TIB++);
     158             :   }
     159             : }
     160             : 
     161         284 : bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); }
     162             : 
     163             : Expected<TypeIndex>
     164          66 : TpiStream::findFullDeclForForwardRef(TypeIndex ForwardRefTI) const {
     165          66 :   CVType F = Types->getType(ForwardRefTI);
     166          66 :   if (!isUdtForwardRef(F))
     167             :     return ForwardRefTI;
     168             : 
     169          66 :   Expected<TagRecordHash> ForwardTRH = hashTagRecord(F);
     170          66 :   if (!ForwardTRH)
     171             :     return ForwardTRH.takeError();
     172             : 
     173          66 :   uint32_t BucketIdx = ForwardTRH->FullRecordHash % Header->NumHashBuckets;
     174             : 
     175         132 :   for (TypeIndex TI : HashMap[BucketIdx]) {
     176          66 :     CVType CVT = Types->getType(TI);
     177          66 :     if (CVT.kind() != F.kind())
     178             :       continue;
     179             : 
     180          66 :     Expected<TagRecordHash> FullTRH = hashTagRecord(CVT);
     181          66 :     if (!FullTRH)
     182             :       return FullTRH.takeError();
     183          66 :     if (ForwardTRH->FullRecordHash != FullTRH->FullRecordHash)
     184             :       continue;
     185             :     TagRecord &ForwardTR = ForwardTRH->getRecord();
     186             :     TagRecord &FullTR = FullTRH->getRecord();
     187             : 
     188         132 :     if (!ForwardTR.hasUniqueName()) {
     189             :       if (ForwardTR.getName() == FullTR.getName())
     190             :         return TI;
     191             :       continue;
     192             :     }
     193             : 
     194         132 :     if (!FullTR.hasUniqueName())
     195             :       continue;
     196             :     if (ForwardTR.getUniqueName() == FullTR.getUniqueName())
     197             :       return TI;
     198             :   }
     199             :   return ForwardRefTI;
     200             : }
     201             : 
     202           4 : BinarySubstreamRef TpiStream::getTypeRecordsSubstream() const {
     203           4 :   return TypeRecordsSubstream;
     204             : }
     205             : 
     206          22 : FixedStreamArray<support::ulittle32_t> TpiStream::getHashValues() const {
     207          22 :   return HashValues;
     208             : }
     209             : 
     210         229 : FixedStreamArray<TypeIndexOffset> TpiStream::getTypeIndexOffsets() const {
     211         229 :   return TypeIndexOffsets;
     212             : }
     213             : 
     214           4 : HashTable<support::ulittle32_t> &TpiStream::getHashAdjusters() {
     215           4 :   return HashAdjusters;
     216             : }
     217             : 
     218          10 : CVTypeRange TpiStream::types(bool *HadError) const {
     219          20 :   return make_range(TypeRecords.begin(HadError), TypeRecords.end());
     220             : }
     221             : 
     222           0 : Error TpiStream::commit() { return Error::success(); }

Generated by: LCOV version 1.13