1 //===- CVTypeVisitor.cpp ----------------------------------------*- 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 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" 11 12 using namespace llvm; 13 using namespace llvm::codeview; 14 15 template <typename T> 16 static Error takeObject(ArrayRef<uint8_t> &Data, const T *&Res) { 17 if (Data.size() < sizeof(*Res)) 18 return llvm::make_error<CodeViewError>(cv_error_code::insufficient_buffer); 19 Res = reinterpret_cast<const T *>(Data.data()); 20 Data = Data.drop_front(sizeof(*Res)); 21 return Error::success(); 22 } 23 24 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) 25 : Callbacks(Callbacks) {} 26 27 Error CVTypeVisitor::visitTypeRecord(const CVRecord<TypeLeafKind> &Record) { 28 ArrayRef<uint8_t> LeafData = Record.Data; 29 if (auto EC = Callbacks.visitTypeBegin(Record)) 30 return EC; 31 switch (Record.Type) { 32 default: 33 if (auto EC = Callbacks.visitUnknownType(Record)) 34 return EC; 35 break; 36 case LF_FIELDLIST: 37 if (auto EC = Callbacks.visitFieldListBegin(Record)) 38 return EC; 39 if (auto EC = visitFieldList(Record)) 40 return EC; 41 if (auto EC = Callbacks.visitFieldListEnd(Record)) 42 return EC; 43 break; 44 #define TYPE_RECORD(EnumName, EnumVal, Name) \ 45 case EnumName: { \ 46 TypeRecordKind RK = static_cast<TypeRecordKind>(EnumName); \ 47 auto Result = Name##Record::deserialize(RK, LeafData); \ 48 if (Result.getError()) \ 49 return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record); \ 50 if (auto EC = Callbacks.visit##Name(*Result)) \ 51 return EC; \ 52 break; \ 53 } 54 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ 55 TYPE_RECORD(EnumVal, EnumVal, AliasName) 56 #define MEMBER_RECORD(EnumName, EnumVal, Name) 57 #include "llvm/DebugInfo/CodeView/TypeRecords.def" 58 } 59 if (auto EC = Callbacks.visitTypeEnd(Record)) 60 return EC; 61 return Error::success(); 62 } 63 64 /// Visits the type records in Data. Sets the error flag on parse failures. 65 Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) { 66 for (const auto &I : Types) { 67 if (auto EC = visitTypeRecord(I)) 68 return EC; 69 } 70 return Error::success(); 71 } 72 73 Error CVTypeVisitor::skipPadding(ArrayRef<uint8_t> &Data) { 74 if (Data.empty()) 75 return Error::success(); 76 uint8_t Leaf = Data.front(); 77 if (Leaf < LF_PAD0) 78 return Error::success(); 79 // Leaf is greater than 0xf0. We should advance by the number of bytes in 80 // the low 4 bits. 81 unsigned BytesToAdvance = Leaf & 0x0F; 82 if (Data.size() < BytesToAdvance) { 83 return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record, 84 "Invalid padding bytes!"); 85 } 86 Data = Data.drop_front(BytesToAdvance); 87 return Error::success(); 88 } 89 90 /// Visits individual member records of a field list record. Member records do 91 /// not describe their own length, and need special handling. 92 Error CVTypeVisitor::visitFieldList(const CVRecord<TypeLeafKind> &Record) { 93 ArrayRef<uint8_t> RecordData = Record.Data; 94 while (!RecordData.empty()) { 95 const ulittle16_t *LeafPtr; 96 if (auto EC = takeObject(RecordData, LeafPtr)) 97 return EC; 98 TypeLeafKind Leaf = TypeLeafKind(unsigned(*LeafPtr)); 99 switch (Leaf) { 100 default: 101 // Field list records do not describe their own length, so we cannot 102 // continue parsing past an unknown member type. 103 if (auto EC = Callbacks.visitUnknownMember(Record)) 104 return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record); 105 #define MEMBER_RECORD(EnumName, EnumVal, Name) \ 106 case EnumName: { \ 107 TypeRecordKind RK = static_cast<TypeRecordKind>(EnumName); \ 108 auto Result = Name##Record::deserialize(RK, RecordData); \ 109 if (Result.getError()) \ 110 return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record); \ 111 if (auto EC = Callbacks.visit##Name(*Result)) \ 112 return EC; \ 113 break; \ 114 } 115 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ 116 MEMBER_RECORD(EnumVal, EnumVal, AliasName) 117 #include "llvm/DebugInfo/CodeView/TypeRecords.def" 118 } 119 if (auto EC = skipPadding(RecordData)) 120 return EC; 121 } 122 return Error::success(); 123 } 124