]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / include / llvm / DebugInfo / CodeView / CodeViewRecordIO.h
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 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H
10 #define LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H
11
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>
25
26 namespace llvm {
27
28 namespace codeview {
29
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 ~CodeViewRecordStreamer() = default;
37 };
38
39 class CodeViewRecordIO {
40   uint32_t getCurrentOffset() const {
41     if (isWriting())
42       return Writer->getOffset();
43     else if (isReading())
44       return Reader->getOffset();
45     else
46       return 0;
47   }
48
49 public:
50   // deserializes records to structures
51   explicit CodeViewRecordIO(BinaryStreamReader &Reader) : Reader(&Reader) {}
52
53   // serializes records to buffer
54   explicit CodeViewRecordIO(BinaryStreamWriter &Writer) : Writer(&Writer) {}
55
56   // writes records to assembly file using MC library interface
57   explicit CodeViewRecordIO(CodeViewRecordStreamer &Streamer)
58       : Streamer(&Streamer) {}
59
60   Error beginRecord(Optional<uint32_t> MaxLength);
61   Error endRecord();
62
63   Error mapInteger(TypeIndex &TypeInd, const Twine &Comment = "");
64
65   bool isStreaming() const {
66     return (Streamer != nullptr) && (Reader == nullptr) && (Writer == nullptr);
67   }
68   bool isReading() const {
69     return (Reader != nullptr) && (Streamer == nullptr) && (Writer == nullptr);
70   }
71   bool isWriting() const {
72     return (Writer != nullptr) && (Streamer == nullptr) && (Reader == nullptr);
73   }
74
75   uint32_t maxFieldLength() const;
76
77   template <typename T> Error mapObject(T &Value) {
78     if (isStreaming()) {
79       StringRef BytesSR =
80           StringRef((reinterpret_cast<const char *>(&Value)), sizeof(Value));
81       Streamer->EmitBytes(BytesSR);
82       incrStreamedLen(sizeof(T));
83       return Error::success();
84     }
85
86     if (isWriting())
87       return Writer->writeObject(Value);
88
89     const T *ValuePtr;
90     if (auto EC = Reader->readObject(ValuePtr))
91       return EC;
92     Value = *ValuePtr;
93     return Error::success();
94   }
95
96   template <typename T> Error mapInteger(T &Value, const Twine &Comment = "") {
97     if (isStreaming()) {
98       emitComment(Comment);
99       Streamer->EmitIntValue((int)Value, sizeof(T));
100       incrStreamedLen(sizeof(T));
101       return Error::success();
102     }
103
104     if (isWriting())
105       return Writer->writeInteger(Value);
106
107     return Reader->readInteger(Value);
108   }
109
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);
113
114     using U = typename std::underlying_type<T>::type;
115     U X;
116
117     if (isWriting() || isStreaming())
118       X = static_cast<U>(Value);
119
120     if (auto EC = mapInteger(X, Comment))
121       return EC;
122
123     if (isReading())
124       Value = static_cast<T>(X);
125
126     return Error::success();
127   }
128
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 = "");
134
135   Error mapStringZVectorZ(std::vector<StringRef> &Value,
136                           const Twine &Comment = "");
137
138   template <typename SizeType, typename T, typename ElementMapper>
139   Error mapVectorN(T &Items, const ElementMapper &Mapper,
140                    const Twine &Comment = "") {
141     SizeType Size;
142     if (isStreaming()) {
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
147
148       for (auto &X : Items) {
149         if (auto EC = Mapper(*this, X))
150           return EC;
151       }
152     } else if (isWriting()) {
153       Size = static_cast<SizeType>(Items.size());
154       if (auto EC = Writer->writeInteger(Size))
155         return EC;
156
157       for (auto &X : Items) {
158         if (auto EC = Mapper(*this, X))
159           return EC;
160       }
161     } else {
162       if (auto EC = Reader->readInteger(Size))
163         return EC;
164       for (SizeType I = 0; I < Size; ++I) {
165         typename T::value_type Item;
166         if (auto EC = Mapper(*this, Item))
167           return EC;
168         Items.push_back(Item);
169       }
170     }
171
172     return Error::success();
173   }
174
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))
182           return EC;
183       }
184     } else {
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))
189           return EC;
190         Items.push_back(Field);
191       }
192     }
193     return Error::success();
194   }
195
196   Error mapByteVectorTail(ArrayRef<uint8_t> &Bytes, const Twine &Comment = "");
197   Error mapByteVectorTail(std::vector<uint8_t> &Bytes,
198                           const Twine &Comment = "");
199
200   Error padToAlignment(uint32_t Align);
201   Error skipPadding();
202
203   uint64_t getStreamedLen() {
204     if (isStreaming())
205       return StreamedLen;
206     return 0;
207   }
208
209 private:
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);
216
217   void incrStreamedLen(const uint64_t &Len) {
218     if (isStreaming())
219       StreamedLen += Len;
220   }
221
222   void resetStreamedLen() {
223     if (isStreaming())
224       StreamedLen = 4; // The record prefix is 4 bytes long
225   }
226
227   void emitComment(const Twine &Comment) {
228     if (isStreaming()) {
229       Twine TComment(Comment);
230       Streamer->AddComment(TComment);
231     }
232   }
233
234   struct RecordLimit {
235     uint32_t BeginOffset;
236     Optional<uint32_t> MaxLength;
237
238     Optional<uint32_t> bytesRemaining(uint32_t CurrentOffset) const {
239       if (!MaxLength.hasValue())
240         return None;
241       assert(CurrentOffset >= BeginOffset);
242
243       uint32_t BytesUsed = CurrentOffset - BeginOffset;
244       if (BytesUsed >= *MaxLength)
245         return 0;
246       return *MaxLength - BytesUsed;
247     }
248   };
249
250   SmallVector<RecordLimit, 2> Limits;
251
252   BinaryStreamReader *Reader = nullptr;
253   BinaryStreamWriter *Writer = nullptr;
254   CodeViewRecordStreamer *Streamer = nullptr;
255   uint64_t StreamedLen = 0;
256 };
257
258 } // end namespace codeview
259 } // end namespace llvm
260
261 #endif // LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H