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 ~CodeViewRecordStreamer() = default;
39 class CodeViewRecordIO {
40 uint32_t getCurrentOffset() const {
42 return Writer->getOffset();
44 return Reader->getOffset();
50 // deserializes records to structures
51 explicit CodeViewRecordIO(BinaryStreamReader &Reader) : Reader(&Reader) {}
53 // serializes records to buffer
54 explicit CodeViewRecordIO(BinaryStreamWriter &Writer) : Writer(&Writer) {}
56 // writes records to assembly file using MC library interface
57 explicit CodeViewRecordIO(CodeViewRecordStreamer &Streamer)
58 : Streamer(&Streamer) {}
60 Error beginRecord(Optional<uint32_t> MaxLength);
63 Error mapInteger(TypeIndex &TypeInd, const Twine &Comment = "");
65 bool isStreaming() const {
66 return (Streamer != nullptr) && (Reader == nullptr) && (Writer == nullptr);
68 bool isReading() const {
69 return (Reader != nullptr) && (Streamer == nullptr) && (Writer == nullptr);
71 bool isWriting() const {
72 return (Writer != nullptr) && (Streamer == nullptr) && (Reader == nullptr);
75 uint32_t maxFieldLength() const;
77 template <typename T> Error mapObject(T &Value) {
80 StringRef((reinterpret_cast<const char *>(&Value)), sizeof(Value));
81 Streamer->EmitBytes(BytesSR);
82 incrStreamedLen(sizeof(T));
83 return Error::success();
87 return Writer->writeObject(Value);
90 if (auto EC = Reader->readObject(ValuePtr))
93 return Error::success();
96 template <typename T> Error mapInteger(T &Value, const Twine &Comment = "") {
99 Streamer->EmitIntValue((int)Value, sizeof(T));
100 incrStreamedLen(sizeof(T));
101 return Error::success();
105 return Writer->writeInteger(Value);
107 return Reader->readInteger(Value);
110 template <typename T> Error mapEnum(T &Value, const Twine &Comment = "") {
111 if (!isStreaming() && sizeof(Value) > maxFieldLength())
112 return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
114 using U = typename std::underlying_type<T>::type;
117 if (isWriting() || isStreaming())
118 X = static_cast<U>(Value);
120 if (auto EC = mapInteger(X, Comment))
124 Value = static_cast<T>(X);
126 return Error::success();
129 Error mapEncodedInteger(int64_t &Value, const Twine &Comment = "");
130 Error mapEncodedInteger(uint64_t &Value, const Twine &Comment = "");
131 Error mapEncodedInteger(APSInt &Value, const Twine &Comment = "");
132 Error mapStringZ(StringRef &Value, const Twine &Comment = "");
133 Error mapGuid(GUID &Guid, const Twine &Comment = "");
135 Error mapStringZVectorZ(std::vector<StringRef> &Value,
136 const Twine &Comment = "");
138 template <typename SizeType, typename T, typename ElementMapper>
139 Error mapVectorN(T &Items, const ElementMapper &Mapper,
140 const Twine &Comment = "") {
143 Size = static_cast<SizeType>(Items.size());
144 emitComment(Comment);
145 Streamer->EmitIntValue(Size, sizeof(Size));
146 incrStreamedLen(sizeof(Size)); // add 1 for the delimiter
148 for (auto &X : Items) {
149 if (auto EC = Mapper(*this, X))
152 } else if (isWriting()) {
153 Size = static_cast<SizeType>(Items.size());
154 if (auto EC = Writer->writeInteger(Size))
157 for (auto &X : Items) {
158 if (auto EC = Mapper(*this, X))
162 if (auto EC = Reader->readInteger(Size))
164 for (SizeType I = 0; I < Size; ++I) {
165 typename T::value_type Item;
166 if (auto EC = Mapper(*this, Item))
168 Items.push_back(Item);
172 return Error::success();
175 template <typename T, typename ElementMapper>
176 Error mapVectorTail(T &Items, const ElementMapper &Mapper,
177 const Twine &Comment = "") {
178 emitComment(Comment);
179 if (isStreaming() || isWriting()) {
180 for (auto &Item : Items) {
181 if (auto EC = Mapper(*this, Item))
185 typename T::value_type Field;
186 // Stop when we run out of bytes or we hit record padding bytes.
187 while (!Reader->empty() && Reader->peek() < 0xf0 /* LF_PAD0 */) {
188 if (auto EC = Mapper(*this, Field))
190 Items.push_back(Field);
193 return Error::success();
196 Error mapByteVectorTail(ArrayRef<uint8_t> &Bytes, const Twine &Comment = "");
197 Error mapByteVectorTail(std::vector<uint8_t> &Bytes,
198 const Twine &Comment = "");
200 Error padToAlignment(uint32_t Align);
203 uint64_t getStreamedLen() {
210 void emitEncodedSignedInteger(const int64_t &Value,
211 const Twine &Comment = "");
212 void emitEncodedUnsignedInteger(const uint64_t &Value,
213 const Twine &Comment = "");
214 Error writeEncodedSignedInteger(const int64_t &Value);
215 Error writeEncodedUnsignedInteger(const uint64_t &Value);
217 void incrStreamedLen(const uint64_t &Len) {
222 void resetStreamedLen() {
224 StreamedLen = 4; // The record prefix is 4 bytes long
227 void emitComment(const Twine &Comment) {
229 Twine TComment(Comment);
230 Streamer->AddComment(TComment);
235 uint32_t BeginOffset;
236 Optional<uint32_t> MaxLength;
238 Optional<uint32_t> bytesRemaining(uint32_t CurrentOffset) const {
239 if (!MaxLength.hasValue())
241 assert(CurrentOffset >= BeginOffset);
243 uint32_t BytesUsed = CurrentOffset - BeginOffset;
244 if (BytesUsed >= *MaxLength)
246 return *MaxLength - BytesUsed;
250 SmallVector<RecordLimit, 2> Limits;
252 BinaryStreamReader *Reader = nullptr;
253 BinaryStreamWriter *Writer = nullptr;
254 CodeViewRecordStreamer *Streamer = nullptr;
255 uint64_t StreamedLen = 0;
258 } // end namespace codeview
259 } // end namespace llvm
261 #endif // LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H