|
| 1 | +//===- CVTypeVisitor.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_CVTYPEVISITOR_H |
| 11 | +#define LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H |
| 12 | + |
| 13 | +#include "llvm/DebugInfo/CodeView/CodeView.h" |
| 14 | +#include "llvm/DebugInfo/CodeView/TypeIndex.h" |
| 15 | +#include "llvm/DebugInfo/CodeView/TypeRecord.h" |
| 16 | +#include "llvm/DebugInfo/CodeView/TypeStream.h" |
| 17 | + |
| 18 | +namespace llvm { |
| 19 | +namespace codeview { |
| 20 | + |
| 21 | +template <typename Derived> |
| 22 | +class CVTypeVisitor { |
| 23 | +public: |
| 24 | + CVTypeVisitor() {} |
| 25 | + |
| 26 | + bool hadError() const { return HadError; } |
| 27 | + |
| 28 | + template <typename T> |
| 29 | + bool consumeObject(ArrayRef<uint8_t> &Data, const T *&Res) { |
| 30 | + if (Data.size() < sizeof(*Res)) { |
| 31 | + HadError = true; |
| 32 | + return false; |
| 33 | + } |
| 34 | + Res = reinterpret_cast<const T *>(Data.data()); |
| 35 | + Data = Data.drop_front(sizeof(*Res)); |
| 36 | + return true; |
| 37 | + } |
| 38 | + |
| 39 | + /// Actions to take on known types. By default, they do nothing. Visit methods |
| 40 | + /// for member records take the FieldData by non-const reference and are |
| 41 | + /// expected to consume the trailing bytes used by the field. |
| 42 | + /// FIXME: Make the visitor interpret the trailing bytes so that clients don't |
| 43 | + /// need to. |
| 44 | +#define TYPE_RECORD(ClassName, LeafEnum) \ |
| 45 | + void visit##ClassName(TypeLeafKind LeafType, const ClassName *Record, \ |
| 46 | + ArrayRef<uint8_t> LeafData) {} |
| 47 | +#define TYPE_RECORD_ALIAS(ClassName, LeafEnum) |
| 48 | +#define MEMBER_RECORD(ClassName, LeafEnum) \ |
| 49 | + void visit##ClassName(TypeLeafKind LeafType, const ClassName *Record, \ |
| 50 | + ArrayRef<uint8_t> &FieldData) {} |
| 51 | +#define MEMBER_RECORD_ALIAS(ClassName, LeafEnum) |
| 52 | +#include "TypeRecords.def" |
| 53 | + |
| 54 | + /// Visits the type records in Data and returns remaining data. Sets the |
| 55 | + /// error flag on parse failures. |
| 56 | + void visitTypeStream(ArrayRef<uint8_t> Data) { |
| 57 | + for (const auto &I : makeTypeRange(Data)) { |
| 58 | + ArrayRef<uint8_t> LeafData = I.LeafData; |
| 59 | + ArrayRef<uint8_t> RecordData = LeafData; |
| 60 | + auto *DerivedThis = static_cast<Derived *>(this); |
| 61 | + DerivedThis->visitTypeBegin(I.Leaf, RecordData); |
| 62 | + switch (I.Leaf) { |
| 63 | + default: |
| 64 | + DerivedThis->visitUnknownType(I.Leaf); |
| 65 | + break; |
| 66 | + case LF_FIELDLIST: |
| 67 | + DerivedThis->visitFieldList(I.Leaf, LeafData); |
| 68 | + break; |
| 69 | + case LF_METHODLIST: |
| 70 | + DerivedThis->visitMethodList(I.Leaf, LeafData); |
| 71 | + break; |
| 72 | +#define TYPE_RECORD(ClassName, LeafEnum) \ |
| 73 | + case LeafEnum: { \ |
| 74 | + const ClassName *Rec; \ |
| 75 | + if (!CVTypeVisitor::consumeObject(LeafData, Rec)) \ |
| 76 | + return; \ |
| 77 | + DerivedThis->visit##ClassName(I.Leaf, Rec, LeafData); \ |
| 78 | + break; \ |
| 79 | + } |
| 80 | +#include "TypeRecords.def" |
| 81 | + } |
| 82 | + DerivedThis->visitTypeEnd(I.Leaf, RecordData); |
| 83 | + } |
| 84 | + } |
| 85 | + |
| 86 | + /// Action to take on unknown types. By default, they are ignored. |
| 87 | + void visitUnknownType(TypeLeafKind Leaf) {} |
| 88 | + |
| 89 | + /// Paired begin/end actions for all types. Receives all record data, |
| 90 | + /// including the fixed-length record prefix. |
| 91 | + void visitTypeBegin(TypeLeafKind Leaf, ArrayRef<uint8_t> RecordData) {} |
| 92 | + void visitTypeEnd(TypeLeafKind Leaf, ArrayRef<uint8_t> RecordData) {} |
| 93 | + |
| 94 | + static ArrayRef<uint8_t> skipPadding(ArrayRef<uint8_t> Data) { |
| 95 | + if (Data.empty()) |
| 96 | + return Data; |
| 97 | + uint8_t Leaf = Data.front(); |
| 98 | + if (Leaf < LF_PAD0) |
| 99 | + return Data; |
| 100 | + // Leaf is greater than 0xf0. We should advance by the number of bytes in |
| 101 | + // the low 4 bits. |
| 102 | + return Data.drop_front(Leaf & 0x0F); |
| 103 | + } |
| 104 | + |
| 105 | + /// Visits individual member records of a field list record. Member records do |
| 106 | + /// not describe their own length, and need special handling. |
| 107 | + void visitFieldList(TypeLeafKind Leaf, ArrayRef<uint8_t> FieldData) { |
| 108 | + while (!FieldData.empty()) { |
| 109 | + const ulittle16_t *LeafPtr; |
| 110 | + if (!CVTypeVisitor::consumeObject(FieldData, LeafPtr)) |
| 111 | + return; |
| 112 | + TypeLeafKind Leaf = TypeLeafKind(unsigned(*LeafPtr)); |
| 113 | + switch (Leaf) { |
| 114 | + default: |
| 115 | + // Field list records do not describe their own length, so we cannot |
| 116 | + // continue parsing past an unknown member type. |
| 117 | + visitUnknownMember(Leaf); |
| 118 | + HadError = true; |
| 119 | + return; |
| 120 | +#define MEMBER_RECORD(ClassName, LeafEnum) \ |
| 121 | + case LeafEnum: { \ |
| 122 | + const ClassName *Rec; \ |
| 123 | + if (!CVTypeVisitor::consumeObject(FieldData, Rec)) \ |
| 124 | + return; \ |
| 125 | + static_cast<Derived *>(this)->visit##ClassName(Leaf, Rec, FieldData); \ |
| 126 | + break; \ |
| 127 | + } |
| 128 | +#include "TypeRecords.def" |
| 129 | + } |
| 130 | + FieldData = skipPadding(FieldData); |
| 131 | + } |
| 132 | + } |
| 133 | + |
| 134 | + /// Action to take on method overload lists, which do not have a common record |
| 135 | + /// prefix. The LeafData is composed of MethodListEntry objects, each of which |
| 136 | + /// may have a trailing 32-bit vftable offset. |
| 137 | + /// FIXME: Hoist this complexity into the visitor. |
| 138 | + void visitMethodList(TypeLeafKind Leaf, ArrayRef<uint8_t> LeafData) {} |
| 139 | + |
| 140 | + /// Action to take on unknown members. By default, they are ignored. Member |
| 141 | + /// record parsing cannot recover from an unknown member record, so this |
| 142 | + /// method is only called at most once per field list record. |
| 143 | + void visitUnknownMember(TypeLeafKind Leaf) {} |
| 144 | + |
| 145 | +private: |
| 146 | + /// Whether a type stream parsing error was encountered. |
| 147 | + bool HadError = false; |
| 148 | +}; |
| 149 | + |
| 150 | +} // end namespace codeview |
| 151 | +} // end namespace llvm |
| 152 | + |
| 153 | +#endif // LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H |
0 commit comments