xref: /freebsd/contrib/llvm-project/llvm/include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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/SmallVector.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
15 #include "llvm/Support/BinaryStreamReader.h"
16 #include "llvm/Support/BinaryStreamWriter.h"
17 #include "llvm/Support/Compiler.h"
18 #include "llvm/Support/Error.h"
19 #include <cassert>
20 #include <cstdint>
21 #include <type_traits>
22 
23 namespace llvm {
24 
25 template <typename T> class ArrayRef;
26 class APSInt;
27 
28 namespace codeview {
29 class TypeIndex;
30 struct GUID;
31 
32 class CodeViewRecordStreamer {
33 public:
34   virtual void emitBytes(StringRef Data) = 0;
35   virtual void emitIntValue(uint64_t Value, unsigned Size) = 0;
36   virtual void emitBinaryData(StringRef Data) = 0;
37   virtual void AddComment(const Twine &T) = 0;
38   virtual void AddRawComment(const Twine &T) = 0;
39   virtual bool isVerboseAsm() = 0;
40   virtual std::string getTypeName(TypeIndex TI) = 0;
41   virtual ~CodeViewRecordStreamer() = default;
42 };
43 
44 class CodeViewRecordIO {
getCurrentOffset()45   uint32_t getCurrentOffset() const {
46     if (isWriting())
47       return Writer->getOffset();
48     else if (isReading())
49       return Reader->getOffset();
50     else
51       return 0;
52   }
53 
54 public:
55   // deserializes records to structures
CodeViewRecordIO(BinaryStreamReader & Reader)56   explicit CodeViewRecordIO(BinaryStreamReader &Reader) : Reader(&Reader) {}
57 
58   // serializes records to buffer
CodeViewRecordIO(BinaryStreamWriter & Writer)59   explicit CodeViewRecordIO(BinaryStreamWriter &Writer) : Writer(&Writer) {}
60 
61   // writes records to assembly file using MC library interface
CodeViewRecordIO(CodeViewRecordStreamer & Streamer)62   explicit CodeViewRecordIO(CodeViewRecordStreamer &Streamer)
63       : Streamer(&Streamer) {}
64 
65   LLVM_ABI Error beginRecord(std::optional<uint32_t> MaxLength);
66   LLVM_ABI Error endRecord();
67 
68   LLVM_ABI Error mapInteger(TypeIndex &TypeInd, const Twine &Comment = "");
69 
isStreaming()70   bool isStreaming() const {
71     return (Streamer != nullptr) && (Reader == nullptr) && (Writer == nullptr);
72   }
isReading()73   bool isReading() const {
74     return (Reader != nullptr) && (Streamer == nullptr) && (Writer == nullptr);
75   }
isWriting()76   bool isWriting() const {
77     return (Writer != nullptr) && (Streamer == nullptr) && (Reader == nullptr);
78   }
79 
80   LLVM_ABI uint32_t maxFieldLength() const;
81 
mapObject(T & Value)82   template <typename T> Error mapObject(T &Value) {
83     if (isStreaming()) {
84       StringRef BytesSR =
85           StringRef((reinterpret_cast<const char *>(&Value)), sizeof(Value));
86       Streamer->emitBytes(BytesSR);
87       incrStreamedLen(sizeof(T));
88       return Error::success();
89     }
90 
91     if (isWriting())
92       return Writer->writeObject(Value);
93 
94     const T *ValuePtr;
95     if (auto EC = Reader->readObject(ValuePtr))
96       return EC;
97     Value = *ValuePtr;
98     return Error::success();
99   }
100 
101   template <typename T> Error mapInteger(T &Value, const Twine &Comment = "") {
102     if (isStreaming()) {
103       emitComment(Comment);
104       Streamer->emitIntValue((int)Value, sizeof(T));
105       incrStreamedLen(sizeof(T));
106       return Error::success();
107     }
108 
109     if (isWriting())
110       return Writer->writeInteger(Value);
111 
112     return Reader->readInteger(Value);
113   }
114 
115   template <typename T> Error mapEnum(T &Value, const Twine &Comment = "") {
116     if (!isStreaming() && sizeof(Value) > maxFieldLength())
117       return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
118 
119     using U = std::underlying_type_t<T>;
120     U X;
121 
122     if (isWriting() || isStreaming())
123       X = static_cast<U>(Value);
124 
125     if (auto EC = mapInteger(X, Comment))
126       return EC;
127 
128     if (isReading())
129       Value = static_cast<T>(X);
130 
131     return Error::success();
132   }
133 
134   LLVM_ABI Error mapEncodedInteger(int64_t &Value, const Twine &Comment = "");
135   LLVM_ABI Error mapEncodedInteger(uint64_t &Value, const Twine &Comment = "");
136   LLVM_ABI Error mapEncodedInteger(APSInt &Value, const Twine &Comment = "");
137   LLVM_ABI Error mapStringZ(StringRef &Value, const Twine &Comment = "");
138   LLVM_ABI Error mapGuid(GUID &Guid, const Twine &Comment = "");
139 
140   LLVM_ABI Error mapStringZVectorZ(std::vector<StringRef> &Value,
141                                    const Twine &Comment = "");
142 
143   template <typename SizeType, typename T, typename ElementMapper>
144   Error mapVectorN(T &Items, const ElementMapper &Mapper,
145                    const Twine &Comment = "") {
146     SizeType Size;
147     if (isStreaming()) {
148       Size = static_cast<SizeType>(Items.size());
149       emitComment(Comment);
150       Streamer->emitIntValue(Size, sizeof(Size));
151       incrStreamedLen(sizeof(Size)); // add 1 for the delimiter
152 
153       for (auto &X : Items) {
154         if (auto EC = Mapper(*this, X))
155           return EC;
156       }
157     } else if (isWriting()) {
158       Size = static_cast<SizeType>(Items.size());
159       if (auto EC = Writer->writeInteger(Size))
160         return EC;
161 
162       for (auto &X : Items) {
163         if (auto EC = Mapper(*this, X))
164           return EC;
165       }
166     } else {
167       if (auto EC = Reader->readInteger(Size))
168         return EC;
169       for (SizeType I = 0; I < Size; ++I) {
170         typename T::value_type Item;
171         if (auto EC = Mapper(*this, Item))
172           return EC;
173         Items.push_back(Item);
174       }
175     }
176 
177     return Error::success();
178   }
179 
180   template <typename T, typename ElementMapper>
181   Error mapVectorTail(T &Items, const ElementMapper &Mapper,
182                       const Twine &Comment = "") {
183     emitComment(Comment);
184     if (isStreaming() || isWriting()) {
185       for (auto &Item : Items) {
186         if (auto EC = Mapper(*this, Item))
187           return EC;
188       }
189     } else {
190       typename T::value_type Field;
191       // Stop when we run out of bytes or we hit record padding bytes.
192       while (!Reader->empty() && Reader->peek() < 0xf0 /* LF_PAD0 */) {
193         if (auto EC = Mapper(*this, Field))
194           return EC;
195         Items.push_back(Field);
196       }
197     }
198     return Error::success();
199   }
200 
201   LLVM_ABI Error mapByteVectorTail(ArrayRef<uint8_t> &Bytes,
202                                    const Twine &Comment = "");
203   LLVM_ABI Error mapByteVectorTail(std::vector<uint8_t> &Bytes,
204                                    const Twine &Comment = "");
205 
206   LLVM_ABI Error padToAlignment(uint32_t Align);
207   LLVM_ABI Error skipPadding();
208 
getStreamedLen()209   uint64_t getStreamedLen() {
210     if (isStreaming())
211       return StreamedLen;
212     return 0;
213   }
214 
emitRawComment(const Twine & T)215   void emitRawComment(const Twine &T) {
216     if (isStreaming() && Streamer->isVerboseAsm())
217       Streamer->AddRawComment(T);
218   }
219 
220 private:
221   void emitEncodedSignedInteger(const int64_t &Value,
222                                 const Twine &Comment = "");
223   void emitEncodedUnsignedInteger(const uint64_t &Value,
224                                   const Twine &Comment = "");
225   Error writeEncodedSignedInteger(const int64_t &Value);
226   Error writeEncodedUnsignedInteger(const uint64_t &Value);
227 
incrStreamedLen(const uint64_t & Len)228   void incrStreamedLen(const uint64_t &Len) {
229     if (isStreaming())
230       StreamedLen += Len;
231   }
232 
resetStreamedLen()233   void resetStreamedLen() {
234     if (isStreaming())
235       StreamedLen = 4; // The record prefix is 4 bytes long
236   }
237 
emitComment(const Twine & Comment)238   void emitComment(const Twine &Comment) {
239     if (isStreaming() && Streamer->isVerboseAsm()) {
240       Twine TComment(Comment);
241       if (!TComment.isTriviallyEmpty())
242         Streamer->AddComment(TComment);
243     }
244   }
245 
246   struct RecordLimit {
247     uint32_t BeginOffset;
248     std::optional<uint32_t> MaxLength;
249 
bytesRemainingRecordLimit250     std::optional<uint32_t> bytesRemaining(uint32_t CurrentOffset) const {
251       if (!MaxLength)
252         return std::nullopt;
253       assert(CurrentOffset >= BeginOffset);
254 
255       uint32_t BytesUsed = CurrentOffset - BeginOffset;
256       if (BytesUsed >= *MaxLength)
257         return 0;
258       return *MaxLength - BytesUsed;
259     }
260   };
261 
262   SmallVector<RecordLimit, 2> Limits;
263 
264   BinaryStreamReader *Reader = nullptr;
265   BinaryStreamWriter *Writer = nullptr;
266   CodeViewRecordStreamer *Streamer = nullptr;
267   uint64_t StreamedLen = 0;
268 };
269 
270 } // end namespace codeview
271 } // end namespace llvm
272 
273 #endif // LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H
274