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