1 //===- StreamReader.h - Reads bytes and objects from a stream ---*- 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_STREAMREADER_H 11 #define LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H 12 13 #include "llvm/ADT/ArrayRef.h" 14 #include "llvm/DebugInfo/CodeView/CodeViewError.h" 15 #include "llvm/DebugInfo/CodeView/StreamArray.h" 16 #include "llvm/DebugInfo/CodeView/StreamInterface.h" 17 #include "llvm/Support/Endian.h" 18 #include "llvm/Support/Error.h" 19 20 #include <string> 21 22 namespace llvm { 23 namespace codeview { 24 25 class StreamRef; 26 27 class StreamReader { 28 public: 29 StreamReader(StreamRef Stream); 30 31 Error readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer); 32 Error readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size); 33 Error readInteger(uint16_t &Dest); 34 Error readInteger(uint32_t &Dest); 35 Error readZeroString(StringRef &Dest); 36 Error readFixedString(StringRef &Dest, uint32_t Length); 37 Error readStreamRef(StreamRef &Ref); 38 Error readStreamRef(StreamRef &Ref, uint32_t Length); 39 readEnum(T & Dest)40 template <typename T> Error readEnum(T &Dest) { 41 typename std::underlying_type<T>::type N; 42 if (auto EC = readInteger(N)) 43 return EC; 44 Dest = static_cast<T>(N); 45 return Error::success(); 46 } 47 readObject(const T * & Dest)48 template <typename T> Error readObject(const T *&Dest) { 49 ArrayRef<uint8_t> Buffer; 50 if (auto EC = readBytes(Buffer, sizeof(T))) 51 return EC; 52 Dest = reinterpret_cast<const T *>(Buffer.data()); 53 return Error::success(); 54 } 55 56 template <typename T> readArray(ArrayRef<T> & Array,uint32_t NumElements)57 Error readArray(ArrayRef<T> &Array, uint32_t NumElements) { 58 ArrayRef<uint8_t> Bytes; 59 if (NumElements == 0) { 60 Array = ArrayRef<T>(); 61 return Error::success(); 62 } 63 64 if (NumElements > UINT32_MAX/sizeof(T)) 65 return make_error<CodeViewError>(cv_error_code::insufficient_buffer); 66 67 if (auto EC = readBytes(Bytes, NumElements * sizeof(T))) 68 return EC; 69 Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements); 70 return Error::success(); 71 } 72 73 template <typename T, typename U> readArray(VarStreamArray<T,U> & Array,uint32_t Size)74 Error readArray(VarStreamArray<T, U> &Array, uint32_t Size) { 75 StreamRef S; 76 if (auto EC = readStreamRef(S, Size)) 77 return EC; 78 Array = VarStreamArray<T, U>(S, Array.getExtractor()); 79 return Error::success(); 80 } 81 82 template <typename T> readArray(FixedStreamArray<T> & Array,uint32_t NumItems)83 Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) { 84 if (NumItems == 0) { 85 Array = FixedStreamArray<T>(); 86 return Error::success(); 87 } 88 uint32_t Length = NumItems * sizeof(T); 89 if (Length / sizeof(T) != NumItems) 90 return make_error<CodeViewError>(cv_error_code::corrupt_record); 91 if (Offset + Length > Stream.getLength()) 92 return make_error<CodeViewError>(cv_error_code::insufficient_buffer); 93 StreamRef View = Stream.slice(Offset, Length); 94 Array = FixedStreamArray<T>(View); 95 Offset += Length; 96 return Error::success(); 97 } 98 setOffset(uint32_t Off)99 void setOffset(uint32_t Off) { Offset = Off; } getOffset()100 uint32_t getOffset() const { return Offset; } getLength()101 uint32_t getLength() const { return Stream.getLength(); } bytesRemaining()102 uint32_t bytesRemaining() const { return getLength() - getOffset(); } 103 104 private: 105 StreamRef Stream; 106 uint32_t Offset; 107 }; 108 } // namespace codeview 109 } // namespace llvm 110 111 #endif // LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H 112