1 //===- CodeViewRecordIO.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_CODEVIEWRECORDIO_H
10 #define LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H
12 #include "llvm/ADT/APSInt.h"
13 #include "llvm/ADT/None.h"
14 #include "llvm/ADT/Optional.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
18 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
19 #include "llvm/Support/BinaryStreamReader.h"
20 #include "llvm/Support/BinaryStreamWriter.h"
21 #include "llvm/Support/Error.h"
24 #include <type_traits>
30 class CodeViewRecordStreamer
{
32 virtual void EmitBytes(StringRef Data
) = 0;
33 virtual void EmitIntValue(uint64_t Value
, unsigned Size
) = 0;
34 virtual void EmitBinaryData(StringRef Data
) = 0;
35 virtual void AddComment(const Twine
&T
) = 0;
36 virtual void AddRawComment(const Twine
&T
) = 0;
37 virtual bool isVerboseAsm() = 0;
38 virtual std::string
getTypeName(TypeIndex TI
) = 0;
39 virtual ~CodeViewRecordStreamer() = default;
42 class CodeViewRecordIO
{
43 uint32_t getCurrentOffset() const {
45 return Writer
->getOffset();
47 return Reader
->getOffset();
53 // deserializes records to structures
54 explicit CodeViewRecordIO(BinaryStreamReader
&Reader
) : Reader(&Reader
) {}
56 // serializes records to buffer
57 explicit CodeViewRecordIO(BinaryStreamWriter
&Writer
) : Writer(&Writer
) {}
59 // writes records to assembly file using MC library interface
60 explicit CodeViewRecordIO(CodeViewRecordStreamer
&Streamer
)
61 : Streamer(&Streamer
) {}
63 Error
beginRecord(Optional
<uint32_t> MaxLength
);
66 Error
mapInteger(TypeIndex
&TypeInd
, const Twine
&Comment
= "");
68 bool isStreaming() const {
69 return (Streamer
!= nullptr) && (Reader
== nullptr) && (Writer
== nullptr);
71 bool isReading() const {
72 return (Reader
!= nullptr) && (Streamer
== nullptr) && (Writer
== nullptr);
74 bool isWriting() const {
75 return (Writer
!= nullptr) && (Streamer
== nullptr) && (Reader
== nullptr);
78 uint32_t maxFieldLength() const;
80 template <typename T
> Error
mapObject(T
&Value
) {
83 StringRef((reinterpret_cast<const char *>(&Value
)), sizeof(Value
));
84 Streamer
->EmitBytes(BytesSR
);
85 incrStreamedLen(sizeof(T
));
86 return Error::success();
90 return Writer
->writeObject(Value
);
93 if (auto EC
= Reader
->readObject(ValuePtr
))
96 return Error::success();
99 template <typename T
> Error
mapInteger(T
&Value
, const Twine
&Comment
= "") {
101 emitComment(Comment
);
102 Streamer
->EmitIntValue((int)Value
, sizeof(T
));
103 incrStreamedLen(sizeof(T
));
104 return Error::success();
108 return Writer
->writeInteger(Value
);
110 return Reader
->readInteger(Value
);
113 template <typename T
> Error
mapEnum(T
&Value
, const Twine
&Comment
= "") {
114 if (!isStreaming() && sizeof(Value
) > maxFieldLength())
115 return make_error
<CodeViewError
>(cv_error_code::insufficient_buffer
);
117 using U
= typename
std::underlying_type
<T
>::type
;
120 if (isWriting() || isStreaming())
121 X
= static_cast<U
>(Value
);
123 if (auto EC
= mapInteger(X
, Comment
))
127 Value
= static_cast<T
>(X
);
129 return Error::success();
132 Error
mapEncodedInteger(int64_t &Value
, const Twine
&Comment
= "");
133 Error
mapEncodedInteger(uint64_t &Value
, const Twine
&Comment
= "");
134 Error
mapEncodedInteger(APSInt
&Value
, const Twine
&Comment
= "");
135 Error
mapStringZ(StringRef
&Value
, const Twine
&Comment
= "");
136 Error
mapGuid(GUID
&Guid
, const Twine
&Comment
= "");
138 Error
mapStringZVectorZ(std::vector
<StringRef
> &Value
,
139 const Twine
&Comment
= "");
141 template <typename SizeType
, typename T
, typename ElementMapper
>
142 Error
mapVectorN(T
&Items
, const ElementMapper
&Mapper
,
143 const Twine
&Comment
= "") {
146 Size
= static_cast<SizeType
>(Items
.size());
147 emitComment(Comment
);
148 Streamer
->EmitIntValue(Size
, sizeof(Size
));
149 incrStreamedLen(sizeof(Size
)); // add 1 for the delimiter
151 for (auto &X
: Items
) {
152 if (auto EC
= Mapper(*this, X
))
155 } else if (isWriting()) {
156 Size
= static_cast<SizeType
>(Items
.size());
157 if (auto EC
= Writer
->writeInteger(Size
))
160 for (auto &X
: Items
) {
161 if (auto EC
= Mapper(*this, X
))
165 if (auto EC
= Reader
->readInteger(Size
))
167 for (SizeType I
= 0; I
< Size
; ++I
) {
168 typename
T::value_type Item
;
169 if (auto EC
= Mapper(*this, Item
))
171 Items
.push_back(Item
);
175 return Error::success();
178 template <typename T
, typename ElementMapper
>
179 Error
mapVectorTail(T
&Items
, const ElementMapper
&Mapper
,
180 const Twine
&Comment
= "") {
181 emitComment(Comment
);
182 if (isStreaming() || isWriting()) {
183 for (auto &Item
: Items
) {
184 if (auto EC
= Mapper(*this, Item
))
188 typename
T::value_type Field
;
189 // Stop when we run out of bytes or we hit record padding bytes.
190 while (!Reader
->empty() && Reader
->peek() < 0xf0 /* LF_PAD0 */) {
191 if (auto EC
= Mapper(*this, Field
))
193 Items
.push_back(Field
);
196 return Error::success();
199 Error
mapByteVectorTail(ArrayRef
<uint8_t> &Bytes
, const Twine
&Comment
= "");
200 Error
mapByteVectorTail(std::vector
<uint8_t> &Bytes
,
201 const Twine
&Comment
= "");
203 Error
padToAlignment(uint32_t Align
);
206 uint64_t getStreamedLen() {
212 void emitRawComment(const Twine
&T
) {
213 if (isStreaming() && Streamer
->isVerboseAsm())
214 Streamer
->AddRawComment(T
);
218 void emitEncodedSignedInteger(const int64_t &Value
,
219 const Twine
&Comment
= "");
220 void emitEncodedUnsignedInteger(const uint64_t &Value
,
221 const Twine
&Comment
= "");
222 Error
writeEncodedSignedInteger(const int64_t &Value
);
223 Error
writeEncodedUnsignedInteger(const uint64_t &Value
);
225 void incrStreamedLen(const uint64_t &Len
) {
230 void resetStreamedLen() {
232 StreamedLen
= 4; // The record prefix is 4 bytes long
235 void emitComment(const Twine
&Comment
) {
236 if (isStreaming() && Streamer
->isVerboseAsm()) {
237 Twine
TComment(Comment
);
238 if (!TComment
.isTriviallyEmpty())
239 Streamer
->AddComment(TComment
);
244 uint32_t BeginOffset
;
245 Optional
<uint32_t> MaxLength
;
247 Optional
<uint32_t> bytesRemaining(uint32_t CurrentOffset
) const {
248 if (!MaxLength
.hasValue())
250 assert(CurrentOffset
>= BeginOffset
);
252 uint32_t BytesUsed
= CurrentOffset
- BeginOffset
;
253 if (BytesUsed
>= *MaxLength
)
255 return *MaxLength
- BytesUsed
;
259 SmallVector
<RecordLimit
, 2> Limits
;
261 BinaryStreamReader
*Reader
= nullptr;
262 BinaryStreamWriter
*Writer
= nullptr;
263 CodeViewRecordStreamer
*Streamer
= nullptr;
264 uint64_t StreamedLen
= 0;
267 } // end namespace codeview
268 } // end namespace llvm
270 #endif // LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H