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 template <typename Kind
> class CVRecord
{
29 CVRecord() : Type(static_cast<Kind
>(0)) {}
31 CVRecord(Kind K
, ArrayRef
<uint8_t> Data
) : Type(K
), RecordData(Data
) {}
33 bool valid() const { return Type
!= static_cast<Kind
>(0); }
35 uint32_t length() const { return RecordData
.size(); }
36 Kind
kind() const { return Type
; }
37 ArrayRef
<uint8_t> data() const { return RecordData
; }
38 StringRef
str_data() const {
39 return StringRef(reinterpret_cast<const char *>(RecordData
.data()),
43 ArrayRef
<uint8_t> content() const {
44 return RecordData
.drop_front(sizeof(RecordPrefix
));
48 ArrayRef
<uint8_t> RecordData
;
51 template <typename Kind
> struct RemappedRecord
{
52 explicit RemappedRecord(const CVRecord
<Kind
> &R
) : OriginalRecord(R
) {}
54 CVRecord
<Kind
> OriginalRecord
;
55 SmallVector
<std::pair
<uint32_t, TypeIndex
>, 8> Mappings
;
58 template <typename Record
, typename Func
>
59 Error
forEachCodeViewRecord(ArrayRef
<uint8_t> StreamBuffer
, Func F
) {
60 while (!StreamBuffer
.empty()) {
61 if (StreamBuffer
.size() < sizeof(RecordPrefix
))
62 return make_error
<CodeViewError
>(cv_error_code::corrupt_record
);
64 const RecordPrefix
*Prefix
=
65 reinterpret_cast<const RecordPrefix
*>(StreamBuffer
.data());
67 size_t RealLen
= Prefix
->RecordLen
+ 2;
68 if (StreamBuffer
.size() < RealLen
)
69 return make_error
<CodeViewError
>(cv_error_code::corrupt_record
);
71 ArrayRef
<uint8_t> Data
= StreamBuffer
.take_front(RealLen
);
72 StreamBuffer
= StreamBuffer
.drop_front(RealLen
);
74 Record
R(static_cast<decltype(Record::Type
)>((uint16_t)Prefix
->RecordKind
),
79 return Error::success();
82 /// Read a complete record from a stream at a random offset.
83 template <typename Kind
>
84 inline Expected
<CVRecord
<Kind
>> readCVRecordFromStream(BinaryStreamRef Stream
,
86 const RecordPrefix
*Prefix
= nullptr;
87 BinaryStreamReader
Reader(Stream
);
88 Reader
.setOffset(Offset
);
90 if (auto EC
= Reader
.readObject(Prefix
))
92 if (Prefix
->RecordLen
< 2)
93 return make_error
<CodeViewError
>(cv_error_code::corrupt_record
);
94 Kind K
= static_cast<Kind
>(uint16_t(Prefix
->RecordKind
));
96 Reader
.setOffset(Offset
);
97 ArrayRef
<uint8_t> RawData
;
98 if (auto EC
= Reader
.readBytes(RawData
, Prefix
->RecordLen
+ sizeof(uint16_t)))
100 return codeview::CVRecord
<Kind
>(K
, RawData
);
103 } // end namespace codeview
105 template <typename Kind
>
106 struct VarStreamArrayExtractor
<codeview::CVRecord
<Kind
>> {
107 Error
operator()(BinaryStreamRef Stream
, uint32_t &Len
,
108 codeview::CVRecord
<Kind
> &Item
) {
109 auto ExpectedRec
= codeview::readCVRecordFromStream
<Kind
>(Stream
, 0);
111 return ExpectedRec
.takeError();
113 Len
= ExpectedRec
->length();
114 return Error::success();
118 } // end namespace llvm
120 #endif // LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H