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