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