LCOV - code coverage report
Current view: top level - lib/DebugInfo/CodeView - TypeSerializer.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 149 166 89.8 %
Date: 2017-09-14 15:23:50 Functions: 17 18 94.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- TypeSerialzier.cpp -------------------------------------------------===//
       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/CodeView/TypeSerializer.h"
      11             : #include "llvm/ADT/ArrayRef.h"
      12             : #include "llvm/ADT/DenseSet.h"
      13             : #include "llvm/ADT/STLExtras.h"
      14             : #include "llvm/DebugInfo/CodeView/CodeView.h"
      15             : #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
      16             : #include "llvm/DebugInfo/CodeView/TypeIndex.h"
      17             : #include "llvm/Support/Allocator.h"
      18             : #include "llvm/Support/BinaryByteStream.h"
      19             : #include "llvm/Support/BinaryStreamWriter.h"
      20             : #include "llvm/Support/Endian.h"
      21             : #include "llvm/Support/Error.h"
      22             : #include <algorithm>
      23             : #include <cassert>
      24             : #include <cstdint>
      25             : #include <cstring>
      26             : 
      27             : using namespace llvm;
      28             : using namespace llvm::codeview;
      29             : 
      30             : namespace {
      31             : 
      32             : struct HashedType {
      33             :   uint64_t Hash;
      34             :   const uint8_t *Data;
      35             :   unsigned Size; // FIXME: Go to uint16_t?
      36             :   TypeIndex Index;
      37             : };
      38             : 
      39             : /// Wrapper around a poitner to a HashedType. Hash and equality operations are
      40             : /// based on data in the pointee.
      41             : struct HashedTypePtr {
      42             :   HashedTypePtr() = default;
      43        2487 :   HashedTypePtr(HashedType *Ptr) : Ptr(Ptr) {}
      44             : 
      45             :   HashedType *Ptr = nullptr;
      46             : };
      47             : 
      48             : } // end anonymous namespace
      49             : 
      50             : namespace llvm {
      51             : 
      52             : template <> struct DenseMapInfo<HashedTypePtr> {
      53       15724 :   static inline HashedTypePtr getEmptyKey() { return HashedTypePtr(nullptr); }
      54             : 
      55             :   static inline HashedTypePtr getTombstoneKey() {
      56        4986 :     return HashedTypePtr(reinterpret_cast<HashedType *>(1));
      57             :   }
      58             : 
      59             :   static unsigned getHashValue(HashedTypePtr Val) {
      60             :     assert(Val.Ptr != getEmptyKey().Ptr && Val.Ptr != getTombstoneKey().Ptr);
      61        2775 :     return Val.Ptr->Hash;
      62             :   }
      63             : 
      64       10248 :   static bool isEqual(HashedTypePtr LHSP, HashedTypePtr RHSP) {
      65       10248 :     HashedType *LHS = LHSP.Ptr;
      66       10248 :     HashedType *RHS = RHSP.Ptr;
      67       12454 :     if (RHS == getEmptyKey().Ptr || RHS == getTombstoneKey().Ptr)
      68        9095 :       return LHS == RHS;
      69        1153 :     if (LHS->Hash != RHS->Hash || LHS->Size != RHS->Size)
      70             :       return false;
      71         383 :     return ::memcmp(LHS->Data, RHS->Data, LHS->Size) == 0;
      72             :   }
      73             : };
      74             : 
      75             : } // end namespace llvm
      76             : 
      77             : /// Private implementation so that we don't leak our DenseMap instantiations to
      78             : /// users.
      79        9682 : class llvm::codeview::TypeHasher {
      80             : private:
      81             :   /// Storage for type record provided by the caller. Records will outlive the
      82             :   /// hasher object, so they should be allocated here.
      83             :   BumpPtrAllocator &RecordStorage;
      84             : 
      85             :   /// Storage for hash keys. These only need to live as long as the hashing
      86             :   /// operation.
      87             :   BumpPtrAllocator KeyStorage;
      88             : 
      89             :   /// Hash table. We really want a DenseMap<ArrayRef<uint8_t>, TypeIndex> here,
      90             :   /// but DenseMap is inefficient when the keys are long (like type records)
      91             :   /// because it recomputes the hash value of every key when it grows. This
      92             :   /// value type stores the hash out of line in KeyStorage, so that table
      93             :   /// entries are small and easy to rehash.
      94             :   DenseSet<HashedTypePtr> HashedRecords;
      95             : 
      96             : public:
      97       14523 :   TypeHasher(BumpPtrAllocator &RecordStorage) : RecordStorage(RecordStorage) {}
      98             : 
      99           0 :   void reset() { HashedRecords.clear(); }
     100             : 
     101             :   /// Takes the bytes of type record, inserts them into the hash table, saves
     102             :   /// them, and returns a pointer to an identical stable type record along with
     103             :   /// its type index in the destination stream.
     104             :   TypeIndex getOrCreateRecord(ArrayRef<uint8_t> &Record, TypeIndex TI);
     105             : };
     106             : 
     107        2487 : TypeIndex TypeHasher::getOrCreateRecord(ArrayRef<uint8_t> &Record,
     108             :                                         TypeIndex TI) {
     109             :   assert(Record.size() < UINT32_MAX && "Record too big");
     110             :   assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!");
     111             : 
     112             :   // Compute the hash up front so we can store it in the key.
     113        4974 :   HashedType TempHashedType = {hash_value(Record), Record.data(),
     114        4974 :                                unsigned(Record.size()), TI};
     115        7461 :   auto Result = HashedRecords.insert(HashedTypePtr(&TempHashedType));
     116        2487 :   HashedType *&Hashed = Result.first->Ptr;
     117             : 
     118        2487 :   if (Result.second) {
     119             :     // This was a new type record. We need stable storage for both the key and
     120             :     // the record. The record should outlive the hashing operation.
     121        4208 :     Hashed = KeyStorage.Allocate<HashedType>();
     122        2104 :     *Hashed = TempHashedType;
     123             : 
     124        4208 :     uint8_t *Stable = RecordStorage.Allocate<uint8_t>(Record.size());
     125        2104 :     memcpy(Stable, Record.data(), Record.size());
     126        2104 :     Hashed->Data = Stable;
     127             :     assert(Hashed->Size == Record.size());
     128             :   }
     129             : 
     130             :   // Update the caller's copy of Record to point a stable copy.
     131        2487 :   Record = ArrayRef<uint8_t>(Hashed->Data, Hashed->Size);
     132        2487 :   return Hashed->Index;
     133             : }
     134             : 
     135        5379 : TypeIndex TypeSerializer::nextTypeIndex() const {
     136       10758 :   return TypeIndex::fromArrayIndex(SeenRecords.size());
     137             : }
     138             : 
     139           0 : bool TypeSerializer::isInFieldList() const {
     140           0 :   return TypeKind.hasValue() && *TypeKind == TypeLeafKind::LF_FIELDLIST;
     141             : }
     142             : 
     143       12366 : MutableArrayRef<uint8_t> TypeSerializer::getCurrentSubRecordData() {
     144             :   assert(isInFieldList());
     145       37098 :   return getCurrentRecordData().drop_front(CurrentSegment.length());
     146             : }
     147             : 
     148       14118 : MutableArrayRef<uint8_t> TypeSerializer::getCurrentRecordData() {
     149       42354 :   return MutableArrayRef<uint8_t>(RecordBuffer).take_front(Writer.getOffset());
     150             : }
     151             : 
     152        1752 : Error TypeSerializer::writeRecordPrefix(TypeLeafKind Kind) {
     153             :   RecordPrefix Prefix;
     154        3504 :   Prefix.RecordKind = Kind;
     155        1752 :   Prefix.RecordLen = 0;
     156        7008 :   if (auto EC = Writer.writeObject(Prefix))
     157           0 :     return EC;
     158        5256 :   return Error::success();
     159             : }
     160             : 
     161             : Expected<MutableArrayRef<uint8_t>>
     162        7931 : TypeSerializer::addPadding(MutableArrayRef<uint8_t> Record) {
     163        7931 :   uint32_t Align = Record.size() % 4;
     164        7931 :   if (Align == 0)
     165             :     return Record;
     166             : 
     167        1846 :   int PaddingBytes = 4 - Align;
     168        1846 :   int N = PaddingBytes;
     169        7420 :   while (PaddingBytes > 0) {
     170        2787 :     uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes);
     171        8361 :     if (auto EC = Writer.writeInteger(Pad))
     172           0 :       return std::move(EC);
     173        2787 :     --PaddingBytes;
     174             :   }
     175        7384 :   return MutableArrayRef<uint8_t>(Record.data(), Record.size() + N);
     176             : }
     177             : 
     178        5025 : TypeSerializer::TypeSerializer(BumpPtrAllocator &Storage, bool Hash)
     179             :     : RecordStorage(Storage), RecordBuffer(MaxRecordLength * 2),
     180             :       Stream(RecordBuffer, support::little), Writer(Stream),
     181       65325 :       Mapping(Writer) {
     182             :   // RecordBuffer needs to be able to hold enough data so that if we are 1
     183             :   // byte short of MaxRecordLen, and then we try to write MaxRecordLen bytes,
     184             :   // we won't overflow.
     185        5025 :   if (Hash)
     186       14523 :     Hasher = llvm::make_unique<TypeHasher>(Storage);
     187        5025 : }
     188             : 
     189             : TypeSerializer::~TypeSerializer() = default;
     190             : 
     191        1484 : ArrayRef<ArrayRef<uint8_t>> TypeSerializer::records() const {
     192        2968 :   return SeenRecords;
     193             : }
     194             : 
     195         134 : void TypeSerializer::reset() {
     196         268 :   if (Hasher)
     197           0 :     Hasher->reset();
     198         268 :   Writer.setOffset(0);
     199         536 :   CurrentSegment = RecordSegment();
     200         268 :   FieldListSegments.clear();
     201         268 :   TypeKind.reset();
     202         268 :   MemberKind.reset();
     203         268 :   SeenRecords.clear();
     204         134 : }
     205             : 
     206        2892 : TypeIndex TypeSerializer::insertRecordBytes(ArrayRef<uint8_t> &Record) {
     207             :   assert(!TypeKind.hasValue() && "Already in a type mapping!");
     208             :   assert(Writer.getOffset() == 0 && "Stream has data already!");
     209             : 
     210        5784 :   if (Hasher) {
     211        4974 :     TypeIndex ActualTI = Hasher->getOrCreateRecord(Record, nextTypeIndex());
     212        2487 :     if (nextTypeIndex() == ActualTI)
     213        2104 :       SeenRecords.push_back(Record);
     214        2487 :     return ActualTI;
     215             :   }
     216             : 
     217         405 :   TypeIndex NewTI = nextTypeIndex();
     218         810 :   uint8_t *Stable = RecordStorage.Allocate<uint8_t>(Record.size());
     219         405 :   memcpy(Stable, Record.data(), Record.size());
     220         405 :   Record = ArrayRef<uint8_t>(Stable, Record.size());
     221         405 :   SeenRecords.push_back(Record);
     222         405 :   return NewTI;
     223             : }
     224             : 
     225        1002 : TypeIndex TypeSerializer::insertRecord(const RemappedType &Record) {
     226             :   assert(!TypeKind.hasValue() && "Already in a type mapping!");
     227             :   assert(Writer.getOffset() == 0 && "Stream has data already!");
     228             : 
     229        1002 :   TypeIndex TI;
     230        1002 :   ArrayRef<uint8_t> OriginalData = Record.OriginalRecord.RecordData;
     231        1002 :   if (Record.Mappings.empty()) {
     232             :     // This record did not remap any type indices.  Just write it.
     233         488 :     return insertRecordBytes(OriginalData);
     234             :   }
     235             : 
     236             :   // At least one type index was remapped.  Before we can hash it we have to
     237             :   // copy the full record bytes, re-write each type index, then hash the copy.
     238             :   // We do this in temporary storage since only the DenseMap can decide whether
     239             :   // this record already exists, and if it does we don't want the memory to
     240             :   // stick around.
     241         514 :   RemapStorage.resize(OriginalData.size());
     242        1028 :   ::memcpy(&RemapStorage[0], OriginalData.data(), OriginalData.size());
     243        1028 :   uint8_t *ContentBegin = RemapStorage.data() + sizeof(RecordPrefix);
     244        2554 :   for (const auto &M : Record.Mappings) {
     245             :     // First 4 bytes of every record are the record prefix, but the mapping
     246             :     // offset is relative to the content which starts after.
     247        1012 :     *(TypeIndex *)(ContentBegin + M.first) = M.second;
     248             :   }
     249        1028 :   auto RemapRef = makeArrayRef(RemapStorage);
     250         514 :   return insertRecordBytes(RemapRef);
     251             : }
     252             : 
     253        1748 : Error TypeSerializer::visitTypeBegin(CVType &Record) {
     254             :   assert(!TypeKind.hasValue() && "Already in a type mapping!");
     255             :   assert(Writer.getOffset() == 0 && "Stream has data already!");
     256             : 
     257        5244 :   if (auto EC = writeRecordPrefix(Record.kind()))
     258           0 :     return EC;
     259             : 
     260        3496 :   TypeKind = Record.kind();
     261        5244 :   if (auto EC = Mapping.visitTypeBegin(Record))
     262           0 :     return EC;
     263             : 
     264        5244 :   return Error::success();
     265             : }
     266             : 
     267        1748 : Expected<TypeIndex> TypeSerializer::visitTypeEndGetIndex(CVType &Record) {
     268             :   assert(TypeKind.hasValue() && "Not in a type mapping!");
     269        5244 :   if (auto EC = Mapping.visitTypeEnd(Record))
     270           0 :     return std::move(EC);
     271             : 
     272             :   // Update the record's length and fill out the CVType members to point to
     273             :   // the stable memory holding the record's data.
     274        1748 :   auto ThisRecordData = getCurrentRecordData();
     275        1748 :   auto ExpectedData = addPadding(ThisRecordData);
     276        1748 :   if (!ExpectedData)
     277           0 :     return ExpectedData.takeError();
     278        1748 :   ThisRecordData = *ExpectedData;
     279             : 
     280             :   RecordPrefix *Prefix =
     281        1748 :       reinterpret_cast<RecordPrefix *>(ThisRecordData.data());
     282        3496 :   Prefix->RecordLen = ThisRecordData.size() - sizeof(uint16_t);
     283             : 
     284        3496 :   Record.Type = *TypeKind;
     285        1748 :   Record.RecordData = ThisRecordData;
     286             : 
     287             :   // insertRecordBytes assumes we're not in a mapping, so do this first.
     288        3496 :   TypeKind.reset();
     289        3496 :   Writer.setOffset(0);
     290             : 
     291        1748 :   TypeIndex InsertedTypeIndex = insertRecordBytes(Record.RecordData);
     292             : 
     293             :   // Write out each additional segment in reverse order, and update each
     294             :   // record's continuation index to point to the previous one.
     295        7000 :   for (auto X : reverse(FieldListSegments)) {
     296           4 :     auto CIBytes = X.take_back(sizeof(uint32_t));
     297             :     support::ulittle32_t *CI =
     298           4 :         reinterpret_cast<support::ulittle32_t *>(CIBytes.data());
     299             :     assert(*CI == 0xB0C0B0C0 && "Invalid TypeIndex placeholder");
     300           8 :     *CI = InsertedTypeIndex.getIndex();
     301           4 :     InsertedTypeIndex = insertRecordBytes(X);
     302             :   }
     303             : 
     304        3496 :   FieldListSegments.clear();
     305        3496 :   CurrentSegment.SubRecords.clear();
     306             : 
     307             :   return InsertedTypeIndex;
     308             : }
     309             : 
     310         134 : Error TypeSerializer::visitTypeEnd(CVType &Record) {
     311         268 :   auto ExpectedIndex = visitTypeEndGetIndex(Record);
     312         134 :   if (!ExpectedIndex)
     313             :     return ExpectedIndex.takeError();
     314         402 :   return Error::success();
     315             : }
     316             : 
     317        6183 : Error TypeSerializer::visitMemberBegin(CVMemberRecord &Record) {
     318             :   assert(isInFieldList() && "Not in a field list!");
     319             :   assert(!MemberKind.hasValue() && "Already in a member record!");
     320       12366 :   MemberKind = Record.Kind;
     321             : 
     322       18549 :   if (auto EC = Mapping.visitMemberBegin(Record))
     323           0 :     return EC;
     324             : 
     325       18549 :   return Error::success();
     326             : }
     327             : 
     328        6183 : Error TypeSerializer::visitMemberEnd(CVMemberRecord &Record) {
     329       18549 :   if (auto EC = Mapping.visitMemberEnd(Record))
     330           0 :     return EC;
     331             : 
     332             :   // Check if this subrecord makes the current segment not fit in 64K minus
     333             :   // the space for a continuation record (8 bytes). If the segment does not
     334             :   // fit, insert a continuation record.
     335        6183 :   if (Writer.getOffset() > MaxRecordLength - ContinuationLength) {
     336           4 :     MutableArrayRef<uint8_t> Data = getCurrentRecordData();
     337           8 :     SubRecord LastSubRecord = CurrentSegment.SubRecords.back();
     338           8 :     uint32_t CopySize = CurrentSegment.length() - LastSubRecord.Size;
     339           8 :     auto CopyData = Data.take_front(CopySize);
     340           8 :     auto LeftOverData = Data.drop_front(CopySize);
     341             :     assert(LastSubRecord.Size == LeftOverData.size());
     342             : 
     343             :     // Allocate stable storage for the record and copy the old record plus
     344             :     // continuation over.
     345           4 :     uint16_t LengthWithSize = CopySize + ContinuationLength;
     346             :     assert(LengthWithSize <= MaxRecordLength);
     347           4 :     RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(CopyData.data());
     348           8 :     Prefix->RecordLen = LengthWithSize - sizeof(uint16_t);
     349             : 
     350           8 :     uint8_t *SegmentBytes = RecordStorage.Allocate<uint8_t>(LengthWithSize);
     351           8 :     auto SavedSegment = MutableArrayRef<uint8_t>(SegmentBytes, LengthWithSize);
     352           8 :     MutableBinaryByteStream CS(SavedSegment, support::little);
     353           8 :     BinaryStreamWriter CW(CS);
     354          12 :     if (auto EC = CW.writeBytes(CopyData))
     355           0 :       return EC;
     356          12 :     if (auto EC = CW.writeEnum(TypeLeafKind::LF_INDEX))
     357           0 :       return EC;
     358          12 :     if (auto EC = CW.writeInteger<uint16_t>(0))
     359           0 :       return EC;
     360          12 :     if (auto EC = CW.writeInteger<uint32_t>(0xB0C0B0C0))
     361           0 :       return EC;
     362           4 :     FieldListSegments.push_back(SavedSegment);
     363             : 
     364             :     // Write a new placeholder record prefix to mark the start of this new
     365             :     // top-level record.
     366           8 :     Writer.setOffset(0);
     367          12 :     if (auto EC = writeRecordPrefix(TypeLeafKind::LF_FIELDLIST))
     368           0 :       return EC;
     369             : 
     370             :     // Then move over the subrecord that overflowed the old segment to the
     371             :     // beginning of this segment.  Note that we have to use memmove here
     372             :     // instead of Writer.writeBytes(), because the new and old locations
     373             :     // could overlap.
     374          12 :     ::memmove(Stream.data().data() + sizeof(RecordPrefix), LeftOverData.data(),
     375             :               LeftOverData.size());
     376             :     // And point the segment writer at the end of that subrecord.
     377           8 :     Writer.setOffset(LeftOverData.size() + sizeof(RecordPrefix));
     378             : 
     379           8 :     CurrentSegment.SubRecords.clear();
     380           4 :     CurrentSegment.SubRecords.push_back(LastSubRecord);
     381             :   }
     382             : 
     383             :   // Update the CVMemberRecord since we may have shifted around or gotten
     384             :   // padded.
     385        6183 :   Record.Data = getCurrentSubRecordData();
     386             : 
     387       12366 :   MemberKind.reset();
     388       18549 :   return Error::success();
     389             : }

Generated by: LCOV version 1.13