]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
Upgrade to OpenSSH 7.3p1.
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / DebugInfo / CodeView / CVTypeVisitor.cpp
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 }