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>
takeObject(ArrayRef<uint8_t> & Data,const T * & Res)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
CVTypeVisitor(TypeVisitorCallbacks & Callbacks)24 CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
25 : Callbacks(Callbacks) {}
26
visitTypeRecord(const CVRecord<TypeLeafKind> & Record)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.
visitTypeStream(const CVTypeArray & Types)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
skipPadding(ArrayRef<uint8_t> & Data)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.
visitFieldList(const CVRecord<TypeLeafKind> & Record)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