File indexing completed on 2026-05-10 08:43:39
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H
0010 #define LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H
0011
0012 #include "llvm/ADT/SmallVector.h"
0013 #include "llvm/ADT/StringRef.h"
0014 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
0015 #include "llvm/Support/BinaryStreamReader.h"
0016 #include "llvm/Support/BinaryStreamWriter.h"
0017 #include "llvm/Support/Error.h"
0018 #include <cassert>
0019 #include <cstdint>
0020 #include <type_traits>
0021
0022 namespace llvm {
0023
0024 template <typename T> class ArrayRef;
0025 class APSInt;
0026
0027 namespace codeview {
0028 class TypeIndex;
0029 struct GUID;
0030
0031 class CodeViewRecordStreamer {
0032 public:
0033 virtual void emitBytes(StringRef Data) = 0;
0034 virtual void emitIntValue(uint64_t Value, unsigned Size) = 0;
0035 virtual void emitBinaryData(StringRef Data) = 0;
0036 virtual void AddComment(const Twine &T) = 0;
0037 virtual void AddRawComment(const Twine &T) = 0;
0038 virtual bool isVerboseAsm() = 0;
0039 virtual std::string getTypeName(TypeIndex TI) = 0;
0040 virtual ~CodeViewRecordStreamer() = default;
0041 };
0042
0043 class CodeViewRecordIO {
0044 uint32_t getCurrentOffset() const {
0045 if (isWriting())
0046 return Writer->getOffset();
0047 else if (isReading())
0048 return Reader->getOffset();
0049 else
0050 return 0;
0051 }
0052
0053 public:
0054
0055 explicit CodeViewRecordIO(BinaryStreamReader &Reader) : Reader(&Reader) {}
0056
0057
0058 explicit CodeViewRecordIO(BinaryStreamWriter &Writer) : Writer(&Writer) {}
0059
0060
0061 explicit CodeViewRecordIO(CodeViewRecordStreamer &Streamer)
0062 : Streamer(&Streamer) {}
0063
0064 Error beginRecord(std::optional<uint32_t> MaxLength);
0065 Error endRecord();
0066
0067 Error mapInteger(TypeIndex &TypeInd, const Twine &Comment = "");
0068
0069 bool isStreaming() const {
0070 return (Streamer != nullptr) && (Reader == nullptr) && (Writer == nullptr);
0071 }
0072 bool isReading() const {
0073 return (Reader != nullptr) && (Streamer == nullptr) && (Writer == nullptr);
0074 }
0075 bool isWriting() const {
0076 return (Writer != nullptr) && (Streamer == nullptr) && (Reader == nullptr);
0077 }
0078
0079 uint32_t maxFieldLength() const;
0080
0081 template <typename T> Error mapObject(T &Value) {
0082 if (isStreaming()) {
0083 StringRef BytesSR =
0084 StringRef((reinterpret_cast<const char *>(&Value)), sizeof(Value));
0085 Streamer->emitBytes(BytesSR);
0086 incrStreamedLen(sizeof(T));
0087 return Error::success();
0088 }
0089
0090 if (isWriting())
0091 return Writer->writeObject(Value);
0092
0093 const T *ValuePtr;
0094 if (auto EC = Reader->readObject(ValuePtr))
0095 return EC;
0096 Value = *ValuePtr;
0097 return Error::success();
0098 }
0099
0100 template <typename T> Error mapInteger(T &Value, const Twine &Comment = "") {
0101 if (isStreaming()) {
0102 emitComment(Comment);
0103 Streamer->emitIntValue((int)Value, sizeof(T));
0104 incrStreamedLen(sizeof(T));
0105 return Error::success();
0106 }
0107
0108 if (isWriting())
0109 return Writer->writeInteger(Value);
0110
0111 return Reader->readInteger(Value);
0112 }
0113
0114 template <typename T> Error mapEnum(T &Value, const Twine &Comment = "") {
0115 if (!isStreaming() && sizeof(Value) > maxFieldLength())
0116 return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
0117
0118 using U = std::underlying_type_t<T>;
0119 U X;
0120
0121 if (isWriting() || isStreaming())
0122 X = static_cast<U>(Value);
0123
0124 if (auto EC = mapInteger(X, Comment))
0125 return EC;
0126
0127 if (isReading())
0128 Value = static_cast<T>(X);
0129
0130 return Error::success();
0131 }
0132
0133 Error mapEncodedInteger(int64_t &Value, const Twine &Comment = "");
0134 Error mapEncodedInteger(uint64_t &Value, const Twine &Comment = "");
0135 Error mapEncodedInteger(APSInt &Value, const Twine &Comment = "");
0136 Error mapStringZ(StringRef &Value, const Twine &Comment = "");
0137 Error mapGuid(GUID &Guid, const Twine &Comment = "");
0138
0139 Error mapStringZVectorZ(std::vector<StringRef> &Value,
0140 const Twine &Comment = "");
0141
0142 template <typename SizeType, typename T, typename ElementMapper>
0143 Error mapVectorN(T &Items, const ElementMapper &Mapper,
0144 const Twine &Comment = "") {
0145 SizeType Size;
0146 if (isStreaming()) {
0147 Size = static_cast<SizeType>(Items.size());
0148 emitComment(Comment);
0149 Streamer->emitIntValue(Size, sizeof(Size));
0150 incrStreamedLen(sizeof(Size));
0151
0152 for (auto &X : Items) {
0153 if (auto EC = Mapper(*this, X))
0154 return EC;
0155 }
0156 } else if (isWriting()) {
0157 Size = static_cast<SizeType>(Items.size());
0158 if (auto EC = Writer->writeInteger(Size))
0159 return EC;
0160
0161 for (auto &X : Items) {
0162 if (auto EC = Mapper(*this, X))
0163 return EC;
0164 }
0165 } else {
0166 if (auto EC = Reader->readInteger(Size))
0167 return EC;
0168 for (SizeType I = 0; I < Size; ++I) {
0169 typename T::value_type Item;
0170 if (auto EC = Mapper(*this, Item))
0171 return EC;
0172 Items.push_back(Item);
0173 }
0174 }
0175
0176 return Error::success();
0177 }
0178
0179 template <typename T, typename ElementMapper>
0180 Error mapVectorTail(T &Items, const ElementMapper &Mapper,
0181 const Twine &Comment = "") {
0182 emitComment(Comment);
0183 if (isStreaming() || isWriting()) {
0184 for (auto &Item : Items) {
0185 if (auto EC = Mapper(*this, Item))
0186 return EC;
0187 }
0188 } else {
0189 typename T::value_type Field;
0190
0191 while (!Reader->empty() && Reader->peek() < 0xf0 ) {
0192 if (auto EC = Mapper(*this, Field))
0193 return EC;
0194 Items.push_back(Field);
0195 }
0196 }
0197 return Error::success();
0198 }
0199
0200 Error mapByteVectorTail(ArrayRef<uint8_t> &Bytes, const Twine &Comment = "");
0201 Error mapByteVectorTail(std::vector<uint8_t> &Bytes,
0202 const Twine &Comment = "");
0203
0204 Error padToAlignment(uint32_t Align);
0205 Error skipPadding();
0206
0207 uint64_t getStreamedLen() {
0208 if (isStreaming())
0209 return StreamedLen;
0210 return 0;
0211 }
0212
0213 void emitRawComment(const Twine &T) {
0214 if (isStreaming() && Streamer->isVerboseAsm())
0215 Streamer->AddRawComment(T);
0216 }
0217
0218 private:
0219 void emitEncodedSignedInteger(const int64_t &Value,
0220 const Twine &Comment = "");
0221 void emitEncodedUnsignedInteger(const uint64_t &Value,
0222 const Twine &Comment = "");
0223 Error writeEncodedSignedInteger(const int64_t &Value);
0224 Error writeEncodedUnsignedInteger(const uint64_t &Value);
0225
0226 void incrStreamedLen(const uint64_t &Len) {
0227 if (isStreaming())
0228 StreamedLen += Len;
0229 }
0230
0231 void resetStreamedLen() {
0232 if (isStreaming())
0233 StreamedLen = 4;
0234 }
0235
0236 void emitComment(const Twine &Comment) {
0237 if (isStreaming() && Streamer->isVerboseAsm()) {
0238 Twine TComment(Comment);
0239 if (!TComment.isTriviallyEmpty())
0240 Streamer->AddComment(TComment);
0241 }
0242 }
0243
0244 struct RecordLimit {
0245 uint32_t BeginOffset;
0246 std::optional<uint32_t> MaxLength;
0247
0248 std::optional<uint32_t> bytesRemaining(uint32_t CurrentOffset) const {
0249 if (!MaxLength)
0250 return std::nullopt;
0251 assert(CurrentOffset >= BeginOffset);
0252
0253 uint32_t BytesUsed = CurrentOffset - BeginOffset;
0254 if (BytesUsed >= *MaxLength)
0255 return 0;
0256 return *MaxLength - BytesUsed;
0257 }
0258 };
0259
0260 SmallVector<RecordLimit, 2> Limits;
0261
0262 BinaryStreamReader *Reader = nullptr;
0263 BinaryStreamWriter *Writer = nullptr;
0264 CodeViewRecordStreamer *Streamer = nullptr;
0265 uint64_t StreamedLen = 0;
0266 };
0267
0268 }
0269 }
0270
0271 #endif