Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  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 {
  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
  55.   explicit CodeViewRecordIO(BinaryStreamReader &Reader) : Reader(&Reader) {}
  56.  
  57.   // serializes records to buffer
  58.   explicit CodeViewRecordIO(BinaryStreamWriter &Writer) : Writer(&Writer) {}
  59.  
  60.   // writes records to assembly file using MC library interface
  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.  
  69.   bool isStreaming() const {
  70.     return (Streamer != nullptr) && (Reader == nullptr) && (Writer == nullptr);
  71.   }
  72.   bool isReading() const {
  73.     return (Reader != nullptr) && (Streamer == nullptr) && (Writer == nullptr);
  74.   }
  75.   bool isWriting() const {
  76.     return (Writer != nullptr) && (Streamer == nullptr) && (Reader == nullptr);
  77.   }
  78.  
  79.   uint32_t maxFieldLength() const;
  80.  
  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.  
  207.   uint64_t getStreamedLen() {
  208.     if (isStreaming())
  209.       return StreamedLen;
  210.     return 0;
  211.   }
  212.  
  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.  
  226.   void incrStreamedLen(const uint64_t &Len) {
  227.     if (isStreaming())
  228.       StreamedLen += Len;
  229.   }
  230.  
  231.   void resetStreamedLen() {
  232.     if (isStreaming())
  233.       StreamedLen = 4; // The record prefix is 4 bytes long
  234.   }
  235.  
  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.  
  248.     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.