• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- CodeViewRecordIO.h ---------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H
11 #define LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H
12 
13 #include "llvm/ADT/APSInt.h"
14 #include "llvm/ADT/None.h"
15 #include "llvm/ADT/Optional.h"
16 #include "llvm/ADT/SmallVector.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
19 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
20 #include "llvm/Support/BinaryStreamReader.h"
21 #include "llvm/Support/BinaryStreamWriter.h"
22 #include "llvm/Support/Error.h"
23 #include <cassert>
24 #include <cstdint>
25 #include <type_traits>
26 
27 namespace llvm {
28 namespace codeview {
29 
30 class CodeViewRecordIO {
getCurrentOffset()31   uint32_t getCurrentOffset() const {
32     return (isWriting()) ? Writer->getOffset() : Reader->getOffset();
33   }
34 
35 public:
CodeViewRecordIO(BinaryStreamReader & Reader)36   explicit CodeViewRecordIO(BinaryStreamReader &Reader) : Reader(&Reader) {}
CodeViewRecordIO(BinaryStreamWriter & Writer)37   explicit CodeViewRecordIO(BinaryStreamWriter &Writer) : Writer(&Writer) {}
38 
39   Error beginRecord(Optional<uint32_t> MaxLength);
40   Error endRecord();
41 
42   Error mapInteger(TypeIndex &TypeInd);
43 
isReading()44   bool isReading() const { return Reader != nullptr; }
isWriting()45   bool isWriting() const { return !isReading(); }
46 
47   uint32_t maxFieldLength() const;
48 
mapObject(T & Value)49   template <typename T> Error mapObject(T &Value) {
50     if (isWriting())
51       return Writer->writeObject(Value);
52 
53     const T *ValuePtr;
54     if (auto EC = Reader->readObject(ValuePtr))
55       return EC;
56     Value = *ValuePtr;
57     return Error::success();
58   }
59 
mapInteger(T & Value)60   template <typename T> Error mapInteger(T &Value) {
61     if (isWriting())
62       return Writer->writeInteger(Value);
63 
64     return Reader->readInteger(Value);
65   }
66 
mapEnum(T & Value)67   template <typename T> Error mapEnum(T &Value) {
68     if (sizeof(Value) > maxFieldLength())
69       return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
70 
71     using U = typename std::underlying_type<T>::type;
72     U X;
73     if (isWriting())
74       X = static_cast<U>(Value);
75 
76     if (auto EC = mapInteger(X))
77       return EC;
78     if (isReading())
79       Value = static_cast<T>(X);
80     return Error::success();
81   }
82 
83   Error mapEncodedInteger(int64_t &Value);
84   Error mapEncodedInteger(uint64_t &Value);
85   Error mapEncodedInteger(APSInt &Value);
86   Error mapStringZ(StringRef &Value);
87   Error mapGuid(GUID &Guid);
88 
89   Error mapStringZVectorZ(std::vector<StringRef> &Value);
90 
91   template <typename SizeType, typename T, typename ElementMapper>
mapVectorN(T & Items,const ElementMapper & Mapper)92   Error mapVectorN(T &Items, const ElementMapper &Mapper) {
93     SizeType Size;
94     if (isWriting()) {
95       Size = static_cast<SizeType>(Items.size());
96       if (auto EC = Writer->writeInteger(Size))
97         return EC;
98 
99       for (auto &X : Items) {
100         if (auto EC = Mapper(*this, X))
101           return EC;
102       }
103     } else {
104       if (auto EC = Reader->readInteger(Size))
105         return EC;
106       for (SizeType I = 0; I < Size; ++I) {
107         typename T::value_type Item;
108         if (auto EC = Mapper(*this, Item))
109           return EC;
110         Items.push_back(Item);
111       }
112     }
113 
114     return Error::success();
115   }
116 
117   template <typename T, typename ElementMapper>
mapVectorTail(T & Items,const ElementMapper & Mapper)118   Error mapVectorTail(T &Items, const ElementMapper &Mapper) {
119     if (isWriting()) {
120       for (auto &Item : Items) {
121         if (auto EC = Mapper(*this, Item))
122           return EC;
123       }
124     } else {
125       typename T::value_type Field;
126       // Stop when we run out of bytes or we hit record padding bytes.
127       while (!Reader->empty() && Reader->peek() < 0xf0 /* LF_PAD0 */) {
128         if (auto EC = Mapper(*this, Field))
129           return EC;
130         Items.push_back(Field);
131       }
132     }
133     return Error::success();
134   }
135 
136   Error mapByteVectorTail(ArrayRef<uint8_t> &Bytes);
137   Error mapByteVectorTail(std::vector<uint8_t> &Bytes);
138 
139   Error padToAlignment(uint32_t Align);
140   Error skipPadding();
141 
142 private:
143   Error writeEncodedSignedInteger(const int64_t &Value);
144   Error writeEncodedUnsignedInteger(const uint64_t &Value);
145 
146   struct RecordLimit {
147     uint32_t BeginOffset;
148     Optional<uint32_t> MaxLength;
149 
bytesRemainingRecordLimit150     Optional<uint32_t> bytesRemaining(uint32_t CurrentOffset) const {
151       if (!MaxLength.hasValue())
152         return None;
153       assert(CurrentOffset >= BeginOffset);
154 
155       uint32_t BytesUsed = CurrentOffset - BeginOffset;
156       if (BytesUsed >= *MaxLength)
157         return 0;
158       return *MaxLength - BytesUsed;
159     }
160   };
161 
162   SmallVector<RecordLimit, 2> Limits;
163 
164   BinaryStreamReader *Reader = nullptr;
165   BinaryStreamWriter *Writer = nullptr;
166 };
167 
168 } // end namespace codeview
169 } // end namespace llvm
170 
171 #endif // LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H
172