1 //===- CVRecord.h -----------------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H
10 #define LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/Optional.h"
14 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
15 #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
16 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
17 #include "llvm/Support/BinaryStreamReader.h"
18 #include "llvm/Support/BinaryStreamRef.h"
19 #include "llvm/Support/Endian.h"
20 #include "llvm/Support/Error.h"
27 /// CVRecord is a fat pointer (base + size pair) to a symbol or type record.
28 /// Carrying the size separately instead of trusting the size stored in the
29 /// record prefix provides some extra safety and flexibility.
30 template <typename Kind
> class CVRecord
{
34 CVRecord(ArrayRef
<uint8_t> Data
) : RecordData(Data
) {}
36 CVRecord(const RecordPrefix
*P
, size_t Size
)
37 : RecordData(reinterpret_cast<const uint8_t *>(P
), Size
) {}
39 bool valid() const { return kind() != Kind(0); }
41 uint32_t length() const { return RecordData
.size(); }
44 if (RecordData
.size() < sizeof(RecordPrefix
))
46 return static_cast<Kind
>(static_cast<uint16_t>(
47 reinterpret_cast<const RecordPrefix
*>(RecordData
.data())->RecordKind
));
50 ArrayRef
<uint8_t> data() const { return RecordData
; }
52 StringRef
str_data() const {
53 return StringRef(reinterpret_cast<const char *>(RecordData
.data()),
57 ArrayRef
<uint8_t> content() const {
58 return RecordData
.drop_front(sizeof(RecordPrefix
));
61 ArrayRef
<uint8_t> RecordData
;
64 template <typename Kind
> struct RemappedRecord
{
65 explicit RemappedRecord(const CVRecord
<Kind
> &R
) : OriginalRecord(R
) {}
67 CVRecord
<Kind
> OriginalRecord
;
68 SmallVector
<std::pair
<uint32_t, TypeIndex
>, 8> Mappings
;
71 template <typename Record
, typename Func
>
72 Error
forEachCodeViewRecord(ArrayRef
<uint8_t> StreamBuffer
, Func F
) {
73 while (!StreamBuffer
.empty()) {
74 if (StreamBuffer
.size() < sizeof(RecordPrefix
))
75 return make_error
<CodeViewError
>(cv_error_code::corrupt_record
);
77 const RecordPrefix
*Prefix
=
78 reinterpret_cast<const RecordPrefix
*>(StreamBuffer
.data());
80 size_t RealLen
= Prefix
->RecordLen
+ 2;
81 if (StreamBuffer
.size() < RealLen
)
82 return make_error
<CodeViewError
>(cv_error_code::corrupt_record
);
84 ArrayRef
<uint8_t> Data
= StreamBuffer
.take_front(RealLen
);
85 StreamBuffer
= StreamBuffer
.drop_front(RealLen
);
91 return Error::success();
94 /// Read a complete record from a stream at a random offset.
95 template <typename Kind
>
96 inline Expected
<CVRecord
<Kind
>> readCVRecordFromStream(BinaryStreamRef Stream
,
98 const RecordPrefix
*Prefix
= nullptr;
99 BinaryStreamReader
Reader(Stream
);
100 Reader
.setOffset(Offset
);
102 if (auto EC
= Reader
.readObject(Prefix
))
103 return std::move(EC
);
104 if (Prefix
->RecordLen
< 2)
105 return make_error
<CodeViewError
>(cv_error_code::corrupt_record
);
107 Reader
.setOffset(Offset
);
108 ArrayRef
<uint8_t> RawData
;
109 if (auto EC
= Reader
.readBytes(RawData
, Prefix
->RecordLen
+ sizeof(uint16_t)))
110 return std::move(EC
);
111 return codeview::CVRecord
<Kind
>(RawData
);
114 } // end namespace codeview
116 template <typename Kind
>
117 struct VarStreamArrayExtractor
<codeview::CVRecord
<Kind
>> {
118 Error
operator()(BinaryStreamRef Stream
, uint32_t &Len
,
119 codeview::CVRecord
<Kind
> &Item
) {
120 auto ExpectedRec
= codeview::readCVRecordFromStream
<Kind
>(Stream
, 0);
122 return ExpectedRec
.takeError();
124 Len
= ExpectedRec
->length();
125 return Error::success();
129 } // end namespace llvm
131 #endif // LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H