diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-05-03 20:26:11 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-05-03 20:26:11 +0000 |
commit | 148779df305667b6942fee7e758fdf81a6498f38 (patch) | |
tree | 976d85fb9cb4bc8ed54348b045f742be90e10c57 /include/llvm/Support | |
parent | a303c417bbdb53703c2c17398b08486bde78f1f6 (diff) |
Diffstat (limited to 'include/llvm/Support')
-rw-r--r-- | include/llvm/Support/BinaryStreamArray.h | 234 | ||||
-rw-r--r-- | include/llvm/Support/BinaryStreamReader.h | 28 | ||||
-rw-r--r-- | include/llvm/Support/BinaryStreamRef.h | 3 | ||||
-rw-r--r-- | include/llvm/Support/BinaryStreamWriter.h | 6 | ||||
-rw-r--r-- | include/llvm/Support/DataExtractor.h | 22 | ||||
-rw-r--r-- | include/llvm/Support/ELFRelocs/Hexagon.def | 5 |
6 files changed, 204 insertions, 94 deletions
diff --git a/include/llvm/Support/BinaryStreamArray.h b/include/llvm/Support/BinaryStreamArray.h index 748a62be231e..f141c30f16c7 100644 --- a/include/llvm/Support/BinaryStreamArray.h +++ b/include/llvm/Support/BinaryStreamArray.h @@ -42,99 +42,34 @@ namespace llvm { /// having to specify a second template argument to VarStreamArray (documented /// below). template <typename T> struct VarStreamArrayExtractor { - typedef void Context; + struct ContextType {}; // Method intentionally deleted. You must provide an explicit specialization - // with the following method implemented. - static Error extract(BinaryStreamRef Stream, uint32_t &Len, T &Item, - Context *Ctx) = delete; -}; - -/// VarStreamArray represents an array of variable length records backed by a -/// stream. This could be a contiguous sequence of bytes in memory, it could -/// be a file on disk, or it could be a PDB stream where bytes are stored as -/// discontiguous blocks in a file. Usually it is desirable to treat arrays -/// as contiguous blocks of memory, but doing so with large PDB files, for -/// example, could mean allocating huge amounts of memory just to allow -/// re-ordering of stream data to be contiguous before iterating over it. By -/// abstracting this out, we need not duplicate this memory, and we can -/// iterate over arrays in arbitrarily formatted streams. Elements are parsed -/// lazily on iteration, so there is no upfront cost associated with building -/// or copying a VarStreamArray, no matter how large it may be. -/// -/// You create a VarStreamArray by specifying a ValueType and an Extractor type. -/// If you do not specify an Extractor type, you are expected to specialize -/// VarStreamArrayExtractor<T> for your ValueType. -/// -/// The default extractor type is stateless, but by specializing -/// VarStreamArrayExtractor or defining your own custom extractor type and -/// adding the appropriate ContextType typedef to the class, you can pass a -/// context field during construction of the VarStreamArray that will be -/// passed to each call to extract. -/// -template <typename ValueType, typename ExtractorType> -class VarStreamArrayIterator; - -template <typename ValueType, - typename ExtractorType = VarStreamArrayExtractor<ValueType>> -class VarStreamArray { -public: - typedef typename ExtractorType::ContextType ContextType; - typedef VarStreamArrayIterator<ValueType, ExtractorType> Iterator; - friend Iterator; - - VarStreamArray() = default; - - explicit VarStreamArray(BinaryStreamRef Stream, - ContextType *Context = nullptr) - : Stream(Stream), Context(Context) {} - - VarStreamArray(const VarStreamArray<ValueType, ExtractorType> &Other) - : Stream(Other.Stream), Context(Other.Context) {} - - Iterator begin(bool *HadError = nullptr) const { - if (empty()) - return end(); - - return Iterator(*this, Context, HadError); - } - - Iterator end() const { return Iterator(); } - - bool empty() const { return Stream.getLength() == 0; } - - /// \brief given an offset into the array's underlying stream, return an - /// iterator to the record at that offset. This is considered unsafe - /// since the behavior is undefined if \p Offset does not refer to the - /// beginning of a valid record. - Iterator at(uint32_t Offset) const { - return Iterator(*this, Context, Stream.drop_front(Offset), nullptr); - } - - BinaryStreamRef getUnderlyingStream() const { return Stream; } + // with one of the following two methods implemented. + static Error extract(BinaryStreamRef Stream, uint32_t &Len, T &Item) = delete; -private: - BinaryStreamRef Stream; - ContextType *Context = nullptr; + static Error extract(BinaryStreamRef Stream, uint32_t &Len, T &Item, + const ContextType &Ctx) = delete; }; -template <typename ValueType, typename ExtractorType> +template <typename ArrayType, typename Value, typename Extractor, + typename WrappedCtx> class VarStreamArrayIterator : public iterator_facade_base< - VarStreamArrayIterator<ValueType, ExtractorType>, - std::forward_iterator_tag, ValueType> { - typedef typename ExtractorType::ContextType ContextType; - typedef VarStreamArrayIterator<ValueType, ExtractorType> IterType; - typedef VarStreamArray<ValueType, ExtractorType> ArrayType; + VarStreamArrayIterator<ArrayType, Value, Extractor, WrappedCtx>, + std::forward_iterator_tag, Value> { + typedef VarStreamArrayIterator<ArrayType, Value, Extractor, WrappedCtx> + IterType; public: - VarStreamArrayIterator(const ArrayType &Array, ContextType *Context, + VarStreamArrayIterator() = default; + VarStreamArrayIterator(const ArrayType &Array, const WrappedCtx &Ctx, BinaryStreamRef Stream, bool *HadError = nullptr) - : IterRef(Stream), Context(Context), Array(&Array), HadError(HadError) { + : IterRef(Stream), Ctx(&Ctx), Array(&Array), HadError(HadError) { if (IterRef.getLength() == 0) moveToEnd(); else { - auto EC = ExtractorType::extract(IterRef, ThisLen, ThisValue, Context); + auto EC = Ctx.template invoke<Extractor>(IterRef, ThisLen, ThisValue); if (EC) { consumeError(std::move(EC)); markError(); @@ -142,11 +77,13 @@ public: } } - VarStreamArrayIterator(const ArrayType &Array, ContextType *Context, + VarStreamArrayIterator(const ArrayType &Array, const WrappedCtx &Ctx, bool *HadError = nullptr) - : VarStreamArrayIterator(Array, Context, Array.Stream, HadError) {} + : VarStreamArrayIterator(Array, Ctx, Array.Stream, HadError) {} + + VarStreamArrayIterator(const WrappedCtx &Ctx) : Ctx(&Ctx) {} + VarStreamArrayIterator(const VarStreamArrayIterator &Other) = default; - VarStreamArrayIterator() = default; ~VarStreamArrayIterator() = default; bool operator==(const IterType &R) const { @@ -164,12 +101,12 @@ public: return false; } - const ValueType &operator*() const { + const Value &operator*() const { assert(Array && !HasError); return ThisValue; } - ValueType &operator*() { + Value &operator*() { assert(Array && !HasError); return ThisValue; } @@ -185,7 +122,7 @@ public: moveToEnd(); } else { // There is some data after the current record. - auto EC = ExtractorType::extract(IterRef, ThisLen, ThisValue, Context); + auto EC = Ctx->template invoke<Extractor>(IterRef, ThisLen, ThisValue); if (EC) { consumeError(std::move(EC)); markError(); @@ -210,15 +147,136 @@ private: *HadError = true; } - ValueType ThisValue; + Value ThisValue; BinaryStreamRef IterRef; - ContextType *Context{nullptr}; + const WrappedCtx *Ctx{nullptr}; const ArrayType *Array{nullptr}; uint32_t ThisLen{0}; bool HasError{false}; bool *HadError{nullptr}; }; +template <typename T, typename Context> struct ContextWrapper { + ContextWrapper() = default; + + explicit ContextWrapper(Context &&Ctx) : Ctx(Ctx) {} + + template <typename Extractor> + Error invoke(BinaryStreamRef Stream, uint32_t &Len, T &Item) const { + return Extractor::extract(Stream, Len, Item, Ctx); + } + + Context Ctx; +}; + +template <typename T> struct ContextWrapper<T, void> { + ContextWrapper() = default; + + template <typename Extractor> + Error invoke(BinaryStreamRef Stream, uint32_t &Len, T &Item) const { + return Extractor::extract(Stream, Len, Item); + } +}; + +/// VarStreamArray represents an array of variable length records backed by a +/// stream. This could be a contiguous sequence of bytes in memory, it could +/// be a file on disk, or it could be a PDB stream where bytes are stored as +/// discontiguous blocks in a file. Usually it is desirable to treat arrays +/// as contiguous blocks of memory, but doing so with large PDB files, for +/// example, could mean allocating huge amounts of memory just to allow +/// re-ordering of stream data to be contiguous before iterating over it. By +/// abstracting this out, we need not duplicate this memory, and we can +/// iterate over arrays in arbitrarily formatted streams. Elements are parsed +/// lazily on iteration, so there is no upfront cost associated with building +/// or copying a VarStreamArray, no matter how large it may be. +/// +/// You create a VarStreamArray by specifying a ValueType and an Extractor type. +/// If you do not specify an Extractor type, you are expected to specialize +/// VarStreamArrayExtractor<T> for your ValueType. +/// +/// The default extractor type is stateless, but by specializing +/// VarStreamArrayExtractor or defining your own custom extractor type and +/// adding the appropriate ContextType typedef to the class, you can pass a +/// context field during construction of the VarStreamArray that will be +/// passed to each call to extract. +/// +template <typename Value, typename Extractor, typename WrappedCtx> +class VarStreamArrayBase { + typedef VarStreamArrayBase<Value, Extractor, WrappedCtx> MyType; + +public: + typedef VarStreamArrayIterator<MyType, Value, Extractor, WrappedCtx> Iterator; + friend Iterator; + + VarStreamArrayBase() = default; + + VarStreamArrayBase(BinaryStreamRef Stream, const WrappedCtx &Ctx) + : Stream(Stream), Ctx(Ctx) {} + + VarStreamArrayBase(const MyType &Other) + : Stream(Other.Stream), Ctx(Other.Ctx) {} + + Iterator begin(bool *HadError = nullptr) const { + if (empty()) + return end(); + + return Iterator(*this, Ctx, Stream, HadError); + } + + bool valid() const { return Stream.valid(); } + + Iterator end() const { return Iterator(Ctx); } + + bool empty() const { return Stream.getLength() == 0; } + + /// \brief given an offset into the array's underlying stream, return an + /// iterator to the record at that offset. This is considered unsafe + /// since the behavior is undefined if \p Offset does not refer to the + /// beginning of a valid record. + Iterator at(uint32_t Offset) const { + return Iterator(*this, Ctx, Stream.drop_front(Offset), nullptr); + } + + BinaryStreamRef getUnderlyingStream() const { return Stream; } + +private: + BinaryStreamRef Stream; + WrappedCtx Ctx; +}; + +template <typename Value, typename Extractor, typename Context> +class VarStreamArrayImpl + : public VarStreamArrayBase<Value, Extractor, + ContextWrapper<Value, Context>> { + typedef ContextWrapper<Value, Context> WrappedContext; + typedef VarStreamArrayImpl<Value, Extractor, Context> MyType; + typedef VarStreamArrayBase<Value, Extractor, WrappedContext> BaseType; + +public: + typedef Context ContextType; + + VarStreamArrayImpl() = default; + VarStreamArrayImpl(BinaryStreamRef Stream, Context &&Ctx) + : BaseType(Stream, WrappedContext(std::forward<Context>(Ctx))) {} +}; + +template <typename Value, typename Extractor> +class VarStreamArrayImpl<Value, Extractor, void> + : public VarStreamArrayBase<Value, Extractor, ContextWrapper<Value, void>> { + typedef ContextWrapper<Value, void> WrappedContext; + typedef VarStreamArrayImpl<Value, Extractor, void> MyType; + typedef VarStreamArrayBase<Value, Extractor, WrappedContext> BaseType; + +public: + VarStreamArrayImpl() = default; + VarStreamArrayImpl(BinaryStreamRef Stream) + : BaseType(Stream, WrappedContext()) {} +}; + +template <typename Value, typename Extractor = VarStreamArrayExtractor<Value>> +using VarStreamArray = + VarStreamArrayImpl<Value, Extractor, typename Extractor::ContextType>; + template <typename T> class FixedStreamArrayIterator; /// FixedStreamArray is similar to VarStreamArray, except with each record diff --git a/include/llvm/Support/BinaryStreamReader.h b/include/llvm/Support/BinaryStreamReader.h index f30d82d81b25..77738077f5ff 100644 --- a/include/llvm/Support/BinaryStreamReader.h +++ b/include/llvm/Support/BinaryStreamReader.h @@ -31,6 +31,7 @@ namespace llvm { /// are overridable. class BinaryStreamReader { public: + BinaryStreamReader() = default; explicit BinaryStreamReader(BinaryStreamRef Stream); virtual ~BinaryStreamReader() {} @@ -172,13 +173,29 @@ public: /// \returns a success error code if the data was successfully read, otherwise /// returns an appropriate error code. template <typename T, typename U> - Error - readArray(VarStreamArray<T, U> &Array, uint32_t Size, - typename VarStreamArray<T, U>::ContextType *Context = nullptr) { + Error readArray(VarStreamArray<T, U> &Array, uint32_t Size) { BinaryStreamRef S; if (auto EC = readStreamRef(S, Size)) return EC; - Array = VarStreamArray<T, U>(S, Context); + Array = VarStreamArray<T, U>(S); + return Error::success(); + } + + /// Read a VarStreamArray of size \p Size bytes and store the result into + /// \p Array. Updates the stream's offset to point after the newly read + /// array. Never causes a copy (although iterating the elements of the + /// VarStreamArray may, depending upon the implementation of the underlying + /// stream). + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + template <typename T, typename U, typename ContextType> + Error readArray(VarStreamArray<T, U> &Array, uint32_t Size, + ContextType &&Context) { + BinaryStreamRef S; + if (auto EC = readStreamRef(S, Size)) + return EC; + Array = VarStreamArray<T, U>(S, std::move(Context)); return Error::success(); } @@ -227,6 +244,9 @@ public: /// \returns the next byte in the stream. uint8_t peek() const; + std::pair<BinaryStreamReader, BinaryStreamReader> + split(uint32_t Offset) const; + private: BinaryStreamRef Stream; uint32_t Offset; diff --git a/include/llvm/Support/BinaryStreamRef.h b/include/llvm/Support/BinaryStreamRef.h index 23ce02fd7ca4..465e724a6886 100644 --- a/include/llvm/Support/BinaryStreamRef.h +++ b/include/llvm/Support/BinaryStreamRef.h @@ -98,6 +98,9 @@ public: BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset, uint32_t Length) = delete; + /// Check if a Stream is valid. + bool valid() const { return Stream != nullptr; } + /// Given an Offset into this StreamRef and a Size, return a reference to a /// buffer owned by the stream. /// diff --git a/include/llvm/Support/BinaryStreamWriter.h b/include/llvm/Support/BinaryStreamWriter.h index 6734a797ccc4..1b61c32a2541 100644 --- a/include/llvm/Support/BinaryStreamWriter.h +++ b/include/llvm/Support/BinaryStreamWriter.h @@ -20,6 +20,7 @@ #include "llvm/Support/Error.h" #include <cstdint> #include <type_traits> +#include <utility> namespace llvm { @@ -30,8 +31,6 @@ namespace llvm { /// although no methods are overridable. class BinaryStreamWriter { public: - // FIXME: We should be able to slice and drop_front etc on Writers / Readers. - BinaryStreamWriter() = default; explicit BinaryStreamWriter(WritableBinaryStreamRef Stream); virtual ~BinaryStreamWriter() {} @@ -152,6 +151,9 @@ public: return writeStreamRef(Array.getUnderlyingStream()); } + /// Splits the Writer into two Writers at a given offset. + std::pair<BinaryStreamWriter, BinaryStreamWriter> split(uint32_t Off) const; + void setOffset(uint32_t Off) { Offset = Off; } uint32_t getOffset() const { return Offset; } uint32_t getLength() const { return Stream.getLength(); } diff --git a/include/llvm/Support/DataExtractor.h b/include/llvm/Support/DataExtractor.h index 2d1180c228e3..380b628fd95f 100644 --- a/include/llvm/Support/DataExtractor.h +++ b/include/llvm/Support/DataExtractor.h @@ -58,6 +58,28 @@ public: /// NULL will be returned. const char *getCStr(uint32_t *offset_ptr) const; + /// Extract a C string from \a *OffsetPtr. + /// + /// Returns a StringRef for the C String from the data at the offset + /// pointed to by \a OffsetPtr. A variable length NULL terminated C + /// string will be extracted and the \a OffsetPtr will be + /// updated with the offset of the byte that follows the NULL + /// terminator byte. + /// + /// \param[in,out] OffsetPtr + /// A pointer to an offset within the data that will be advanced + /// by the appropriate number of bytes if the value is extracted + /// correctly. If the offset is out of bounds or there are not + /// enough bytes to extract this value, the offset will be left + /// unmodified. + /// + /// \return + /// A StringRef for the C string value in the data. If the offset + /// pointed to by \a OffsetPtr is out of bounds, or if the + /// offset plus the length of the C string is out of bounds, + /// a default-initialized StringRef will be returned. + StringRef getCStrRef(uint32_t *OffsetPtr) const; + /// Extract an unsigned integer of size \a byte_size from \a /// *offset_ptr. /// diff --git a/include/llvm/Support/ELFRelocs/Hexagon.def b/include/llvm/Support/ELFRelocs/Hexagon.def index 74e1d405cebd..5021e2b26ce5 100644 --- a/include/llvm/Support/ELFRelocs/Hexagon.def +++ b/include/llvm/Support/ELFRelocs/Hexagon.def @@ -99,3 +99,8 @@ ELF_RELOC(R_HEX_LD_GOT_32_6_X, 91) ELF_RELOC(R_HEX_LD_GOT_16_X, 92) ELF_RELOC(R_HEX_LD_GOT_11_X, 93) ELF_RELOC(R_HEX_23_REG, 94) +ELF_RELOC(R_HEX_GD_PLT_B22_PCREL_X, 95) +ELF_RELOC(R_HEX_GD_PLT_B32_PCREL_X, 96) +ELF_RELOC(R_HEX_LD_PLT_B22_PCREL_X, 97) +ELF_RELOC(R_HEX_LD_PLT_B32_PCREL_X, 98) +ELF_RELOC(R_HEX_27_REG, 99) |