Home | History | Annotate | Download | only in CodeView
      1 //===- CodeViewRecordIO.h ---------------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #ifndef LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H
     11 #define LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H
     12 
     13 #include "llvm/ADT/APSInt.h"
     14 #include "llvm/ADT/None.h"
     15 #include "llvm/ADT/Optional.h"
     16 #include "llvm/ADT/SmallVector.h"
     17 #include "llvm/ADT/StringRef.h"
     18 #include "llvm/DebugInfo/CodeView/CodeViewError.h"
     19 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
     20 #include "llvm/Support/BinaryStreamReader.h"
     21 #include "llvm/Support/BinaryStreamWriter.h"
     22 #include "llvm/Support/Error.h"
     23 #include <cassert>
     24 #include <cstdint>
     25 #include <type_traits>
     26 
     27 namespace llvm {
     28 namespace codeview {
     29 
     30 class CodeViewRecordIO {
     31   uint32_t getCurrentOffset() const {
     32     return (isWriting()) ? Writer->getOffset() : Reader->getOffset();
     33   }
     34 
     35 public:
     36   explicit CodeViewRecordIO(BinaryStreamReader &Reader) : Reader(&Reader) {}
     37   explicit CodeViewRecordIO(BinaryStreamWriter &Writer) : Writer(&Writer) {}
     38 
     39   Error beginRecord(Optional<uint32_t> MaxLength);
     40   Error endRecord();
     41 
     42   Error mapInteger(TypeIndex &TypeInd);
     43 
     44   bool isReading() const { return Reader != nullptr; }
     45   bool isWriting() const { return !isReading(); }
     46 
     47   uint32_t maxFieldLength() const;
     48 
     49   template <typename T> Error mapObject(T &Value) {
     50     if (isWriting())
     51       return Writer->writeObject(Value);
     52 
     53     const T *ValuePtr;
     54     if (auto EC = Reader->readObject(ValuePtr))
     55       return EC;
     56     Value = *ValuePtr;
     57     return Error::success();
     58   }
     59 
     60   template <typename T> Error mapInteger(T &Value) {
     61     if (isWriting())
     62       return Writer->writeInteger(Value);
     63 
     64     return Reader->readInteger(Value);
     65   }
     66 
     67   template <typename T> Error mapEnum(T &Value) {
     68     if (sizeof(Value) > maxFieldLength())
     69       return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
     70 
     71     using U = typename std::underlying_type<T>::type;
     72     U X;
     73     if (isWriting())
     74       X = static_cast<U>(Value);
     75 
     76     if (auto EC = mapInteger(X))
     77       return EC;
     78     if (isReading())
     79       Value = static_cast<T>(X);
     80     return Error::success();
     81   }
     82 
     83   Error mapEncodedInteger(int64_t &Value);
     84   Error mapEncodedInteger(uint64_t &Value);
     85   Error mapEncodedInteger(APSInt &Value);
     86   Error mapStringZ(StringRef &Value);
     87   Error mapGuid(StringRef &Guid);
     88 
     89   Error mapStringZVectorZ(std::vector<StringRef> &Value);
     90 
     91   template <typename SizeType, typename T, typename ElementMapper>
     92   Error mapVectorN(T &Items, const ElementMapper &Mapper) {
     93     SizeType Size;
     94     if (isWriting()) {
     95       Size = static_cast<SizeType>(Items.size());
     96       if (auto EC = Writer->writeInteger(Size))
     97         return EC;
     98 
     99       for (auto &X : Items) {
    100         if (auto EC = Mapper(*this, X))
    101           return EC;
    102       }
    103     } else {
    104       if (auto EC = Reader->readInteger(Size))
    105         return EC;
    106       for (SizeType I = 0; I < Size; ++I) {
    107         typename T::value_type Item;
    108         if (auto EC = Mapper(*this, Item))
    109           return EC;
    110         Items.push_back(Item);
    111       }
    112     }
    113 
    114     return Error::success();
    115   }
    116 
    117   template <typename T, typename ElementMapper>
    118   Error mapVectorTail(T &Items, const ElementMapper &Mapper) {
    119     if (isWriting()) {
    120       for (auto &Item : Items) {
    121         if (auto EC = Mapper(*this, Item))
    122           return EC;
    123       }
    124     } else {
    125       typename T::value_type Field;
    126       // Stop when we run out of bytes or we hit record padding bytes.
    127       while (!Reader->empty() && Reader->peek() < 0xf0 /* LF_PAD0 */) {
    128         if (auto EC = Mapper(*this, Field))
    129           return EC;
    130         Items.push_back(Field);
    131       }
    132     }
    133     return Error::success();
    134   }
    135 
    136   Error mapByteVectorTail(ArrayRef<uint8_t> &Bytes);
    137   Error mapByteVectorTail(std::vector<uint8_t> &Bytes);
    138 
    139   Error padToAlignment(uint32_t Align);
    140   Error skipPadding();
    141 
    142 private:
    143   Error writeEncodedSignedInteger(const int64_t &Value);
    144   Error writeEncodedUnsignedInteger(const uint64_t &Value);
    145 
    146   struct RecordLimit {
    147     uint32_t BeginOffset;
    148     Optional<uint32_t> MaxLength;
    149 
    150     Optional<uint32_t> bytesRemaining(uint32_t CurrentOffset) const {
    151       if (!MaxLength.hasValue())
    152         return None;
    153       assert(CurrentOffset >= BeginOffset);
    154 
    155       uint32_t BytesUsed = CurrentOffset - BeginOffset;
    156       if (BytesUsed >= *MaxLength)
    157         return 0;
    158       return *MaxLength - BytesUsed;
    159     }
    160   };
    161 
    162   SmallVector<RecordLimit, 2> Limits;
    163 
    164   BinaryStreamReader *Reader = nullptr;
    165   BinaryStreamWriter *Writer = nullptr;
    166 };
    167 
    168 } // end namespace codeview
    169 } // end namespace llvm
    170 
    171 #endif // LLVM_DEBUGINFO_CODEVIEW_CODEVIEWRECORDIO_H
    172