[llvm] [cmake] Add possibility to use ChooseMSVCCRT.cmake when include LLVM library
[llvm-core.git] / include / llvm / DebugInfo / CodeView / CodeViewRecordIO.h
blob60829a51dc25b7527289f0550879d3b94b846f03
1 //===- CodeViewRecordIO.h ---------------------------------------*- C++ -*-===//
2 //
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
6 //
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"
22 #include <cassert>
23 #include <cstdint>
24 #include <type_traits>
26 namespace llvm {
28 namespace codeview {
30 class CodeViewRecordStreamer {
31 public:
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 {
44 if (isWriting())
45 return Writer->getOffset();
46 else if (isReading())
47 return Reader->getOffset();
48 else
49 return 0;
52 public:
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);
64 Error endRecord();
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) {
81 if (isStreaming()) {
82 StringRef BytesSR =
83 StringRef((reinterpret_cast<const char *>(&Value)), sizeof(Value));
84 Streamer->EmitBytes(BytesSR);
85 incrStreamedLen(sizeof(T));
86 return Error::success();
89 if (isWriting())
90 return Writer->writeObject(Value);
92 const T *ValuePtr;
93 if (auto EC = Reader->readObject(ValuePtr))
94 return EC;
95 Value = *ValuePtr;
96 return Error::success();
99 template <typename T> Error mapInteger(T &Value, const Twine &Comment = "") {
100 if (isStreaming()) {
101 emitComment(Comment);
102 Streamer->EmitIntValue((int)Value, sizeof(T));
103 incrStreamedLen(sizeof(T));
104 return Error::success();
107 if (isWriting())
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;
118 U X;
120 if (isWriting() || isStreaming())
121 X = static_cast<U>(Value);
123 if (auto EC = mapInteger(X, Comment))
124 return EC;
126 if (isReading())
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 = "") {
144 SizeType Size;
145 if (isStreaming()) {
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))
153 return EC;
155 } else if (isWriting()) {
156 Size = static_cast<SizeType>(Items.size());
157 if (auto EC = Writer->writeInteger(Size))
158 return EC;
160 for (auto &X : Items) {
161 if (auto EC = Mapper(*this, X))
162 return EC;
164 } else {
165 if (auto EC = Reader->readInteger(Size))
166 return EC;
167 for (SizeType I = 0; I < Size; ++I) {
168 typename T::value_type Item;
169 if (auto EC = Mapper(*this, Item))
170 return EC;
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))
185 return EC;
187 } else {
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))
192 return EC;
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);
204 Error skipPadding();
206 uint64_t getStreamedLen() {
207 if (isStreaming())
208 return StreamedLen;
209 return 0;
212 void emitRawComment(const Twine &T) {
213 if (isStreaming() && Streamer->isVerboseAsm())
214 Streamer->AddRawComment(T);
217 private:
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) {
226 if (isStreaming())
227 StreamedLen += Len;
230 void resetStreamedLen() {
231 if (isStreaming())
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);
243 struct RecordLimit {
244 uint32_t BeginOffset;
245 Optional<uint32_t> MaxLength;
247 Optional<uint32_t> bytesRemaining(uint32_t CurrentOffset) const {
248 if (!MaxLength.hasValue())
249 return None;
250 assert(CurrentOffset >= BeginOffset);
252 uint32_t BytesUsed = CurrentOffset - BeginOffset;
253 if (BytesUsed >= *MaxLength)
254 return 0;
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