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