Home | History | Annotate | Download | only in CodeView
      1 //===- TypeSerializer.h -----------------------------------------*- 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 #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H
     11 #define LLVM_DEBUGINFO_CODEVIEW_TYPESERIALIZER_H
     12 
     13 #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
     14 #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
     15 #include "llvm/Support/BinaryByteStream.h"
     16 #include "llvm/Support/BinaryStreamWriter.h"
     17 
     18 #include "llvm/ADT/Optional.h"
     19 #include "llvm/ADT/SmallVector.h"
     20 #include "llvm/ADT/StringRef.h"
     21 #include "llvm/Support/Allocator.h"
     22 #include "llvm/Support/Error.h"
     23 
     24 namespace llvm {
     25 
     26 namespace codeview {
     27 
     28 class TypeHasher;
     29 
     30 class TypeSerializer : public TypeVisitorCallbacks {
     31   struct SubRecord {
     32     SubRecord(TypeLeafKind K, uint32_t S) : Kind(K), Size(S) {}
     33 
     34     TypeLeafKind Kind;
     35     uint32_t Size = 0;
     36   };
     37   struct RecordSegment {
     38     SmallVector<SubRecord, 16> SubRecords;
     39 
     40     uint32_t length() const {
     41       uint32_t L = sizeof(RecordPrefix);
     42       for (const auto &R : SubRecords) {
     43         L += R.Size;
     44       }
     45       return L;
     46     }
     47   };
     48 
     49   typedef SmallVector<MutableArrayRef<uint8_t>, 2> MutableRecordList;
     50 
     51   static constexpr uint8_t ContinuationLength = 8;
     52   BumpPtrAllocator &RecordStorage;
     53   RecordSegment CurrentSegment;
     54   MutableRecordList FieldListSegments;
     55 
     56   Optional<TypeLeafKind> TypeKind;
     57   Optional<TypeLeafKind> MemberKind;
     58   std::vector<uint8_t> RecordBuffer;
     59   MutableBinaryByteStream Stream;
     60   BinaryStreamWriter Writer;
     61   TypeRecordMapping Mapping;
     62 
     63   /// Private type record hashing implementation details are handled here.
     64   std::unique_ptr<TypeHasher> Hasher;
     65 
     66   /// Contains a list of all records indexed by TypeIndex.toArrayIndex().
     67   SmallVector<ArrayRef<uint8_t>, 2> SeenRecords;
     68 
     69   /// Temporary storage that we use to copy a record's data while re-writing
     70   /// its type indices.
     71   SmallVector<uint8_t, 256> RemapStorage;
     72 
     73   TypeIndex nextTypeIndex() const;
     74 
     75   bool isInFieldList() const;
     76   MutableArrayRef<uint8_t> getCurrentSubRecordData();
     77   MutableArrayRef<uint8_t> getCurrentRecordData();
     78   Error writeRecordPrefix(TypeLeafKind Kind);
     79 
     80   Expected<MutableArrayRef<uint8_t>>
     81   addPadding(MutableArrayRef<uint8_t> Record);
     82 
     83 public:
     84   explicit TypeSerializer(BumpPtrAllocator &Storage, bool Hash = true);
     85   ~TypeSerializer();
     86 
     87   void reset();
     88 
     89   BumpPtrAllocator &getAllocator() { return RecordStorage; }
     90 
     91   ArrayRef<ArrayRef<uint8_t>> records() const;
     92   TypeIndex insertRecordBytes(ArrayRef<uint8_t> &Record);
     93   TypeIndex insertRecord(const RemappedType &Record);
     94   Expected<TypeIndex> visitTypeEndGetIndex(CVType &Record);
     95 
     96   Error visitTypeBegin(CVType &Record) override;
     97   Error visitTypeEnd(CVType &Record) override;
     98   Error visitMemberBegin(CVMemberRecord &Record) override;
     99   Error visitMemberEnd(CVMemberRecord &Record) override;
    100 
    101 #define TYPE_RECORD(EnumName, EnumVal, Name)                                   \
    102   virtual Error visitKnownRecord(CVType &CVR, Name##Record &Record) override { \
    103     return visitKnownRecordImpl(CVR, Record);                                  \
    104   }
    105 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
    106 #define MEMBER_RECORD(EnumName, EnumVal, Name)                                 \
    107   Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \
    108     return visitKnownMemberImpl<Name##Record>(CVR, Record);                    \
    109   }
    110 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
    111 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
    112 
    113 private:
    114   template <typename RecordKind>
    115   Error visitKnownRecordImpl(CVType &CVR, RecordKind &Record) {
    116     return Mapping.visitKnownRecord(CVR, Record);
    117   }
    118 
    119   template <typename RecordType>
    120   Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) {
    121     assert(CVR.Kind == static_cast<TypeLeafKind>(Record.getKind()));
    122 
    123     if (auto EC = Writer.writeEnum(CVR.Kind))
    124       return EC;
    125 
    126     if (auto EC = Mapping.visitKnownMember(CVR, Record))
    127       return EC;
    128 
    129     // Get all the data that was just written and is yet to be committed to
    130     // the current segment.  Then pad it to 4 bytes.
    131     MutableArrayRef<uint8_t> ThisRecord = getCurrentSubRecordData();
    132     auto ExpectedRecord = addPadding(ThisRecord);
    133     if (!ExpectedRecord)
    134       return ExpectedRecord.takeError();
    135     ThisRecord = *ExpectedRecord;
    136 
    137     CurrentSegment.SubRecords.emplace_back(CVR.Kind, ThisRecord.size());
    138     CVR.Data = ThisRecord;
    139 
    140     // Both the last subrecord and the total length of this segment should be
    141     // multiples of 4.
    142     assert(ThisRecord.size() % 4 == 0);
    143     assert(CurrentSegment.length() % 4 == 0);
    144 
    145     return Error::success();
    146   }
    147 };
    148 }
    149 }
    150 
    151 #endif
    152