Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:39

0001 //===- CodeViewRecordIO.h ---------------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
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   // deserializes records to structures
0055   explicit CodeViewRecordIO(BinaryStreamReader &Reader) : Reader(&Reader) {}
0056 
0057   // serializes records to buffer
0058   explicit CodeViewRecordIO(BinaryStreamWriter &Writer) : Writer(&Writer) {}
0059 
0060   // writes records to assembly file using MC library interface
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)); // add 1 for the delimiter
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       // Stop when we run out of bytes or we hit record padding bytes.
0191       while (!Reader->empty() && Reader->peek() < 0xf0 /* LF_PAD0 */) {
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; // The record prefix is 4 bytes long
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 } // end namespace codeview
0269 } // end namespace llvm
0270 
0271 #endif // LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H