Index: lld/trunk/COFF/PDB.cpp =================================================================== --- lld/trunk/COFF/PDB.cpp +++ lld/trunk/COFF/PDB.cpp @@ -20,7 +20,6 @@ #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" @@ -34,6 +33,7 @@ #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Path.h" Index: llvm/trunk/include/llvm/DebugInfo/CodeView/CVRecord.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/CVRecord.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/CVRecord.h @@ -14,8 +14,8 @@ #include "llvm/ADT/Optional.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include Index: llvm/trunk/include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h @@ -17,8 +17,8 @@ #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Error.h" #include #include Index: llvm/trunk/include/llvm/DebugInfo/CodeView/ModuleSubstream.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/ModuleSubstream.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/ModuleSubstream.h @@ -11,8 +11,8 @@ #define LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H #include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" Index: llvm/trunk/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h @@ -15,9 +15,9 @@ #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/Line.h" #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include Index: llvm/trunk/include/llvm/DebugInfo/CodeView/RecordSerialization.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/RecordSerialization.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/RecordSerialization.h @@ -15,7 +15,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include Index: llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h @@ -15,8 +15,8 @@ #include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h" #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" #include "llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" namespace llvm { Index: llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolRecord.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolRecord.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolRecord.h @@ -19,7 +19,7 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include Index: llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolSerializer.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolSerializer.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolSerializer.h @@ -18,9 +18,9 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Error.h" namespace llvm { Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeDeserializer.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeDeserializer.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeDeserializer.h @@ -16,8 +16,8 @@ #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" #include #include Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h @@ -18,7 +18,7 @@ #include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Endian.h" #include #include Index: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeSerializer.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeSerializer.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeSerializer.h @@ -12,8 +12,8 @@ #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" Index: llvm/trunk/include/llvm/DebugInfo/MSF/BinaryByteStream.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/MSF/BinaryByteStream.h +++ llvm/trunk/include/llvm/DebugInfo/MSF/BinaryByteStream.h @@ -1,192 +0,0 @@ -//===- BinaryByteStream.h ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -//===----------------------------------------------------------------------===// -// A BinaryStream which stores data in a single continguous memory buffer. -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_MSF_BINARYBYTESTREAM_H -#define LLVM_DEBUGINFO_MSF_BINARYBYTESTREAM_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/BinaryStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamError.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/MemoryBuffer.h" -#include -#include -#include -#include - -namespace llvm { - -/// \brief An implementation of BinaryStream which holds its entire data set -/// in a single contiguous buffer. BinaryByteStream guarantees that no read -/// operation will ever incur a copy. Note that BinaryByteStream does not -/// own the underlying buffer. -class BinaryByteStream : public BinaryStream { -public: - BinaryByteStream() = default; - BinaryByteStream(ArrayRef Data, llvm::support::endianness Endian) - : Endian(Endian), Data(Data) {} - BinaryByteStream(StringRef Data, llvm::support::endianness Endian) - : Endian(Endian), Data(Data.bytes_begin(), Data.bytes_end()) {} - - llvm::support::endianness getEndian() const override { return Endian; } - - Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) override { - if (auto EC = checkOffset(Offset, Size)) - return EC; - Buffer = Data.slice(Offset, Size); - return Error::success(); - } - - Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) override { - if (auto EC = checkOffset(Offset, 1)) - return EC; - Buffer = Data.slice(Offset); - return Error::success(); - } - - uint32_t getLength() override { return Data.size(); } - - ArrayRef data() const { return Data; } - - StringRef str() const { - const char *CharData = reinterpret_cast(Data.data()); - return StringRef(CharData, Data.size()); - } - -protected: - llvm::support::endianness Endian; - ArrayRef Data; -}; - -/// \brief An implementation of BinaryStream whose data is backed by an llvm -/// MemoryBuffer object. MemoryBufferByteStream owns the MemoryBuffer in -/// question. As with BinaryByteStream, reading from a MemoryBufferByteStream -/// will never cause a copy. -class MemoryBufferByteStream : public BinaryByteStream { -public: - MemoryBufferByteStream(std::unique_ptr Buffer, - llvm::support::endianness Endian) - : BinaryByteStream(Buffer->getBuffer(), Endian), - MemBuffer(std::move(Buffer)) {} - - std::unique_ptr MemBuffer; -}; - -/// \brief An implementation of BinaryStream which holds its entire data set -/// in a single contiguous buffer. As with BinaryByteStream, the mutable -/// version also guarantees that no read operation will ever incur a copy, -/// and similarly it does not own the underlying buffer. -class MutableBinaryByteStream : public WritableBinaryStream { -public: - MutableBinaryByteStream() = default; - MutableBinaryByteStream(MutableArrayRef Data, - llvm::support::endianness Endian) - : Data(Data), ImmutableStream(Data, Endian) {} - - llvm::support::endianness getEndian() const override { - return ImmutableStream.getEndian(); - } - - Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) override { - return ImmutableStream.readBytes(Offset, Size, Buffer); - } - - Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) override { - return ImmutableStream.readLongestContiguousChunk(Offset, Buffer); - } - - uint32_t getLength() override { return ImmutableStream.getLength(); } - - Error writeBytes(uint32_t Offset, ArrayRef Buffer) override { - if (Buffer.empty()) - return Error::success(); - - if (auto EC = checkOffset(Offset, Buffer.size())) - return EC; - - uint8_t *DataPtr = const_cast(Data.data()); - ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size()); - return Error::success(); - } - - Error commit() override { return Error::success(); } - - MutableArrayRef data() const { return Data; } - -private: - MutableArrayRef Data; - BinaryByteStream ImmutableStream; -}; - -/// \brief An implementation of WritableBinaryStream backed by an llvm -/// FileOutputBuffer. -class FileBufferByteStream : public WritableBinaryStream { -private: - class StreamImpl : public MutableBinaryByteStream { - public: - StreamImpl(std::unique_ptr Buffer, - llvm::support::endianness Endian) - : MutableBinaryByteStream( - MutableArrayRef(Buffer->getBufferStart(), - Buffer->getBufferEnd()), - Endian), - FileBuffer(std::move(Buffer)) {} - - Error commit() override { - if (FileBuffer->commit()) - return make_error( - stream_error_code::filesystem_error); - return Error::success(); - } - - private: - std::unique_ptr FileBuffer; - }; - -public: - FileBufferByteStream(std::unique_ptr Buffer, - llvm::support::endianness Endian) - : Impl(std::move(Buffer), Endian) {} - - llvm::support::endianness getEndian() const override { - return Impl.getEndian(); - } - - Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) override { - return Impl.readBytes(Offset, Size, Buffer); - } - - Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) override { - return Impl.readLongestContiguousChunk(Offset, Buffer); - } - - uint32_t getLength() override { return Impl.getLength(); } - - Error writeBytes(uint32_t Offset, ArrayRef Data) override { - return Impl.writeBytes(Offset, Data); - } - - Error commit() override { return Impl.commit(); } - -private: - StreamImpl Impl; -}; - -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_BYTESTREAM_H Index: llvm/trunk/include/llvm/DebugInfo/MSF/BinaryItemStream.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/MSF/BinaryItemStream.h +++ llvm/trunk/include/llvm/DebugInfo/MSF/BinaryItemStream.h @@ -1,95 +0,0 @@ -//===- BinaryItemStream.h ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_MSF_BINARYITEMSTREAM_H -#define LLVM_DEBUGINFO_MSF_BINARYITEMSTREAM_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/BinaryStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamError.h" -#include "llvm/Support/Error.h" -#include -#include - -namespace llvm { - -template struct BinaryItemTraits { - static size_t length(const T &Item) = delete; - static ArrayRef bytes(const T &Item) = delete; -}; - -/// BinaryItemStream represents a sequence of objects stored in some kind of -/// external container but for which it is useful to view as a stream of -/// contiguous bytes. An example of this might be if you have a collection of -/// records and you serialize each one into a buffer, and store these serialized -/// records in a container. The pointers themselves are not laid out -/// contiguously in memory, but we may wish to read from or write to these -/// records as if they were. -template > -class BinaryItemStream : public BinaryStream { -public: - explicit BinaryItemStream(llvm::support::endianness Endian) - : Endian(Endian) {} - - llvm::support::endianness getEndian() const override { return Endian; } - - Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) override { - auto ExpectedIndex = translateOffsetIndex(Offset); - if (!ExpectedIndex) - return ExpectedIndex.takeError(); - const auto &Item = Items[*ExpectedIndex]; - if (auto EC = checkOffset(Offset, Size)) - return EC; - if (Size > Traits::length(Item)) - return make_error(stream_error_code::stream_too_short); - Buffer = Traits::bytes(Item).take_front(Size); - return Error::success(); - } - - Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) override { - auto ExpectedIndex = translateOffsetIndex(Offset); - if (!ExpectedIndex) - return ExpectedIndex.takeError(); - Buffer = Traits::bytes(Items[*ExpectedIndex]); - return Error::success(); - } - - void setItems(ArrayRef ItemArray) { Items = ItemArray; } - - uint32_t getLength() override { - uint32_t Size = 0; - for (const auto &Item : Items) - Size += Traits::length(Item); - return Size; - } - -private: - Expected translateOffsetIndex(uint32_t Offset) const { - uint32_t CurrentOffset = 0; - uint32_t CurrentIndex = 0; - for (const auto &Item : Items) { - if (CurrentOffset >= Offset) - break; - CurrentOffset += Traits::length(Item); - ++CurrentIndex; - } - if (CurrentOffset != Offset) - return make_error(stream_error_code::stream_too_short); - return CurrentIndex; - } - - llvm::support::endianness Endian; - ArrayRef Items; -}; - -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_BINARYITEMSTREAM_H Index: llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStream.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStream.h +++ llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStream.h @@ -1,78 +0,0 @@ -//===- BinaryStream.h - Base interface for a stream of data -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_MSF_BINARYSTREAM_H -#define LLVM_DEBUGINFO_MSF_BINARYSTREAM_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/BinaryStreamError.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include - -namespace llvm { - -/// \brief An interface for accessing data in a stream-like format, but which -/// discourages copying. Instead of specifying a buffer in which to copy -/// data on a read, the API returns an ArrayRef to data owned by the stream's -/// implementation. Since implementations may not necessarily store data in a -/// single contiguous buffer (or even in memory at all), in such cases a it may -/// be necessary for an implementation to cache such a buffer so that it can -/// return it. -class BinaryStream { -public: - virtual ~BinaryStream() = default; - - virtual llvm::support::endianness getEndian() const = 0; - - /// \brief Given an offset into the stream and a number of bytes, attempt to - /// read the bytes and set the output ArrayRef to point to data owned by the - /// stream. - virtual Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) = 0; - - /// \brief Given an offset into the stream, read as much as possible without - /// copying any data. - virtual Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) = 0; - - /// \brief Return the number of bytes of data in this stream. - virtual uint32_t getLength() = 0; - -protected: - Error checkOffset(uint32_t Offset, uint32_t DataSize) { - if (Offset > getLength()) - return make_error(stream_error_code::invalid_offset); - if (getLength() < DataSize + Offset) - return make_error(stream_error_code::stream_too_short); - return Error::success(); - } -}; - -/// \brief A BinaryStream which can be read from as well as written to. Note -/// that writing to a BinaryStream always necessitates copying from the input -/// buffer to the stream's backing store. Streams are assumed to be buffered -/// so that to be portable it is necessary to call commit() on the stream when -/// all data has been written. -class WritableBinaryStream : public BinaryStream { -public: - ~WritableBinaryStream() override = default; - - /// \brief Attempt to write the given bytes into the stream at the desired - /// offset. This will always necessitate a copy. Cannot shrink or grow the - /// stream, only writes into existing allocated space. - virtual Error writeBytes(uint32_t Offset, ArrayRef Data) = 0; - - /// \brief For buffered streams, commits changes to the backing store. - virtual Error commit() = 0; -}; - -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_BINARYSTREAM_H Index: llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStreamArray.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStreamArray.h +++ llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStreamArray.h @@ -1,320 +0,0 @@ -//===- BinaryStreamArray.h - Array backed by an arbitrary stream *- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_MSF_BINARYSTREAMARRAY_H -#define LLVM_DEBUGINFO_MSF_BINARYSTREAMARRAY_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/iterator.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" -#include "llvm/Support/Error.h" -#include -#include - -/// Lightweight arrays that are backed by an arbitrary BinaryStream. This file -/// provides two different array implementations. -/// -/// VarStreamArray - Arrays of variable length records. The user specifies -/// an Extractor type that can extract a record from a given offset and -/// return the number of bytes consumed by the record. -/// -/// FixedStreamArray - Arrays of fixed length records. This is similar in -/// spirit to ArrayRef, but since it is backed by a BinaryStream, the -/// elements of the array need not be laid out in contiguous memory. -namespace llvm { - -/// VarStreamArrayExtractor is intended to be specialized to provide customized -/// extraction logic. On input it receives a BinaryStreamRef pointing to the -/// beginning of the next record, but where the length of the record is not yet -/// known. Upon completion, it should return an appropriate Error instance if -/// a record could not be extracted, or if one could be extracted it should -/// return success and set Len to the number of bytes this record occupied in -/// the underlying stream, and it should fill out the fields of the value type -/// Item appropriately to represent the current record. -/// -/// You can specialize this template for your own custom value types to avoid -/// having to specify a second template argument to VarStreamArray (documented -/// below). -template struct VarStreamArrayExtractor { - // Method intentionally deleted. You must provide an explicit specialization - // with the following method implemented. - Error operator()(BinaryStreamRef Stream, uint32_t &Len, - T &Item) const = 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 for your ValueType. -/// -/// By default an Extractor is default constructed in the class, but in some -/// cases you might find it useful for an Extractor to maintain state across -/// extractions. In this case you can provide your own Extractor through a -/// secondary constructor. The following examples show various ways of -/// creating a VarStreamArray. -/// -/// // Will use VarStreamArrayExtractor as the extractor. -/// VarStreamArray MyTypeArray; -/// -/// // Will use a default-constructed MyExtractor as the extractor. -/// VarStreamArray MyTypeArray2; -/// -/// // Will use the specific instance of MyExtractor provided. -/// // MyExtractor need not be default-constructible in this case. -/// MyExtractor E(SomeContext); -/// VarStreamArray MyTypeArray3(E); -/// -template class VarStreamArrayIterator; - -template > - -class VarStreamArray { - friend class VarStreamArrayIterator; - -public: - typedef VarStreamArrayIterator Iterator; - - VarStreamArray() = default; - explicit VarStreamArray(const Extractor &E) : E(E) {} - - explicit VarStreamArray(BinaryStreamRef Stream) : Stream(Stream) {} - VarStreamArray(BinaryStreamRef Stream, const Extractor &E) - : Stream(Stream), E(E) {} - - VarStreamArray(const VarStreamArray &Other) - : Stream(Other.Stream), E(Other.E) {} - - Iterator begin(bool *HadError = nullptr) const { - return Iterator(*this, E, HadError); - } - - Iterator end() const { return Iterator(E); } - - const Extractor &getExtractor() const { return E; } - - BinaryStreamRef getUnderlyingStream() const { return Stream; } - -private: - BinaryStreamRef Stream; - Extractor E; -}; - -template -class VarStreamArrayIterator - : public iterator_facade_base, - std::forward_iterator_tag, ValueType> { - typedef VarStreamArrayIterator IterType; - typedef VarStreamArray ArrayType; - -public: - VarStreamArrayIterator(const ArrayType &Array, const Extractor &E, - bool *HadError = nullptr) - : IterRef(Array.Stream), Array(&Array), HadError(HadError), Extract(E) { - if (IterRef.getLength() == 0) - moveToEnd(); - else { - auto EC = Extract(IterRef, ThisLen, ThisValue); - if (EC) { - consumeError(std::move(EC)); - markError(); - } - } - } - VarStreamArrayIterator() = default; - explicit VarStreamArrayIterator(const Extractor &E) : Extract(E) {} - ~VarStreamArrayIterator() = default; - - bool operator==(const IterType &R) const { - if (Array && R.Array) { - // Both have a valid array, make sure they're same. - assert(Array == R.Array); - return IterRef == R.IterRef; - } - - // Both iterators are at the end. - if (!Array && !R.Array) - return true; - - // One is not at the end and one is. - return false; - } - - const ValueType &operator*() const { - assert(Array && !HasError); - return ThisValue; - } - - IterType &operator+=(unsigned N) { - for (unsigned I = 0; I < N; ++I) { - // We are done with the current record, discard it so that we are - // positioned at the next record. - IterRef = IterRef.drop_front(ThisLen); - if (IterRef.getLength() == 0) { - // There is nothing after the current record, we must make this an end - // iterator. - moveToEnd(); - } else { - // There is some data after the current record. - auto EC = Extract(IterRef, ThisLen, ThisValue); - if (EC) { - consumeError(std::move(EC)); - markError(); - } else if (ThisLen == 0) { - // An empty record? Make this an end iterator. - moveToEnd(); - } - } - } - return *this; - } - -private: - void moveToEnd() { - Array = nullptr; - ThisLen = 0; - } - void markError() { - moveToEnd(); - HasError = true; - if (HadError != nullptr) - *HadError = true; - } - - ValueType ThisValue; - BinaryStreamRef IterRef; - const ArrayType *Array{nullptr}; - uint32_t ThisLen{0}; - bool HasError{false}; - bool *HadError{nullptr}; - Extractor Extract; -}; - -template class FixedStreamArrayIterator; - -/// FixedStreamArray is similar to VarStreamArray, except with each record -/// having a fixed-length. As with VarStreamArray, there is no upfront -/// cost associated with building or copying a FixedStreamArray, as the -/// memory for each element is not read from the backing stream until that -/// element is iterated. -template class FixedStreamArray { - friend class FixedStreamArrayIterator; - -public: - FixedStreamArray() = default; - explicit FixedStreamArray(BinaryStreamRef Stream) : Stream(Stream) { - assert(Stream.getLength() % sizeof(T) == 0); - } - - bool operator==(const FixedStreamArray &Other) const { - return Stream == Other.Stream; - } - - bool operator!=(const FixedStreamArray &Other) const { - return !(*this == Other); - } - - FixedStreamArray &operator=(const FixedStreamArray &) = default; - - const T &operator[](uint32_t Index) const { - assert(Index < size()); - uint32_t Off = Index * sizeof(T); - ArrayRef Data; - if (auto EC = Stream.readBytes(Off, sizeof(T), Data)) { - assert(false && "Unexpected failure reading from stream"); - // This should never happen since we asserted that the stream length was - // an exact multiple of the element size. - consumeError(std::move(EC)); - } - assert(llvm::alignmentAdjustment(Data.data(), alignof(T)) == 0); - return *reinterpret_cast(Data.data()); - } - - uint32_t size() const { return Stream.getLength() / sizeof(T); } - - bool empty() const { return size() == 0; } - - FixedStreamArrayIterator begin() const { - return FixedStreamArrayIterator(*this, 0); - } - - FixedStreamArrayIterator end() const { - return FixedStreamArrayIterator(*this, size()); - } - - BinaryStreamRef getUnderlyingStream() const { return Stream; } - -private: - BinaryStreamRef Stream; -}; - -template -class FixedStreamArrayIterator - : public iterator_facade_base, - std::random_access_iterator_tag, T> { - -public: - FixedStreamArrayIterator(const FixedStreamArray &Array, uint32_t Index) - : Array(Array), Index(Index) {} - - FixedStreamArrayIterator & - operator=(const FixedStreamArrayIterator &Other) { - Array = Other.Array; - Index = Other.Index; - return *this; - } - - const T &operator*() const { return Array[Index]; } - - bool operator==(const FixedStreamArrayIterator &R) const { - assert(Array == R.Array); - return (Index == R.Index) && (Array == R.Array); - } - - FixedStreamArrayIterator &operator+=(std::ptrdiff_t N) { - Index += N; - return *this; - } - - FixedStreamArrayIterator &operator-=(std::ptrdiff_t N) { - assert(Index >= N); - Index -= N; - return *this; - } - - std::ptrdiff_t operator-(const FixedStreamArrayIterator &R) const { - assert(Array == R.Array); - assert(Index >= R.Index); - return Index - R.Index; - } - - bool operator<(const FixedStreamArrayIterator &RHS) const { - assert(Array == RHS.Array); - return Index < RHS.Index; - } - -private: - FixedStreamArray Array; - uint32_t Index; -}; - -} // namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_BINARYSTREAMARRAY_H Index: llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStreamError.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStreamError.h +++ llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStreamError.h @@ -1,47 +0,0 @@ -//===- BinaryStreamError.h - Error extensions for Binary Streams *- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_MSF_BINARYSTREAMERROR_H -#define LLVM_DEBUGINFO_MSF_BINARYSTREAMERROR_H - -#include "llvm/Support/Error.h" - -#include - -namespace llvm { -enum class stream_error_code { - unspecified, - stream_too_short, - invalid_array_size, - invalid_offset, - filesystem_error -}; - -/// Base class for errors originating when parsing raw PDB files -class BinaryStreamError : public ErrorInfo { -public: - static char ID; - explicit BinaryStreamError(stream_error_code C); - explicit BinaryStreamError(StringRef Context); - BinaryStreamError(stream_error_code C, StringRef Context); - - void log(raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; - - StringRef getErrorMessage() const; - - stream_error_code getErrorCode() const { return Code; } - -private: - std::string ErrMsg; - stream_error_code Code; -}; -} // namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_BINARYSTREAMERROR_H Index: llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStreamReader.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStreamReader.h +++ llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStreamReader.h @@ -1,234 +0,0 @@ -//===- BinaryStreamReader.h - Reads objects from a binary stream *- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_MSF_BINARYSTREAMREADER_H -#define LLVM_DEBUGINFO_MSF_BINARYSTREAMREADER_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/MathExtras.h" -#include "llvm/Support/type_traits.h" - -#include -#include - -namespace llvm { - -/// \brief Provides read only access to a subclass of `BinaryStream`. Provides -/// bounds checking and helpers for writing certain common data types such as -/// null-terminated strings, integers in various flavors of endianness, etc. -/// Can be subclassed to provide reading of custom datatypes, although no -/// are overridable. -class BinaryStreamReader { -public: - explicit BinaryStreamReader(BinaryStreamRef Stream); - virtual ~BinaryStreamReader() {} - - /// Read as much as possible from the underlying string at the current offset - /// without invoking a copy, and set \p Buffer to the resulting data slice. - /// Updates the stream's offset to point after the newly read data. - /// - /// \returns a success error code if the data was successfully read, otherwise - /// returns an appropriate error code. - Error readLongestContiguousChunk(ArrayRef &Buffer); - - /// Read \p Size bytes from the underlying stream at the current offset and - /// and set \p Buffer to the resulting data slice. Whether a copy occurs - /// depends on the implementation of the underlying stream. Updates the - /// stream's offset to point after the newly read data. - /// - /// \returns a success error code if the data was successfully read, otherwise - /// returns an appropriate error code. - Error readBytes(ArrayRef &Buffer, uint32_t Size); - - /// Read an integer of the specified endianness into \p Dest and update the - /// stream's offset. The data is always copied from the stream's underlying - /// buffer into \p Dest. Updates the stream's offset to point after the newly - /// read data. - /// - /// \returns a success error code if the data was successfully read, otherwise - /// returns an appropriate error code. - template Error readInteger(T &Dest) { - static_assert(std::is_integral::value, - "Cannot call readInteger with non-integral value!"); - - ArrayRef Bytes; - if (auto EC = readBytes(Bytes, sizeof(T))) - return EC; - - Dest = llvm::support::endian::read( - Bytes.data(), Stream.getEndian()); - return Error::success(); - } - - /// Similar to readInteger. - template Error readEnum(T &Dest) { - static_assert(std::is_enum::value, - "Cannot call readEnum with non-enum value!"); - typename std::underlying_type::type N; - if (auto EC = readInteger(N)) - return EC; - Dest = static_cast(N); - return Error::success(); - } - - /// Read a null terminated string from \p Dest. Whether a copy occurs depends - /// on the implementation of the underlying stream. Updates the stream's - /// offset to point after the newly read data. - /// - /// \returns a success error code if the data was successfully read, otherwise - /// returns an appropriate error code. - Error readCString(StringRef &Dest); - - /// Read a \p Length byte string into \p Dest. Whether a copy occurs depends - /// on the implementation of the underlying stream. Updates the stream's - /// offset to point after the newly read data. - /// - /// \returns a success error code if the data was successfully read, otherwise - /// returns an appropriate error code. - Error readFixedString(StringRef &Dest, uint32_t Length); - - /// Read the entire remainder of the underlying stream into \p Ref. This is - /// equivalent to calling getUnderlyingStream().slice(Offset). Updates the - /// stream's offset to point to the end of the stream. Never causes a copy. - /// - /// \returns a success error code if the data was successfully read, otherwise - /// returns an appropriate error code. - Error readStreamRef(BinaryStreamRef &Ref); - - /// Read \p Length bytes from the underlying stream into \p Ref. This is - /// equivalent to calling getUnderlyingStream().slice(Offset, Length). - /// Updates the stream's offset to point after the newly read object. Never - /// causes a copy. - /// - /// \returns a success error code if the data was successfully read, otherwise - /// returns an appropriate error code. - Error readStreamRef(BinaryStreamRef &Ref, uint32_t Length); - - /// Get a pointer to an object of type T from the underlying stream, as if by - /// memcpy, and store the result into \p Dest. It is up to the caller to - /// ensure that objects of type T can be safely treated in this manner. - /// Updates the stream's offset to point after the newly read object. Whether - /// a copy occurs depends 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 Error readObject(const T *&Dest) { - ArrayRef Buffer; - if (auto EC = readBytes(Buffer, sizeof(T))) - return EC; - Dest = reinterpret_cast(Buffer.data()); - return Error::success(); - } - - /// Get a reference to a \p NumElements element array of objects of type T - /// from the underlying stream as if by memcpy, and store the resulting array - /// slice into \p array. It is up to the caller to ensure that objects of - /// type T can be safely treated in this manner. Updates the stream's offset - /// to point after the newly read object. Whether a copy occurs depends 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 - Error readArray(ArrayRef &Array, uint32_t NumElements) { - ArrayRef Bytes; - if (NumElements == 0) { - Array = ArrayRef(); - return Error::success(); - } - - if (NumElements > UINT32_MAX / sizeof(T)) - return make_error( - stream_error_code::invalid_array_size); - - if (auto EC = readBytes(Bytes, NumElements * sizeof(T))) - return EC; - - assert(alignmentAdjustment(Bytes.data(), alignof(T)) == 0 && - "Reading at invalid alignment!"); - - Array = ArrayRef(reinterpret_cast(Bytes.data()), NumElements); - 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 - Error readArray(VarStreamArray &Array, uint32_t Size) { - BinaryStreamRef S; - if (auto EC = readStreamRef(S, Size)) - return EC; - Array = VarStreamArray(S, Array.getExtractor()); - return Error::success(); - } - - /// Read a FixedStreamArray of \p NumItems elements 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 - /// FixedStreamArray 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 - Error readArray(FixedStreamArray &Array, uint32_t NumItems) { - if (NumItems == 0) { - Array = FixedStreamArray(); - return Error::success(); - } - - if (NumItems > UINT32_MAX / sizeof(T)) - return make_error( - stream_error_code::invalid_array_size); - - BinaryStreamRef View; - if (auto EC = readStreamRef(View, NumItems * sizeof(T))) - return EC; - - Array = FixedStreamArray(View); - return Error::success(); - } - - bool empty() const { return bytesRemaining() == 0; } - void setOffset(uint32_t Off) { Offset = Off; } - uint32_t getOffset() const { return Offset; } - uint32_t getLength() const { return Stream.getLength(); } - uint32_t bytesRemaining() const { return getLength() - getOffset(); } - - /// Advance the stream's offset by \p Amount bytes. - /// - /// \returns a success error code if at least \p Amount bytes remain in the - /// stream, otherwise returns an appropriate error code. - Error skip(uint32_t Amount); - - /// Examine the next byte of the underlying stream without advancing the - /// stream's offset. If the stream is empty the behavior is undefined. - /// - /// \returns the next byte in the stream. - uint8_t peek() const; - -private: - BinaryStreamRef Stream; - uint32_t Offset; -}; -} // namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_BINARYSTREAMREADER_H Index: llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStreamRef.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStreamRef.h +++ llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStreamRef.h @@ -1,174 +0,0 @@ -//===- BinaryStreamRef.h - A copyable reference to a stream -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_MSF_BINARYSTREAMREF_H -#define LLVM_DEBUGINFO_MSF_BINARYSTREAMREF_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/BinaryStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamError.h" -#include "llvm/Support/Error.h" -#include -#include - -namespace llvm { - -/// Common stuff for mutable and immutable StreamRefs. -template class BinaryStreamRefBase { -public: - BinaryStreamRefBase() : Stream(nullptr), ViewOffset(0), Length(0) {} - BinaryStreamRefBase(StreamType &Stream, uint32_t Offset, uint32_t Length) - : Stream(&Stream), ViewOffset(Offset), Length(Length) {} - - llvm::support::endianness getEndian() const { return Stream->getEndian(); } - - uint32_t getLength() const { return Length; } - const StreamType *getStream() const { return Stream; } - - /// Return a new BinaryStreamRef with the first \p N elements removed. - RefType drop_front(uint32_t N) const { - if (!Stream) - return RefType(); - - N = std::min(N, Length); - return RefType(*Stream, ViewOffset + N, Length - N); - } - - /// Return a new BinaryStreamRef with only the first \p N elements remaining. - RefType keep_front(uint32_t N) const { - if (!Stream) - return RefType(); - N = std::min(N, Length); - return RefType(*Stream, ViewOffset, N); - } - - /// Return a new BinaryStreamRef with the first \p Offset elements removed, - /// and retaining exactly \p Len elements. - RefType slice(uint32_t Offset, uint32_t Len) const { - return drop_front(Offset).keep_front(Len); - } - - bool operator==(const RefType &Other) const { - if (Stream != Other.Stream) - return false; - if (ViewOffset != Other.ViewOffset) - return false; - if (Length != Other.Length) - return false; - return true; - } - -protected: - Error checkOffset(uint32_t Offset, uint32_t DataSize) const { - if (Offset > getLength()) - return make_error(stream_error_code::invalid_offset); - if (getLength() < DataSize + Offset) - return make_error(stream_error_code::stream_too_short); - return Error::success(); - } - - StreamType *Stream; - uint32_t ViewOffset; - uint32_t Length; -}; - -/// \brief BinaryStreamRef is to BinaryStream what ArrayRef is to an Array. It -/// provides copy-semantics and read only access to a "window" of the underlying -/// BinaryStream. Note that BinaryStreamRef is *not* a BinaryStream. That is to -/// say, it does not inherit and override the methods of BinaryStream. In -/// general, you should not pass around pointers or references to BinaryStreams -/// and use inheritance to achieve polymorphism. Instead, you should pass -/// around BinaryStreamRefs by value and achieve polymorphism that way. -class BinaryStreamRef - : public BinaryStreamRefBase { -public: - BinaryStreamRef() = default; - BinaryStreamRef(BinaryStream &Stream) - : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {} - BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, uint32_t Length) - : BinaryStreamRefBase(Stream, Offset, Length) {} - - // Use BinaryStreamRef.slice() instead. - BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset, - uint32_t Length) = delete; - - /// Given an Offset into this StreamRef and a Size, return a reference to a - /// buffer owned by the stream. - /// - /// \returns a success error code if the entire range of data is within the - /// bounds of this BinaryStreamRef's view and the implementation could read - /// the data, and an appropriate error code otherwise. - Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const { - if (auto EC = checkOffset(Offset, Size)) - return EC; - - return Stream->readBytes(ViewOffset + Offset, Size, Buffer); - } - - /// Given an Offset into this BinaryStreamRef, return a reference to the - /// largest buffer the stream could support without necessitating a copy. - /// - /// \returns a success error code if implementation could read the data, - /// and an appropriate error code otherwise. - Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) const { - if (auto EC = checkOffset(Offset, 1)) - return EC; - - if (auto EC = - Stream->readLongestContiguousChunk(ViewOffset + Offset, Buffer)) - return EC; - // This StreamRef might refer to a smaller window over a larger stream. In - // that case we will have read out more bytes than we should return, because - // we should not read past the end of the current view. - uint32_t MaxLength = Length - Offset; - if (Buffer.size() > MaxLength) - Buffer = Buffer.slice(0, MaxLength); - return Error::success(); - } -}; - -class WritableBinaryStreamRef - : public BinaryStreamRefBase { -public: - WritableBinaryStreamRef() = default; - WritableBinaryStreamRef(WritableBinaryStream &Stream) - : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {} - WritableBinaryStreamRef(WritableBinaryStream &Stream, uint32_t Offset, - uint32_t Length) - : BinaryStreamRefBase(Stream, Offset, Length) {} - - // Use WritableBinaryStreamRef.slice() instead. - WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint32_t Offset, - uint32_t Length) = delete; - - /// Given an Offset into this WritableBinaryStreamRef and some input data, - /// writes the data to the underlying stream. - /// - /// \returns a success error code if the data could fit within the underlying - /// stream at the specified location and the implementation could write the - /// data, and an appropriate error code otherwise. - Error writeBytes(uint32_t Offset, ArrayRef Data) const { - if (auto EC = checkOffset(Offset, Data.size())) - return EC; - - return Stream->writeBytes(ViewOffset + Offset, Data); - } - - operator BinaryStreamRef() { return BinaryStreamRef(*Stream); } - - /// \brief For buffered streams, commits changes to the backing store. - Error commit() { return Stream->commit(); } -}; - -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_BINARYSTREAMREF_H Index: llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStreamWriter.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStreamWriter.h +++ llvm/trunk/include/llvm/DebugInfo/MSF/BinaryStreamWriter.h @@ -1,165 +0,0 @@ -//===- BinaryStreamWriter.h - Writes objects to a BinaryStream ---*- C++-*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_MSF_BINARYSTREAMWRITER_H -#define LLVM_DEBUGINFO_MSF_BINARYSTREAMWRITER_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" -#include "llvm/DebugInfo/MSF/BinaryStreamError.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include -#include - -namespace llvm { - -/// \brief Provides write only access to a subclass of `WritableBinaryStream`. -/// Provides bounds checking and helpers for writing certain common data types -/// such as null-terminated strings, integers in various flavors of endianness, -/// etc. Can be subclassed to provide reading and writing of custom datatypes, -/// although no methods are overridable. -class BinaryStreamWriter { -public: - BinaryStreamWriter() = default; - explicit BinaryStreamWriter(WritableBinaryStreamRef Stream); - virtual ~BinaryStreamWriter() {} - - /// Write the bytes specified in \p Buffer to the underlying stream. - /// On success, updates the offset so that subsequent writes will occur - /// at the next unwritten position. - /// - /// \returns a success error code if the data was successfully written, - /// otherwise returns an appropriate error code. - Error writeBytes(ArrayRef Buffer); - - /// Write the the integer \p Value to the underlying stream in the - /// specified endianness. On success, updates the offset so that - /// subsequent writes occur at the next unwritten position. - /// - /// \returns a success error code if the data was successfully written, - /// otherwise returns an appropriate error code. - template Error writeInteger(T Value) { - static_assert(std::is_integral::value, - "Cannot call writeInteger with non-integral value!"); - uint8_t Buffer[sizeof(T)]; - llvm::support::endian::write( - Buffer, Value, Stream.getEndian()); - return writeBytes(Buffer); - } - - /// Similar to writeInteger - template Error writeEnum(T Num) { - static_assert(std::is_enum::value, - "Cannot call writeEnum with non-Enum type"); - - using U = typename std::underlying_type::type; - return writeInteger(static_cast(Num)); - } - - /// Write the the string \p Str to the underlying stream followed by a null - /// terminator. On success, updates the offset so that subsequent writes - /// occur at the next unwritten position. \p Str need not be null terminated - /// on input. - /// - /// \returns a success error code if the data was successfully written, - /// otherwise returns an appropriate error code. - Error writeCString(StringRef Str); - - /// Write the the string \p Str to the underlying stream without a null - /// terminator. On success, updates the offset so that subsequent writes - /// occur at the next unwritten position. - /// - /// \returns a success error code if the data was successfully written, - /// otherwise returns an appropriate error code. - Error writeFixedString(StringRef Str); - - /// Efficiently reads all data from \p Ref, and writes it to this stream. - /// This operation will not invoke any copies of the source data, regardless - /// of the source stream's implementation. - /// - /// \returns a success error code if the data was successfully written, - /// otherwise returns an appropriate error code. - Error writeStreamRef(BinaryStreamRef Ref); - - /// Efficiently reads \p Size bytes from \p Ref, and writes it to this stream. - /// This operation will not invoke any copies of the source data, regardless - /// of the source stream's implementation. - /// - /// \returns a success error code if the data was successfully written, - /// otherwise returns an appropriate error code. - Error writeStreamRef(BinaryStreamRef Ref, uint32_t Size); - - /// Writes the object \p Obj to the underlying stream, as if by using memcpy. - /// It is up to the caller to ensure that type of \p Obj can be safely copied - /// in this fashion, as no checks are made to ensure that this is safe. - /// - /// \returns a success error code if the data was successfully written, - /// otherwise returns an appropriate error code. - template Error writeObject(const T &Obj) { - static_assert(!std::is_pointer::value, - "writeObject should not be used with pointers, to write " - "the pointed-to value dereference the pointer before calling " - "writeObject"); - return writeBytes( - ArrayRef(reinterpret_cast(&Obj), sizeof(T))); - } - - /// Writes an array of objects of type T to the underlying stream, as if by - /// using memcpy. It is up to the caller to ensure that type of \p Obj can - /// be safely copied in this fashion, as no checks are made to ensure that - /// this is safe. - /// - /// \returns a success error code if the data was successfully written, - /// otherwise returns an appropriate error code. - template Error writeArray(ArrayRef Array) { - if (Array.empty()) - return Error::success(); - if (Array.size() > UINT32_MAX / sizeof(T)) - return make_error( - stream_error_code::invalid_array_size); - - return writeBytes( - ArrayRef(reinterpret_cast(Array.data()), - Array.size() * sizeof(T))); - } - - /// Writes all data from the array \p Array to the underlying stream. - /// - /// \returns a success error code if the data was successfully written, - /// otherwise returns an appropriate error code. - template - Error writeArray(VarStreamArray Array) { - return writeStreamRef(Array.getUnderlyingStream()); - } - - /// Writes all elements from the array \p Array to the underlying stream. - /// - /// \returns a success error code if the data was successfully written, - /// otherwise returns an appropriate error code. - template Error writeArray(FixedStreamArray Array) { - return writeStreamRef(Array.getUnderlyingStream()); - } - - void setOffset(uint32_t Off) { Offset = Off; } - uint32_t getOffset() const { return Offset; } - uint32_t getLength() const { return Stream.getLength(); } - uint32_t bytesRemaining() const { return getLength() - getOffset(); } - -protected: - WritableBinaryStreamRef Stream; - uint32_t Offset = 0; -}; - -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_BINARYSTREAMWRITER_H Index: llvm/trunk/include/llvm/DebugInfo/MSF/MappedBlockStream.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/MSF/MappedBlockStream.h +++ llvm/trunk/include/llvm/DebugInfo/MSF/MappedBlockStream.h @@ -14,11 +14,11 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/MSF/BinaryStream.h" -#include "llvm/DebugInfo/MSF/BinaryStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" #include "llvm/DebugInfo/MSF/MSFStreamLayout.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/DbiStream.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/DbiStream.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/DbiStream.h @@ -11,16 +11,16 @@ #define LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/ModInfo.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/DebugInfo/PDB/Native/StringTable.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h @@ -14,11 +14,11 @@ #include "llvm/ADT/StringSet.h" #include "llvm/Support/Error.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" namespace llvm { Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/GlobalsStream.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/GlobalsStream.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/GlobalsStream.h @@ -10,11 +10,11 @@ #ifndef LLVM_DEBUGINFO_PDB_RAW_GLOBALS_STREAM_H #define LLVM_DEBUGINFO_PDB_RAW_GLOBALS_STREAM_H -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Error.h" namespace llvm { Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/HashTable.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/HashTable.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/HashTable.h @@ -14,9 +14,9 @@ #include "llvm/ADT/SparseBitVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/MathExtras.h" Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/ModInfo.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/ModInfo.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/ModInfo.h @@ -11,9 +11,9 @@ #define LLVM_DEBUGINFO_PDB_RAW_MODINFO_H #include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Error.h" #include #include Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/ModStream.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/ModStream.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/ModStream.h @@ -14,9 +14,9 @@ #include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Error.h" namespace llvm { Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/PDBFile.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/PDBFile.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/PDBFile.h @@ -11,10 +11,10 @@ #define LLVM_DEBUGINFO_PDB_RAW_PDBFILE_H #include "llvm/ADT/DenseMap.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" #include "llvm/DebugInfo/MSF/IMSFFile.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/MathExtras.h" Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/PublicsStream.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/PublicsStream.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/PublicsStream.h @@ -11,11 +11,11 @@ #define LLVM_DEBUGINFO_PDB_RAW_PUBLICSSTREAM_H #include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Error.h" namespace llvm { Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/StringTable.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/StringTable.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/StringTable.h @@ -12,8 +12,8 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiHashing.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiHashing.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiHashing.h @@ -15,8 +15,8 @@ #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStream.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStream.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStream.h @@ -11,11 +11,11 @@ #define LLVM_DEBUGINFO_PDB_RAW_PDBTPISTREAM_H #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" #include "llvm/DebugInfo/PDB/Native/HashTable.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Error.h" Index: llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h +++ llvm/trunk/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h @@ -12,11 +12,11 @@ #include "llvm/ADT/Optional.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" -#include "llvm/DebugInfo/MSF/BinaryItemStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryItemStream.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Error.h" #include Index: llvm/trunk/include/llvm/Support/BinaryByteStream.h =================================================================== --- llvm/trunk/include/llvm/Support/BinaryByteStream.h +++ llvm/trunk/include/llvm/Support/BinaryByteStream.h @@ -0,0 +1,192 @@ +//===- BinaryByteStream.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===// +// A BinaryStream which stores data in a single continguous memory buffer. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BINARYBYTESTREAM_H +#define LLVM_SUPPORT_BINARYBYTESTREAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/MemoryBuffer.h" +#include +#include +#include +#include + +namespace llvm { + +/// \brief An implementation of BinaryStream which holds its entire data set +/// in a single contiguous buffer. BinaryByteStream guarantees that no read +/// operation will ever incur a copy. Note that BinaryByteStream does not +/// own the underlying buffer. +class BinaryByteStream : public BinaryStream { +public: + BinaryByteStream() = default; + BinaryByteStream(ArrayRef Data, llvm::support::endianness Endian) + : Endian(Endian), Data(Data) {} + BinaryByteStream(StringRef Data, llvm::support::endianness Endian) + : Endian(Endian), Data(Data.bytes_begin(), Data.bytes_end()) {} + + llvm::support::endianness getEndian() const override { return Endian; } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) override { + if (auto EC = checkOffset(Offset, Size)) + return EC; + Buffer = Data.slice(Offset, Size); + return Error::success(); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) override { + if (auto EC = checkOffset(Offset, 1)) + return EC; + Buffer = Data.slice(Offset); + return Error::success(); + } + + uint32_t getLength() override { return Data.size(); } + + ArrayRef data() const { return Data; } + + StringRef str() const { + const char *CharData = reinterpret_cast(Data.data()); + return StringRef(CharData, Data.size()); + } + +protected: + llvm::support::endianness Endian; + ArrayRef Data; +}; + +/// \brief An implementation of BinaryStream whose data is backed by an llvm +/// MemoryBuffer object. MemoryBufferByteStream owns the MemoryBuffer in +/// question. As with BinaryByteStream, reading from a MemoryBufferByteStream +/// will never cause a copy. +class MemoryBufferByteStream : public BinaryByteStream { +public: + MemoryBufferByteStream(std::unique_ptr Buffer, + llvm::support::endianness Endian) + : BinaryByteStream(Buffer->getBuffer(), Endian), + MemBuffer(std::move(Buffer)) {} + + std::unique_ptr MemBuffer; +}; + +/// \brief An implementation of BinaryStream which holds its entire data set +/// in a single contiguous buffer. As with BinaryByteStream, the mutable +/// version also guarantees that no read operation will ever incur a copy, +/// and similarly it does not own the underlying buffer. +class MutableBinaryByteStream : public WritableBinaryStream { +public: + MutableBinaryByteStream() = default; + MutableBinaryByteStream(MutableArrayRef Data, + llvm::support::endianness Endian) + : Data(Data), ImmutableStream(Data, Endian) {} + + llvm::support::endianness getEndian() const override { + return ImmutableStream.getEndian(); + } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) override { + return ImmutableStream.readBytes(Offset, Size, Buffer); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) override { + return ImmutableStream.readLongestContiguousChunk(Offset, Buffer); + } + + uint32_t getLength() override { return ImmutableStream.getLength(); } + + Error writeBytes(uint32_t Offset, ArrayRef Buffer) override { + if (Buffer.empty()) + return Error::success(); + + if (auto EC = checkOffset(Offset, Buffer.size())) + return EC; + + uint8_t *DataPtr = const_cast(Data.data()); + ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size()); + return Error::success(); + } + + Error commit() override { return Error::success(); } + + MutableArrayRef data() const { return Data; } + +private: + MutableArrayRef Data; + BinaryByteStream ImmutableStream; +}; + +/// \brief An implementation of WritableBinaryStream backed by an llvm +/// FileOutputBuffer. +class FileBufferByteStream : public WritableBinaryStream { +private: + class StreamImpl : public MutableBinaryByteStream { + public: + StreamImpl(std::unique_ptr Buffer, + llvm::support::endianness Endian) + : MutableBinaryByteStream( + MutableArrayRef(Buffer->getBufferStart(), + Buffer->getBufferEnd()), + Endian), + FileBuffer(std::move(Buffer)) {} + + Error commit() override { + if (FileBuffer->commit()) + return make_error( + stream_error_code::filesystem_error); + return Error::success(); + } + + private: + std::unique_ptr FileBuffer; + }; + +public: + FileBufferByteStream(std::unique_ptr Buffer, + llvm::support::endianness Endian) + : Impl(std::move(Buffer), Endian) {} + + llvm::support::endianness getEndian() const override { + return Impl.getEndian(); + } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) override { + return Impl.readBytes(Offset, Size, Buffer); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) override { + return Impl.readLongestContiguousChunk(Offset, Buffer); + } + + uint32_t getLength() override { return Impl.getLength(); } + + Error writeBytes(uint32_t Offset, ArrayRef Data) override { + return Impl.writeBytes(Offset, Data); + } + + Error commit() override { return Impl.commit(); } + +private: + StreamImpl Impl; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_BYTESTREAM_H Index: llvm/trunk/include/llvm/Support/BinaryItemStream.h =================================================================== --- llvm/trunk/include/llvm/Support/BinaryItemStream.h +++ llvm/trunk/include/llvm/Support/BinaryItemStream.h @@ -0,0 +1,95 @@ +//===- BinaryItemStream.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BINARYITEMSTREAM_H +#define LLVM_SUPPORT_BINARYITEMSTREAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/Error.h" +#include +#include + +namespace llvm { + +template struct BinaryItemTraits { + static size_t length(const T &Item) = delete; + static ArrayRef bytes(const T &Item) = delete; +}; + +/// BinaryItemStream represents a sequence of objects stored in some kind of +/// external container but for which it is useful to view as a stream of +/// contiguous bytes. An example of this might be if you have a collection of +/// records and you serialize each one into a buffer, and store these serialized +/// records in a container. The pointers themselves are not laid out +/// contiguously in memory, but we may wish to read from or write to these +/// records as if they were. +template > +class BinaryItemStream : public BinaryStream { +public: + explicit BinaryItemStream(llvm::support::endianness Endian) + : Endian(Endian) {} + + llvm::support::endianness getEndian() const override { return Endian; } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) override { + auto ExpectedIndex = translateOffsetIndex(Offset); + if (!ExpectedIndex) + return ExpectedIndex.takeError(); + const auto &Item = Items[*ExpectedIndex]; + if (auto EC = checkOffset(Offset, Size)) + return EC; + if (Size > Traits::length(Item)) + return make_error(stream_error_code::stream_too_short); + Buffer = Traits::bytes(Item).take_front(Size); + return Error::success(); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) override { + auto ExpectedIndex = translateOffsetIndex(Offset); + if (!ExpectedIndex) + return ExpectedIndex.takeError(); + Buffer = Traits::bytes(Items[*ExpectedIndex]); + return Error::success(); + } + + void setItems(ArrayRef ItemArray) { Items = ItemArray; } + + uint32_t getLength() override { + uint32_t Size = 0; + for (const auto &Item : Items) + Size += Traits::length(Item); + return Size; + } + +private: + Expected translateOffsetIndex(uint32_t Offset) const { + uint32_t CurrentOffset = 0; + uint32_t CurrentIndex = 0; + for (const auto &Item : Items) { + if (CurrentOffset >= Offset) + break; + CurrentOffset += Traits::length(Item); + ++CurrentIndex; + } + if (CurrentOffset != Offset) + return make_error(stream_error_code::stream_too_short); + return CurrentIndex; + } + + llvm::support::endianness Endian; + ArrayRef Items; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_BINARYITEMSTREAM_H Index: llvm/trunk/include/llvm/Support/BinaryStream.h =================================================================== --- llvm/trunk/include/llvm/Support/BinaryStream.h +++ llvm/trunk/include/llvm/Support/BinaryStream.h @@ -0,0 +1,78 @@ +//===- BinaryStream.h - Base interface for a stream of data -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BINARYSTREAM_H +#define LLVM_SUPPORT_BINARYSTREAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include + +namespace llvm { + +/// \brief An interface for accessing data in a stream-like format, but which +/// discourages copying. Instead of specifying a buffer in which to copy +/// data on a read, the API returns an ArrayRef to data owned by the stream's +/// implementation. Since implementations may not necessarily store data in a +/// single contiguous buffer (or even in memory at all), in such cases a it may +/// be necessary for an implementation to cache such a buffer so that it can +/// return it. +class BinaryStream { +public: + virtual ~BinaryStream() = default; + + virtual llvm::support::endianness getEndian() const = 0; + + /// \brief Given an offset into the stream and a number of bytes, attempt to + /// read the bytes and set the output ArrayRef to point to data owned by the + /// stream. + virtual Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) = 0; + + /// \brief Given an offset into the stream, read as much as possible without + /// copying any data. + virtual Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) = 0; + + /// \brief Return the number of bytes of data in this stream. + virtual uint32_t getLength() = 0; + +protected: + Error checkOffset(uint32_t Offset, uint32_t DataSize) { + if (Offset > getLength()) + return make_error(stream_error_code::invalid_offset); + if (getLength() < DataSize + Offset) + return make_error(stream_error_code::stream_too_short); + return Error::success(); + } +}; + +/// \brief A BinaryStream which can be read from as well as written to. Note +/// that writing to a BinaryStream always necessitates copying from the input +/// buffer to the stream's backing store. Streams are assumed to be buffered +/// so that to be portable it is necessary to call commit() on the stream when +/// all data has been written. +class WritableBinaryStream : public BinaryStream { +public: + ~WritableBinaryStream() override = default; + + /// \brief Attempt to write the given bytes into the stream at the desired + /// offset. This will always necessitate a copy. Cannot shrink or grow the + /// stream, only writes into existing allocated space. + virtual Error writeBytes(uint32_t Offset, ArrayRef Data) = 0; + + /// \brief For buffered streams, commits changes to the backing store. + virtual Error commit() = 0; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_BINARYSTREAM_H Index: llvm/trunk/include/llvm/Support/BinaryStreamArray.h =================================================================== --- llvm/trunk/include/llvm/Support/BinaryStreamArray.h +++ llvm/trunk/include/llvm/Support/BinaryStreamArray.h @@ -0,0 +1,320 @@ +//===- BinaryStreamArray.h - Array backed by an arbitrary stream *- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BINARYSTREAMARRAY_H +#define LLVM_SUPPORT_BINARYSTREAMARRAY_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/Error.h" +#include +#include + +/// Lightweight arrays that are backed by an arbitrary BinaryStream. This file +/// provides two different array implementations. +/// +/// VarStreamArray - Arrays of variable length records. The user specifies +/// an Extractor type that can extract a record from a given offset and +/// return the number of bytes consumed by the record. +/// +/// FixedStreamArray - Arrays of fixed length records. This is similar in +/// spirit to ArrayRef, but since it is backed by a BinaryStream, the +/// elements of the array need not be laid out in contiguous memory. +namespace llvm { + +/// VarStreamArrayExtractor is intended to be specialized to provide customized +/// extraction logic. On input it receives a BinaryStreamRef pointing to the +/// beginning of the next record, but where the length of the record is not yet +/// known. Upon completion, it should return an appropriate Error instance if +/// a record could not be extracted, or if one could be extracted it should +/// return success and set Len to the number of bytes this record occupied in +/// the underlying stream, and it should fill out the fields of the value type +/// Item appropriately to represent the current record. +/// +/// You can specialize this template for your own custom value types to avoid +/// having to specify a second template argument to VarStreamArray (documented +/// below). +template struct VarStreamArrayExtractor { + // Method intentionally deleted. You must provide an explicit specialization + // with the following method implemented. + Error operator()(BinaryStreamRef Stream, uint32_t &Len, + T &Item) const = 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 for your ValueType. +/// +/// By default an Extractor is default constructed in the class, but in some +/// cases you might find it useful for an Extractor to maintain state across +/// extractions. In this case you can provide your own Extractor through a +/// secondary constructor. The following examples show various ways of +/// creating a VarStreamArray. +/// +/// // Will use VarStreamArrayExtractor as the extractor. +/// VarStreamArray MyTypeArray; +/// +/// // Will use a default-constructed MyExtractor as the extractor. +/// VarStreamArray MyTypeArray2; +/// +/// // Will use the specific instance of MyExtractor provided. +/// // MyExtractor need not be default-constructible in this case. +/// MyExtractor E(SomeContext); +/// VarStreamArray MyTypeArray3(E); +/// +template class VarStreamArrayIterator; + +template > + +class VarStreamArray { + friend class VarStreamArrayIterator; + +public: + typedef VarStreamArrayIterator Iterator; + + VarStreamArray() = default; + explicit VarStreamArray(const Extractor &E) : E(E) {} + + explicit VarStreamArray(BinaryStreamRef Stream) : Stream(Stream) {} + VarStreamArray(BinaryStreamRef Stream, const Extractor &E) + : Stream(Stream), E(E) {} + + VarStreamArray(const VarStreamArray &Other) + : Stream(Other.Stream), E(Other.E) {} + + Iterator begin(bool *HadError = nullptr) const { + return Iterator(*this, E, HadError); + } + + Iterator end() const { return Iterator(E); } + + const Extractor &getExtractor() const { return E; } + + BinaryStreamRef getUnderlyingStream() const { return Stream; } + +private: + BinaryStreamRef Stream; + Extractor E; +}; + +template +class VarStreamArrayIterator + : public iterator_facade_base, + std::forward_iterator_tag, ValueType> { + typedef VarStreamArrayIterator IterType; + typedef VarStreamArray ArrayType; + +public: + VarStreamArrayIterator(const ArrayType &Array, const Extractor &E, + bool *HadError = nullptr) + : IterRef(Array.Stream), Array(&Array), HadError(HadError), Extract(E) { + if (IterRef.getLength() == 0) + moveToEnd(); + else { + auto EC = Extract(IterRef, ThisLen, ThisValue); + if (EC) { + consumeError(std::move(EC)); + markError(); + } + } + } + VarStreamArrayIterator() = default; + explicit VarStreamArrayIterator(const Extractor &E) : Extract(E) {} + ~VarStreamArrayIterator() = default; + + bool operator==(const IterType &R) const { + if (Array && R.Array) { + // Both have a valid array, make sure they're same. + assert(Array == R.Array); + return IterRef == R.IterRef; + } + + // Both iterators are at the end. + if (!Array && !R.Array) + return true; + + // One is not at the end and one is. + return false; + } + + const ValueType &operator*() const { + assert(Array && !HasError); + return ThisValue; + } + + IterType &operator+=(unsigned N) { + for (unsigned I = 0; I < N; ++I) { + // We are done with the current record, discard it so that we are + // positioned at the next record. + IterRef = IterRef.drop_front(ThisLen); + if (IterRef.getLength() == 0) { + // There is nothing after the current record, we must make this an end + // iterator. + moveToEnd(); + } else { + // There is some data after the current record. + auto EC = Extract(IterRef, ThisLen, ThisValue); + if (EC) { + consumeError(std::move(EC)); + markError(); + } else if (ThisLen == 0) { + // An empty record? Make this an end iterator. + moveToEnd(); + } + } + } + return *this; + } + +private: + void moveToEnd() { + Array = nullptr; + ThisLen = 0; + } + void markError() { + moveToEnd(); + HasError = true; + if (HadError != nullptr) + *HadError = true; + } + + ValueType ThisValue; + BinaryStreamRef IterRef; + const ArrayType *Array{nullptr}; + uint32_t ThisLen{0}; + bool HasError{false}; + bool *HadError{nullptr}; + Extractor Extract; +}; + +template class FixedStreamArrayIterator; + +/// FixedStreamArray is similar to VarStreamArray, except with each record +/// having a fixed-length. As with VarStreamArray, there is no upfront +/// cost associated with building or copying a FixedStreamArray, as the +/// memory for each element is not read from the backing stream until that +/// element is iterated. +template class FixedStreamArray { + friend class FixedStreamArrayIterator; + +public: + FixedStreamArray() = default; + explicit FixedStreamArray(BinaryStreamRef Stream) : Stream(Stream) { + assert(Stream.getLength() % sizeof(T) == 0); + } + + bool operator==(const FixedStreamArray &Other) const { + return Stream == Other.Stream; + } + + bool operator!=(const FixedStreamArray &Other) const { + return !(*this == Other); + } + + FixedStreamArray &operator=(const FixedStreamArray &) = default; + + const T &operator[](uint32_t Index) const { + assert(Index < size()); + uint32_t Off = Index * sizeof(T); + ArrayRef Data; + if (auto EC = Stream.readBytes(Off, sizeof(T), Data)) { + assert(false && "Unexpected failure reading from stream"); + // This should never happen since we asserted that the stream length was + // an exact multiple of the element size. + consumeError(std::move(EC)); + } + assert(llvm::alignmentAdjustment(Data.data(), alignof(T)) == 0); + return *reinterpret_cast(Data.data()); + } + + uint32_t size() const { return Stream.getLength() / sizeof(T); } + + bool empty() const { return size() == 0; } + + FixedStreamArrayIterator begin() const { + return FixedStreamArrayIterator(*this, 0); + } + + FixedStreamArrayIterator end() const { + return FixedStreamArrayIterator(*this, size()); + } + + BinaryStreamRef getUnderlyingStream() const { return Stream; } + +private: + BinaryStreamRef Stream; +}; + +template +class FixedStreamArrayIterator + : public iterator_facade_base, + std::random_access_iterator_tag, T> { + +public: + FixedStreamArrayIterator(const FixedStreamArray &Array, uint32_t Index) + : Array(Array), Index(Index) {} + + FixedStreamArrayIterator & + operator=(const FixedStreamArrayIterator &Other) { + Array = Other.Array; + Index = Other.Index; + return *this; + } + + const T &operator*() const { return Array[Index]; } + + bool operator==(const FixedStreamArrayIterator &R) const { + assert(Array == R.Array); + return (Index == R.Index) && (Array == R.Array); + } + + FixedStreamArrayIterator &operator+=(std::ptrdiff_t N) { + Index += N; + return *this; + } + + FixedStreamArrayIterator &operator-=(std::ptrdiff_t N) { + assert(Index >= N); + Index -= N; + return *this; + } + + std::ptrdiff_t operator-(const FixedStreamArrayIterator &R) const { + assert(Array == R.Array); + assert(Index >= R.Index); + return Index - R.Index; + } + + bool operator<(const FixedStreamArrayIterator &RHS) const { + assert(Array == RHS.Array); + return Index < RHS.Index; + } + +private: + FixedStreamArray Array; + uint32_t Index; +}; + +} // namespace llvm + +#endif // LLVM_SUPPORT_BINARYSTREAMARRAY_H Index: llvm/trunk/include/llvm/Support/BinaryStreamError.h =================================================================== --- llvm/trunk/include/llvm/Support/BinaryStreamError.h +++ llvm/trunk/include/llvm/Support/BinaryStreamError.h @@ -0,0 +1,48 @@ +//===- BinaryStreamError.h - Error extensions for Binary Streams *- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BINARYSTREAMERROR_H +#define LLVM_SUPPORT_BINARYSTREAMERROR_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" + +#include + +namespace llvm { +enum class stream_error_code { + unspecified, + stream_too_short, + invalid_array_size, + invalid_offset, + filesystem_error +}; + +/// Base class for errors originating when parsing raw PDB files +class BinaryStreamError : public ErrorInfo { +public: + static char ID; + explicit BinaryStreamError(stream_error_code C); + explicit BinaryStreamError(StringRef Context); + BinaryStreamError(stream_error_code C, StringRef Context); + + void log(raw_ostream &OS) const override; + std::error_code convertToErrorCode() const override; + + StringRef getErrorMessage() const; + + stream_error_code getErrorCode() const { return Code; } + +private: + std::string ErrMsg; + stream_error_code Code; +}; +} // namespace llvm + +#endif // LLVM_SUPPORT_BINARYSTREAMERROR_H Index: llvm/trunk/include/llvm/Support/BinaryStreamReader.h =================================================================== --- llvm/trunk/include/llvm/Support/BinaryStreamReader.h +++ llvm/trunk/include/llvm/Support/BinaryStreamReader.h @@ -0,0 +1,234 @@ +//===- BinaryStreamReader.h - Reads objects from a binary stream *- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BINARYSTREAMREADER_H +#define LLVM_SUPPORT_BINARYSTREAMREADER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/type_traits.h" + +#include +#include + +namespace llvm { + +/// \brief Provides read only access to a subclass of `BinaryStream`. Provides +/// bounds checking and helpers for writing certain common data types such as +/// null-terminated strings, integers in various flavors of endianness, etc. +/// Can be subclassed to provide reading of custom datatypes, although no +/// are overridable. +class BinaryStreamReader { +public: + explicit BinaryStreamReader(BinaryStreamRef Stream); + virtual ~BinaryStreamReader() {} + + /// Read as much as possible from the underlying string at the current offset + /// without invoking a copy, and set \p Buffer to the resulting data slice. + /// Updates the stream's offset to point after the newly read data. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + Error readLongestContiguousChunk(ArrayRef &Buffer); + + /// Read \p Size bytes from the underlying stream at the current offset and + /// and set \p Buffer to the resulting data slice. Whether a copy occurs + /// depends on the implementation of the underlying stream. Updates the + /// stream's offset to point after the newly read data. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + Error readBytes(ArrayRef &Buffer, uint32_t Size); + + /// Read an integer of the specified endianness into \p Dest and update the + /// stream's offset. The data is always copied from the stream's underlying + /// buffer into \p Dest. Updates the stream's offset to point after the newly + /// read data. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + template Error readInteger(T &Dest) { + static_assert(std::is_integral::value, + "Cannot call readInteger with non-integral value!"); + + ArrayRef Bytes; + if (auto EC = readBytes(Bytes, sizeof(T))) + return EC; + + Dest = llvm::support::endian::read( + Bytes.data(), Stream.getEndian()); + return Error::success(); + } + + /// Similar to readInteger. + template Error readEnum(T &Dest) { + static_assert(std::is_enum::value, + "Cannot call readEnum with non-enum value!"); + typename std::underlying_type::type N; + if (auto EC = readInteger(N)) + return EC; + Dest = static_cast(N); + return Error::success(); + } + + /// Read a null terminated string from \p Dest. Whether a copy occurs depends + /// on the implementation of the underlying stream. Updates the stream's + /// offset to point after the newly read data. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + Error readCString(StringRef &Dest); + + /// Read a \p Length byte string into \p Dest. Whether a copy occurs depends + /// on the implementation of the underlying stream. Updates the stream's + /// offset to point after the newly read data. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + Error readFixedString(StringRef &Dest, uint32_t Length); + + /// Read the entire remainder of the underlying stream into \p Ref. This is + /// equivalent to calling getUnderlyingStream().slice(Offset). Updates the + /// stream's offset to point to the end of the stream. Never causes a copy. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + Error readStreamRef(BinaryStreamRef &Ref); + + /// Read \p Length bytes from the underlying stream into \p Ref. This is + /// equivalent to calling getUnderlyingStream().slice(Offset, Length). + /// Updates the stream's offset to point after the newly read object. Never + /// causes a copy. + /// + /// \returns a success error code if the data was successfully read, otherwise + /// returns an appropriate error code. + Error readStreamRef(BinaryStreamRef &Ref, uint32_t Length); + + /// Get a pointer to an object of type T from the underlying stream, as if by + /// memcpy, and store the result into \p Dest. It is up to the caller to + /// ensure that objects of type T can be safely treated in this manner. + /// Updates the stream's offset to point after the newly read object. Whether + /// a copy occurs depends 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 Error readObject(const T *&Dest) { + ArrayRef Buffer; + if (auto EC = readBytes(Buffer, sizeof(T))) + return EC; + Dest = reinterpret_cast(Buffer.data()); + return Error::success(); + } + + /// Get a reference to a \p NumElements element array of objects of type T + /// from the underlying stream as if by memcpy, and store the resulting array + /// slice into \p array. It is up to the caller to ensure that objects of + /// type T can be safely treated in this manner. Updates the stream's offset + /// to point after the newly read object. Whether a copy occurs depends 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 + Error readArray(ArrayRef &Array, uint32_t NumElements) { + ArrayRef Bytes; + if (NumElements == 0) { + Array = ArrayRef(); + return Error::success(); + } + + if (NumElements > UINT32_MAX / sizeof(T)) + return make_error( + stream_error_code::invalid_array_size); + + if (auto EC = readBytes(Bytes, NumElements * sizeof(T))) + return EC; + + assert(alignmentAdjustment(Bytes.data(), alignof(T)) == 0 && + "Reading at invalid alignment!"); + + Array = ArrayRef(reinterpret_cast(Bytes.data()), NumElements); + 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 + Error readArray(VarStreamArray &Array, uint32_t Size) { + BinaryStreamRef S; + if (auto EC = readStreamRef(S, Size)) + return EC; + Array = VarStreamArray(S, Array.getExtractor()); + return Error::success(); + } + + /// Read a FixedStreamArray of \p NumItems elements 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 + /// FixedStreamArray 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 + Error readArray(FixedStreamArray &Array, uint32_t NumItems) { + if (NumItems == 0) { + Array = FixedStreamArray(); + return Error::success(); + } + + if (NumItems > UINT32_MAX / sizeof(T)) + return make_error( + stream_error_code::invalid_array_size); + + BinaryStreamRef View; + if (auto EC = readStreamRef(View, NumItems * sizeof(T))) + return EC; + + Array = FixedStreamArray(View); + return Error::success(); + } + + bool empty() const { return bytesRemaining() == 0; } + void setOffset(uint32_t Off) { Offset = Off; } + uint32_t getOffset() const { return Offset; } + uint32_t getLength() const { return Stream.getLength(); } + uint32_t bytesRemaining() const { return getLength() - getOffset(); } + + /// Advance the stream's offset by \p Amount bytes. + /// + /// \returns a success error code if at least \p Amount bytes remain in the + /// stream, otherwise returns an appropriate error code. + Error skip(uint32_t Amount); + + /// Examine the next byte of the underlying stream without advancing the + /// stream's offset. If the stream is empty the behavior is undefined. + /// + /// \returns the next byte in the stream. + uint8_t peek() const; + +private: + BinaryStreamRef Stream; + uint32_t Offset; +}; +} // namespace llvm + +#endif // LLVM_SUPPORT_BINARYSTREAMREADER_H Index: llvm/trunk/include/llvm/Support/BinaryStreamRef.h =================================================================== --- llvm/trunk/include/llvm/Support/BinaryStreamRef.h +++ llvm/trunk/include/llvm/Support/BinaryStreamRef.h @@ -0,0 +1,174 @@ +//===- BinaryStreamRef.h - A copyable reference to a stream -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BINARYSTREAMREF_H +#define LLVM_SUPPORT_BINARYSTREAMREF_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/Error.h" +#include +#include + +namespace llvm { + +/// Common stuff for mutable and immutable StreamRefs. +template class BinaryStreamRefBase { +public: + BinaryStreamRefBase() : Stream(nullptr), ViewOffset(0), Length(0) {} + BinaryStreamRefBase(StreamType &Stream, uint32_t Offset, uint32_t Length) + : Stream(&Stream), ViewOffset(Offset), Length(Length) {} + + llvm::support::endianness getEndian() const { return Stream->getEndian(); } + + uint32_t getLength() const { return Length; } + const StreamType *getStream() const { return Stream; } + + /// Return a new BinaryStreamRef with the first \p N elements removed. + RefType drop_front(uint32_t N) const { + if (!Stream) + return RefType(); + + N = std::min(N, Length); + return RefType(*Stream, ViewOffset + N, Length - N); + } + + /// Return a new BinaryStreamRef with only the first \p N elements remaining. + RefType keep_front(uint32_t N) const { + if (!Stream) + return RefType(); + N = std::min(N, Length); + return RefType(*Stream, ViewOffset, N); + } + + /// Return a new BinaryStreamRef with the first \p Offset elements removed, + /// and retaining exactly \p Len elements. + RefType slice(uint32_t Offset, uint32_t Len) const { + return drop_front(Offset).keep_front(Len); + } + + bool operator==(const RefType &Other) const { + if (Stream != Other.Stream) + return false; + if (ViewOffset != Other.ViewOffset) + return false; + if (Length != Other.Length) + return false; + return true; + } + +protected: + Error checkOffset(uint32_t Offset, uint32_t DataSize) const { + if (Offset > getLength()) + return make_error(stream_error_code::invalid_offset); + if (getLength() < DataSize + Offset) + return make_error(stream_error_code::stream_too_short); + return Error::success(); + } + + StreamType *Stream; + uint32_t ViewOffset; + uint32_t Length; +}; + +/// \brief BinaryStreamRef is to BinaryStream what ArrayRef is to an Array. It +/// provides copy-semantics and read only access to a "window" of the underlying +/// BinaryStream. Note that BinaryStreamRef is *not* a BinaryStream. That is to +/// say, it does not inherit and override the methods of BinaryStream. In +/// general, you should not pass around pointers or references to BinaryStreams +/// and use inheritance to achieve polymorphism. Instead, you should pass +/// around BinaryStreamRefs by value and achieve polymorphism that way. +class BinaryStreamRef + : public BinaryStreamRefBase { +public: + BinaryStreamRef() = default; + BinaryStreamRef(BinaryStream &Stream) + : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {} + BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, uint32_t Length) + : BinaryStreamRefBase(Stream, Offset, Length) {} + + // Use BinaryStreamRef.slice() instead. + BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset, + uint32_t Length) = delete; + + /// Given an Offset into this StreamRef and a Size, return a reference to a + /// buffer owned by the stream. + /// + /// \returns a success error code if the entire range of data is within the + /// bounds of this BinaryStreamRef's view and the implementation could read + /// the data, and an appropriate error code otherwise. + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) const { + if (auto EC = checkOffset(Offset, Size)) + return EC; + + return Stream->readBytes(ViewOffset + Offset, Size, Buffer); + } + + /// Given an Offset into this BinaryStreamRef, return a reference to the + /// largest buffer the stream could support without necessitating a copy. + /// + /// \returns a success error code if implementation could read the data, + /// and an appropriate error code otherwise. + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) const { + if (auto EC = checkOffset(Offset, 1)) + return EC; + + if (auto EC = + Stream->readLongestContiguousChunk(ViewOffset + Offset, Buffer)) + return EC; + // This StreamRef might refer to a smaller window over a larger stream. In + // that case we will have read out more bytes than we should return, because + // we should not read past the end of the current view. + uint32_t MaxLength = Length - Offset; + if (Buffer.size() > MaxLength) + Buffer = Buffer.slice(0, MaxLength); + return Error::success(); + } +}; + +class WritableBinaryStreamRef + : public BinaryStreamRefBase { +public: + WritableBinaryStreamRef() = default; + WritableBinaryStreamRef(WritableBinaryStream &Stream) + : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {} + WritableBinaryStreamRef(WritableBinaryStream &Stream, uint32_t Offset, + uint32_t Length) + : BinaryStreamRefBase(Stream, Offset, Length) {} + + // Use WritableBinaryStreamRef.slice() instead. + WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint32_t Offset, + uint32_t Length) = delete; + + /// Given an Offset into this WritableBinaryStreamRef and some input data, + /// writes the data to the underlying stream. + /// + /// \returns a success error code if the data could fit within the underlying + /// stream at the specified location and the implementation could write the + /// data, and an appropriate error code otherwise. + Error writeBytes(uint32_t Offset, ArrayRef Data) const { + if (auto EC = checkOffset(Offset, Data.size())) + return EC; + + return Stream->writeBytes(ViewOffset + Offset, Data); + } + + operator BinaryStreamRef() { return BinaryStreamRef(*Stream); } + + /// \brief For buffered streams, commits changes to the backing store. + Error commit() { return Stream->commit(); } +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_BINARYSTREAMREF_H Index: llvm/trunk/include/llvm/Support/BinaryStreamWriter.h =================================================================== --- llvm/trunk/include/llvm/Support/BinaryStreamWriter.h +++ llvm/trunk/include/llvm/Support/BinaryStreamWriter.h @@ -0,0 +1,165 @@ +//===- BinaryStreamWriter.h - Writes objects to a BinaryStream ---*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BINARYSTREAMWRITER_H +#define LLVM_SUPPORT_BINARYSTREAMWRITER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include +#include + +namespace llvm { + +/// \brief Provides write only access to a subclass of `WritableBinaryStream`. +/// Provides bounds checking and helpers for writing certain common data types +/// such as null-terminated strings, integers in various flavors of endianness, +/// etc. Can be subclassed to provide reading and writing of custom datatypes, +/// although no methods are overridable. +class BinaryStreamWriter { +public: + BinaryStreamWriter() = default; + explicit BinaryStreamWriter(WritableBinaryStreamRef Stream); + virtual ~BinaryStreamWriter() {} + + /// Write the bytes specified in \p Buffer to the underlying stream. + /// On success, updates the offset so that subsequent writes will occur + /// at the next unwritten position. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + Error writeBytes(ArrayRef Buffer); + + /// Write the the integer \p Value to the underlying stream in the + /// specified endianness. On success, updates the offset so that + /// subsequent writes occur at the next unwritten position. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + template Error writeInteger(T Value) { + static_assert(std::is_integral::value, + "Cannot call writeInteger with non-integral value!"); + uint8_t Buffer[sizeof(T)]; + llvm::support::endian::write( + Buffer, Value, Stream.getEndian()); + return writeBytes(Buffer); + } + + /// Similar to writeInteger + template Error writeEnum(T Num) { + static_assert(std::is_enum::value, + "Cannot call writeEnum with non-Enum type"); + + using U = typename std::underlying_type::type; + return writeInteger(static_cast(Num)); + } + + /// Write the the string \p Str to the underlying stream followed by a null + /// terminator. On success, updates the offset so that subsequent writes + /// occur at the next unwritten position. \p Str need not be null terminated + /// on input. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + Error writeCString(StringRef Str); + + /// Write the the string \p Str to the underlying stream without a null + /// terminator. On success, updates the offset so that subsequent writes + /// occur at the next unwritten position. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + Error writeFixedString(StringRef Str); + + /// Efficiently reads all data from \p Ref, and writes it to this stream. + /// This operation will not invoke any copies of the source data, regardless + /// of the source stream's implementation. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + Error writeStreamRef(BinaryStreamRef Ref); + + /// Efficiently reads \p Size bytes from \p Ref, and writes it to this stream. + /// This operation will not invoke any copies of the source data, regardless + /// of the source stream's implementation. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + Error writeStreamRef(BinaryStreamRef Ref, uint32_t Size); + + /// Writes the object \p Obj to the underlying stream, as if by using memcpy. + /// It is up to the caller to ensure that type of \p Obj can be safely copied + /// in this fashion, as no checks are made to ensure that this is safe. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + template Error writeObject(const T &Obj) { + static_assert(!std::is_pointer::value, + "writeObject should not be used with pointers, to write " + "the pointed-to value dereference the pointer before calling " + "writeObject"); + return writeBytes( + ArrayRef(reinterpret_cast(&Obj), sizeof(T))); + } + + /// Writes an array of objects of type T to the underlying stream, as if by + /// using memcpy. It is up to the caller to ensure that type of \p Obj can + /// be safely copied in this fashion, as no checks are made to ensure that + /// this is safe. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + template Error writeArray(ArrayRef Array) { + if (Array.empty()) + return Error::success(); + if (Array.size() > UINT32_MAX / sizeof(T)) + return make_error( + stream_error_code::invalid_array_size); + + return writeBytes( + ArrayRef(reinterpret_cast(Array.data()), + Array.size() * sizeof(T))); + } + + /// Writes all data from the array \p Array to the underlying stream. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + template + Error writeArray(VarStreamArray Array) { + return writeStreamRef(Array.getUnderlyingStream()); + } + + /// Writes all elements from the array \p Array to the underlying stream. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + template Error writeArray(FixedStreamArray Array) { + return writeStreamRef(Array.getUnderlyingStream()); + } + + void setOffset(uint32_t Off) { Offset = Off; } + uint32_t getOffset() const { return Offset; } + uint32_t getLength() const { return Stream.getLength(); } + uint32_t bytesRemaining() const { return getLength() - getOffset(); } + +protected: + WritableBinaryStreamRef Stream; + uint32_t Offset = 0; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_BINARYSTREAMWRITER_H Index: llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -23,13 +23,13 @@ #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" #include "llvm/IR/Constants.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/COFF.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Target/TargetFrameLowering.h" Index: llvm/trunk/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp @@ -11,7 +11,7 @@ #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" +#include "llvm/Support/BinaryByteStream.h" using namespace llvm; using namespace llvm::codeview; Index: llvm/trunk/lib/DebugInfo/CodeView/CVTypeDumper.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/CVTypeDumper.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/CVTypeDumper.cpp @@ -14,7 +14,7 @@ #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" +#include "llvm/Support/BinaryByteStream.h" using namespace llvm; using namespace llvm::codeview; Index: llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -16,8 +16,8 @@ #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" #include "llvm/DebugInfo/CodeView/TypeServerHandler.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" using namespace llvm; using namespace llvm::codeview; Index: llvm/trunk/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp @@ -10,8 +10,8 @@ #include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" using namespace llvm; using namespace llvm::codeview; Index: llvm/trunk/lib/DebugInfo/CodeView/ModuleSubstream.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/ModuleSubstream.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/ModuleSubstream.cpp @@ -9,7 +9,7 @@ #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamReader.h" using namespace llvm; using namespace llvm::codeview; Index: llvm/trunk/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp @@ -8,8 +8,8 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" using namespace llvm; using namespace llvm::codeview; Index: llvm/trunk/lib/DebugInfo/CodeView/RecordSerialization.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/RecordSerialization.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/RecordSerialization.cpp @@ -16,7 +16,7 @@ #include "llvm/ADT/APSInt.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" +#include "llvm/Support/BinaryByteStream.h" using namespace llvm; using namespace llvm::codeview; Index: llvm/trunk/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp @@ -19,7 +19,7 @@ #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" +#include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/ScopedPrinter.h" Index: llvm/trunk/lib/DebugInfo/CodeView/TypeRecord.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/TypeRecord.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/TypeRecord.cpp @@ -10,8 +10,8 @@ #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" using namespace llvm; using namespace llvm::codeview; Index: llvm/trunk/lib/DebugInfo/CodeView/TypeSerializer.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/CodeView/TypeSerializer.cpp +++ llvm/trunk/lib/DebugInfo/CodeView/TypeSerializer.cpp @@ -9,7 +9,7 @@ #include "llvm/DebugInfo/CodeView/TypeSerializer.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" +#include "llvm/Support/BinaryStreamWriter.h" #include Index: llvm/trunk/lib/DebugInfo/MSF/BinaryStreamError.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/MSF/BinaryStreamError.cpp +++ llvm/trunk/lib/DebugInfo/MSF/BinaryStreamError.cpp @@ -1,56 +0,0 @@ -//===- BinaryStreamError.cpp - Error extensions for streams -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/MSF/BinaryStreamError.h" -#include "llvm/Support/ErrorHandling.h" - -using namespace llvm; - -char BinaryStreamError::ID = 0; - -BinaryStreamError::BinaryStreamError(stream_error_code C) - : BinaryStreamError(C, "") {} - -BinaryStreamError::BinaryStreamError(StringRef Context) - : BinaryStreamError(stream_error_code::unspecified, Context) {} - -BinaryStreamError::BinaryStreamError(stream_error_code C, StringRef Context) - : Code(C) { - ErrMsg = "Stream Error: "; - switch (C) { - case stream_error_code::unspecified: - ErrMsg += "An unspecified error has occurred."; - break; - case stream_error_code::stream_too_short: - ErrMsg += "The stream is too short to perform the requested operation."; - break; - case stream_error_code::invalid_array_size: - ErrMsg += "The buffer size is not a multiple of the array element size."; - break; - case stream_error_code::invalid_offset: - ErrMsg += "The specified offset is invalid for the current stream."; - break; - case stream_error_code::filesystem_error: - ErrMsg += "An I/O error occurred on the file system."; - break; - } - - if (!Context.empty()) { - ErrMsg += " "; - ErrMsg += Context; - } -} - -void BinaryStreamError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; } - -StringRef BinaryStreamError::getErrorMessage() const { return ErrMsg; } - -std::error_code BinaryStreamError::convertToErrorCode() const { - return inconvertibleErrorCode(); -} Index: llvm/trunk/lib/DebugInfo/MSF/BinaryStreamReader.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/MSF/BinaryStreamReader.cpp +++ llvm/trunk/lib/DebugInfo/MSF/BinaryStreamReader.cpp @@ -1,95 +0,0 @@ -//===- BinaryStreamReader.cpp - Reads objects from a binary stream --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" - -#include "llvm/DebugInfo/MSF/BinaryStreamError.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" - -using namespace llvm; - -BinaryStreamReader::BinaryStreamReader(BinaryStreamRef S) - : Stream(S), Offset(0) {} - -Error BinaryStreamReader::readLongestContiguousChunk( - ArrayRef &Buffer) { - if (auto EC = Stream.readLongestContiguousChunk(Offset, Buffer)) - return EC; - Offset += Buffer.size(); - return Error::success(); -} - -Error BinaryStreamReader::readBytes(ArrayRef &Buffer, uint32_t Size) { - if (auto EC = Stream.readBytes(Offset, Size, Buffer)) - return EC; - Offset += Size; - return Error::success(); -} - -Error BinaryStreamReader::readCString(StringRef &Dest) { - // TODO: This could be made more efficient by using readLongestContiguousChunk - // and searching for null terminators in the resulting buffer. - - uint32_t Length = 0; - // First compute the length of the string by reading 1 byte at a time. - uint32_t OriginalOffset = getOffset(); - const char *C; - while (true) { - if (auto EC = readObject(C)) - return EC; - if (*C == '\0') - break; - ++Length; - } - // Now go back and request a reference for that many bytes. - uint32_t NewOffset = getOffset(); - setOffset(OriginalOffset); - - if (auto EC = readFixedString(Dest, Length)) - return EC; - - // Now set the offset back to where it was after we calculated the length. - setOffset(NewOffset); - return Error::success(); -} - -Error BinaryStreamReader::readFixedString(StringRef &Dest, uint32_t Length) { - ArrayRef Bytes; - if (auto EC = readBytes(Bytes, Length)) - return EC; - Dest = StringRef(reinterpret_cast(Bytes.begin()), Bytes.size()); - return Error::success(); -} - -Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref) { - return readStreamRef(Ref, bytesRemaining()); -} - -Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref, uint32_t Length) { - if (bytesRemaining() < Length) - return make_error(stream_error_code::stream_too_short); - Ref = Stream.slice(Offset, Length); - Offset += Length; - return Error::success(); -} - -Error BinaryStreamReader::skip(uint32_t Amount) { - if (Amount > bytesRemaining()) - return make_error(stream_error_code::stream_too_short); - Offset += Amount; - return Error::success(); -} - -uint8_t BinaryStreamReader::peek() const { - ArrayRef Buffer; - auto EC = Stream.readBytes(Offset, 1, Buffer); - assert(!EC && "Cannot peek an empty buffer!"); - llvm::consumeError(std::move(EC)); - return Buffer[0]; -} Index: llvm/trunk/lib/DebugInfo/MSF/BinaryStreamWriter.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/MSF/BinaryStreamWriter.cpp +++ llvm/trunk/lib/DebugInfo/MSF/BinaryStreamWriter.cpp @@ -1,59 +0,0 @@ -//===- BinaryStreamWriter.cpp - Writes objects to a BinaryStream ----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" - -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" - -using namespace llvm; - -BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef S) - : Stream(S), Offset(0) {} - -Error BinaryStreamWriter::writeBytes(ArrayRef Buffer) { - if (auto EC = Stream.writeBytes(Offset, Buffer)) - return EC; - Offset += Buffer.size(); - return Error::success(); -} - -Error BinaryStreamWriter::writeCString(StringRef Str) { - if (auto EC = writeFixedString(Str)) - return EC; - if (auto EC = writeObject('\0')) - return EC; - - return Error::success(); -} - -Error BinaryStreamWriter::writeFixedString(StringRef Str) { - return writeBytes(ArrayRef(Str.bytes_begin(), Str.bytes_end())); -} - -Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) { - return writeStreamRef(Ref, Ref.getLength()); -} - -Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint32_t Length) { - BinaryStreamReader SrcReader(Ref.slice(0, Length)); - // This is a bit tricky. If we just call readBytes, we are requiring that it - // return us the entire stream as a contiguous buffer. There is no guarantee - // this can be satisfied by returning a reference straight from the buffer, as - // an implementation may not store all data in a single contiguous buffer. So - // we iterate over each contiguous chunk, writing each one in succession. - while (SrcReader.bytesRemaining() > 0) { - ArrayRef Chunk; - if (auto EC = SrcReader.readLongestContiguousChunk(Chunk)) - return EC; - if (auto EC = writeBytes(Chunk)) - return EC; - } - return Error::success(); -} Index: llvm/trunk/lib/DebugInfo/MSF/CMakeLists.txt =================================================================== --- llvm/trunk/lib/DebugInfo/MSF/CMakeLists.txt +++ llvm/trunk/lib/DebugInfo/MSF/CMakeLists.txt @@ -1,7 +1,4 @@ add_llvm_library(LLVMDebugInfoMSF - BinaryStreamError.cpp - BinaryStreamReader.cpp - BinaryStreamWriter.cpp MappedBlockStream.cpp MSFBuilder.cpp MSFCommon.cpp Index: llvm/trunk/lib/DebugInfo/MSF/MappedBlockStream.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/MSF/MappedBlockStream.cpp +++ llvm/trunk/lib/DebugInfo/MSF/MappedBlockStream.cpp @@ -9,10 +9,10 @@ #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamError.h" #include "llvm/DebugInfo/MSF/IMSFFile.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/DebugInfo/MSF/MSFStreamLayout.h" +#include "llvm/Support/BinaryStreamError.h" using namespace llvm; using namespace llvm::msf; Index: llvm/trunk/lib/DebugInfo/PDB/Native/DbiStream.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/DbiStream.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/DbiStream.cpp @@ -9,8 +9,6 @@ #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" @@ -21,6 +19,8 @@ #include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" #include #include Index: llvm/trunk/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -10,12 +10,12 @@ #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/COFF.h" using namespace llvm; Index: llvm/trunk/lib/DebugInfo/PDB/Native/GSI.h =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/GSI.h +++ llvm/trunk/lib/DebugInfo/PDB/Native/GSI.h @@ -25,8 +25,8 @@ #ifndef LLVM_LIB_DEBUGINFO_PDB_RAW_GSI_H #define LLVM_LIB_DEBUGINFO_PDB_RAW_GSI_H -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" Index: llvm/trunk/lib/DebugInfo/PDB/Native/GSI.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/GSI.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/GSI.cpp @@ -9,10 +9,10 @@ #include "GSI.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" Index: llvm/trunk/lib/DebugInfo/PDB/Native/GlobalsStream.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/GlobalsStream.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/GlobalsStream.cpp @@ -9,7 +9,7 @@ #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" #include "GSI.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" #include Index: llvm/trunk/lib/DebugInfo/PDB/Native/InfoStream.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/InfoStream.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/InfoStream.cpp @@ -10,12 +10,12 @@ #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" using namespace llvm; using namespace llvm::codeview; Index: llvm/trunk/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp @@ -9,7 +9,6 @@ #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" @@ -17,6 +16,7 @@ #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamWriter.h" using namespace llvm; using namespace llvm::codeview; Index: llvm/trunk/lib/DebugInfo/PDB/Native/ModInfo.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/ModInfo.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/ModInfo.cpp @@ -8,8 +8,8 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Native/ModInfo.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/MathExtras.h" Index: llvm/trunk/lib/DebugInfo/PDB/Native/ModStream.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/ModStream.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/ModStream.cpp @@ -10,12 +10,12 @@ #include "llvm/DebugInfo/PDB/Native/ModStream.h" #include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" #include "llvm/DebugInfo/PDB/Native/ModInfo.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Error.h" #include #include Index: llvm/trunk/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp @@ -13,9 +13,9 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" #include "llvm/DebugInfo/PDB/Native/HashTable.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" #include #include Index: llvm/trunk/lib/DebugInfo/PDB/Native/NativeSession.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/NativeSession.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/NativeSession.cpp @@ -10,7 +10,6 @@ #include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" @@ -20,6 +19,7 @@ #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" Index: llvm/trunk/lib/DebugInfo/PDB/Native/PDBFile.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/PDBFile.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/PDBFile.cpp @@ -10,9 +10,6 @@ #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/MSF/BinaryStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" @@ -23,6 +20,9 @@ #include "llvm/DebugInfo/PDB/Native/StringTable.h" #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/Path.h" Index: llvm/trunk/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -11,8 +11,6 @@ #include "llvm/ADT/BitVector.h" -#include "llvm/DebugInfo/MSF/BinaryStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" @@ -23,6 +21,8 @@ #include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamWriter.h" using namespace llvm; using namespace llvm::codeview; Index: llvm/trunk/lib/DebugInfo/PDB/Native/PublicsStream.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/PublicsStream.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/PublicsStream.cpp @@ -26,11 +26,11 @@ #include "GSI.h" #include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include Index: llvm/trunk/lib/DebugInfo/PDB/Native/StringTable.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/StringTable.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/StringTable.cpp @@ -10,10 +10,10 @@ #include "llvm/DebugInfo/PDB/Native/StringTable.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" #include "llvm/DebugInfo/PDB/Native/Hash.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" using namespace llvm; Index: llvm/trunk/lib/DebugInfo/PDB/Native/StringTableBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/StringTableBuilder.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/StringTableBuilder.cpp @@ -9,9 +9,9 @@ #include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" #include "llvm/DebugInfo/PDB/Native/Hash.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Endian.h" using namespace llvm; Index: llvm/trunk/lib/DebugInfo/PDB/Native/SymbolStream.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/SymbolStream.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/SymbolStream.cpp @@ -11,11 +11,11 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" using namespace llvm; Index: llvm/trunk/lib/DebugInfo/PDB/Native/TpiStream.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/TpiStream.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/TpiStream.cpp @@ -13,7 +13,6 @@ #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h" @@ -21,6 +20,7 @@ #include "llvm/DebugInfo/PDB/Native/RawError.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/DebugInfo/PDB/Native/TpiHashing.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include Index: llvm/trunk/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp =================================================================== --- llvm/trunk/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp +++ llvm/trunk/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp @@ -12,10 +12,6 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" @@ -23,6 +19,10 @@ #include "llvm/DebugInfo/PDB/Native/RawTypes.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include Index: llvm/trunk/lib/Support/BinaryStreamError.cpp =================================================================== --- llvm/trunk/lib/Support/BinaryStreamError.cpp +++ llvm/trunk/lib/Support/BinaryStreamError.cpp @@ -0,0 +1,56 @@ +//===- BinaryStreamError.cpp - Error extensions for streams -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +char BinaryStreamError::ID = 0; + +BinaryStreamError::BinaryStreamError(stream_error_code C) + : BinaryStreamError(C, "") {} + +BinaryStreamError::BinaryStreamError(StringRef Context) + : BinaryStreamError(stream_error_code::unspecified, Context) {} + +BinaryStreamError::BinaryStreamError(stream_error_code C, StringRef Context) + : Code(C) { + ErrMsg = "Stream Error: "; + switch (C) { + case stream_error_code::unspecified: + ErrMsg += "An unspecified error has occurred."; + break; + case stream_error_code::stream_too_short: + ErrMsg += "The stream is too short to perform the requested operation."; + break; + case stream_error_code::invalid_array_size: + ErrMsg += "The buffer size is not a multiple of the array element size."; + break; + case stream_error_code::invalid_offset: + ErrMsg += "The specified offset is invalid for the current stream."; + break; + case stream_error_code::filesystem_error: + ErrMsg += "An I/O error occurred on the file system."; + break; + } + + if (!Context.empty()) { + ErrMsg += " "; + ErrMsg += Context; + } +} + +void BinaryStreamError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; } + +StringRef BinaryStreamError::getErrorMessage() const { return ErrMsg; } + +std::error_code BinaryStreamError::convertToErrorCode() const { + return inconvertibleErrorCode(); +} Index: llvm/trunk/lib/Support/BinaryStreamReader.cpp =================================================================== --- llvm/trunk/lib/Support/BinaryStreamReader.cpp +++ llvm/trunk/lib/Support/BinaryStreamReader.cpp @@ -0,0 +1,95 @@ +//===- BinaryStreamReader.cpp - Reads objects from a binary stream --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/BinaryStreamReader.h" + +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/BinaryStreamRef.h" + +using namespace llvm; + +BinaryStreamReader::BinaryStreamReader(BinaryStreamRef S) + : Stream(S), Offset(0) {} + +Error BinaryStreamReader::readLongestContiguousChunk( + ArrayRef &Buffer) { + if (auto EC = Stream.readLongestContiguousChunk(Offset, Buffer)) + return EC; + Offset += Buffer.size(); + return Error::success(); +} + +Error BinaryStreamReader::readBytes(ArrayRef &Buffer, uint32_t Size) { + if (auto EC = Stream.readBytes(Offset, Size, Buffer)) + return EC; + Offset += Size; + return Error::success(); +} + +Error BinaryStreamReader::readCString(StringRef &Dest) { + // TODO: This could be made more efficient by using readLongestContiguousChunk + // and searching for null terminators in the resulting buffer. + + uint32_t Length = 0; + // First compute the length of the string by reading 1 byte at a time. + uint32_t OriginalOffset = getOffset(); + const char *C; + while (true) { + if (auto EC = readObject(C)) + return EC; + if (*C == '\0') + break; + ++Length; + } + // Now go back and request a reference for that many bytes. + uint32_t NewOffset = getOffset(); + setOffset(OriginalOffset); + + if (auto EC = readFixedString(Dest, Length)) + return EC; + + // Now set the offset back to where it was after we calculated the length. + setOffset(NewOffset); + return Error::success(); +} + +Error BinaryStreamReader::readFixedString(StringRef &Dest, uint32_t Length) { + ArrayRef Bytes; + if (auto EC = readBytes(Bytes, Length)) + return EC; + Dest = StringRef(reinterpret_cast(Bytes.begin()), Bytes.size()); + return Error::success(); +} + +Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref) { + return readStreamRef(Ref, bytesRemaining()); +} + +Error BinaryStreamReader::readStreamRef(BinaryStreamRef &Ref, uint32_t Length) { + if (bytesRemaining() < Length) + return make_error(stream_error_code::stream_too_short); + Ref = Stream.slice(Offset, Length); + Offset += Length; + return Error::success(); +} + +Error BinaryStreamReader::skip(uint32_t Amount) { + if (Amount > bytesRemaining()) + return make_error(stream_error_code::stream_too_short); + Offset += Amount; + return Error::success(); +} + +uint8_t BinaryStreamReader::peek() const { + ArrayRef Buffer; + auto EC = Stream.readBytes(Offset, 1, Buffer); + assert(!EC && "Cannot peek an empty buffer!"); + llvm::consumeError(std::move(EC)); + return Buffer[0]; +} Index: llvm/trunk/lib/Support/BinaryStreamWriter.cpp =================================================================== --- llvm/trunk/lib/Support/BinaryStreamWriter.cpp +++ llvm/trunk/lib/Support/BinaryStreamWriter.cpp @@ -0,0 +1,59 @@ +//===- BinaryStreamWriter.cpp - Writes objects to a BinaryStream ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/BinaryStreamWriter.h" + +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" + +using namespace llvm; + +BinaryStreamWriter::BinaryStreamWriter(WritableBinaryStreamRef S) + : Stream(S), Offset(0) {} + +Error BinaryStreamWriter::writeBytes(ArrayRef Buffer) { + if (auto EC = Stream.writeBytes(Offset, Buffer)) + return EC; + Offset += Buffer.size(); + return Error::success(); +} + +Error BinaryStreamWriter::writeCString(StringRef Str) { + if (auto EC = writeFixedString(Str)) + return EC; + if (auto EC = writeObject('\0')) + return EC; + + return Error::success(); +} + +Error BinaryStreamWriter::writeFixedString(StringRef Str) { + return writeBytes(ArrayRef(Str.bytes_begin(), Str.bytes_end())); +} + +Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) { + return writeStreamRef(Ref, Ref.getLength()); +} + +Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint32_t Length) { + BinaryStreamReader SrcReader(Ref.slice(0, Length)); + // This is a bit tricky. If we just call readBytes, we are requiring that it + // return us the entire stream as a contiguous buffer. There is no guarantee + // this can be satisfied by returning a reference straight from the buffer, as + // an implementation may not store all data in a single contiguous buffer. So + // we iterate over each contiguous chunk, writing each one in succession. + while (SrcReader.bytesRemaining() > 0) { + ArrayRef Chunk; + if (auto EC = SrcReader.readLongestContiguousChunk(Chunk)) + return EC; + if (auto EC = writeBytes(Chunk)) + return EC; + } + return Error::success(); +} Index: llvm/trunk/lib/Support/CMakeLists.txt =================================================================== --- llvm/trunk/lib/Support/CMakeLists.txt +++ llvm/trunk/lib/Support/CMakeLists.txt @@ -34,6 +34,9 @@ ARMAttributeParser.cpp ARMWinEH.cpp Allocator.cpp + BinaryStreamError.cpp + BinaryStreamReader.cpp + BinaryStreamWriter.cpp BlockFrequency.cpp BranchProbability.cpp CachePruning.cpp Index: llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ llvm/trunk/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -21,7 +21,6 @@ #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/EnumTables.h" @@ -36,6 +35,7 @@ #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/PDBExtras.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/FormatVariadic.h" #include Index: llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ llvm/trunk/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -31,7 +31,6 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" @@ -55,6 +54,7 @@ #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" #include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" +#include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/COM.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ConvertUTF.h" Index: llvm/trunk/tools/llvm-readobj/COFFDumper.cpp =================================================================== --- llvm/trunk/tools/llvm-readobj/COFFDumper.cpp +++ llvm/trunk/tools/llvm-readobj/COFFDumper.cpp @@ -35,9 +35,9 @@ #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/COFF.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" Index: llvm/trunk/unittests/DebugInfo/PDB/BinaryStreamTest.cpp =================================================================== --- llvm/trunk/unittests/DebugInfo/PDB/BinaryStreamTest.cpp +++ llvm/trunk/unittests/DebugInfo/PDB/BinaryStreamTest.cpp @@ -1,710 +0,0 @@ -//===- llvm/unittest/Support/BinaryStreamTest.cpp -------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" -#include "llvm/DebugInfo/MSF/BinaryItemStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamArray.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" -#include "gtest/gtest.h" - -#include - -using namespace llvm; -using namespace llvm::support; - -#define EXPECT_NO_ERROR(Err) \ - { \ - auto E = Err; \ - EXPECT_FALSE(static_cast(E)); \ - if (E) \ - consumeError(std::move(E)); \ - } - -#define ASSERT_NO_ERROR(Err) \ - { \ - auto E = Err; \ - ASSERT_FALSE(static_cast(E)); \ - if (E) \ - consumeError(std::move(E)); \ - } - -#define EXPECT_ERROR(Err) \ - { \ - auto E = Err; \ - EXPECT_TRUE(static_cast(E)); \ - if (E) \ - consumeError(std::move(E)); \ - } - -namespace { - -class BrokenStream : public WritableBinaryStream { -public: - BrokenStream(MutableArrayRef Data, endianness Endian, - uint32_t Align) - : Data(Data), PartitionIndex(alignDown(Data.size() / 2, Align)), - Endian(Endian) {} - - endianness getEndian() const override { return Endian; } - - Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) override { - if (auto EC = checkOffset(Offset, Size)) - return EC; - uint32_t S = startIndex(Offset); - auto Ref = Data.drop_front(S); - if (Ref.size() >= Size) { - Buffer = Ref.take_front(Size); - return Error::success(); - } - - uint32_t BytesLeft = Size - Ref.size(); - uint8_t *Ptr = Allocator.Allocate(Size); - ::memcpy(Ptr, Ref.data(), Ref.size()); - ::memcpy(Ptr + Ref.size(), Data.data(), BytesLeft); - Buffer = makeArrayRef(Ptr, Size); - return Error::success(); - } - - Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) override { - if (auto EC = checkOffset(Offset, 1)) - return EC; - uint32_t S = startIndex(Offset); - Buffer = Data.drop_front(S); - return Error::success(); - } - - uint32_t getLength() override { return Data.size(); } - - Error writeBytes(uint32_t Offset, ArrayRef SrcData) override { - if (auto EC = checkOffset(Offset, SrcData.size())) - return EC; - if (SrcData.empty()) - return Error::success(); - - uint32_t S = startIndex(Offset); - MutableArrayRef Ref(Data); - Ref = Ref.drop_front(S); - if (Ref.size() >= SrcData.size()) { - ::memcpy(Ref.data(), SrcData.data(), SrcData.size()); - return Error::success(); - } - - uint32_t BytesLeft = SrcData.size() - Ref.size(); - ::memcpy(Ref.data(), SrcData.data(), Ref.size()); - ::memcpy(&Data[0], SrcData.data() + Ref.size(), BytesLeft); - return Error::success(); - } - Error commit() override { return Error::success(); } - -private: - uint32_t startIndex(uint32_t Offset) const { - return (Offset + PartitionIndex) % Data.size(); - } - - uint32_t endIndex(uint32_t Offset, uint32_t Size) const { - return (startIndex(Offset) + Size - 1) % Data.size(); - } - - // Buffer is organized like this: - // ------------------------------------------------- - // | N/2 | N/2+1 | ... | N-1 | 0 | 1 | ... | N-2-1 | - // ------------------------------------------------- - // So reads from the beginning actually come from the middle. - MutableArrayRef Data; - uint32_t PartitionIndex = 0; - endianness Endian; - BumpPtrAllocator Allocator; -}; - -constexpr endianness Endians[] = { big, little, native }; -constexpr uint32_t NumEndians = llvm::array_lengthof(Endians); -constexpr uint32_t NumStreams = 2 * NumEndians; - -class BinaryStreamTest : public testing::Test { - -public: - BinaryStreamTest() {} - - void SetUp() override { - Streams.clear(); - Streams.resize(NumStreams); - for (uint32_t I = 0; I < NumStreams; ++I) - Streams[I].IsContiguous = (I % 2 == 0); - - InputData.clear(); - OutputData.clear(); - } - -protected: - struct StreamPair { - bool IsContiguous; - std::unique_ptr Input; - std::unique_ptr Output; - }; - - void initializeInput(ArrayRef Input, uint32_t Align) { - InputData = Input; - - BrokenInputData.resize(InputData.size()); - if (!Input.empty()) { - uint32_t PartitionIndex = alignDown(InputData.size() / 2, Align); - uint32_t RightBytes = InputData.size() - PartitionIndex; - uint32_t LeftBytes = PartitionIndex; - if (RightBytes > 0) - ::memcpy(&BrokenInputData[PartitionIndex], Input.data(), RightBytes); - if (LeftBytes > 0) - ::memcpy(&BrokenInputData[0], Input.data() + RightBytes, LeftBytes); - } - - for (uint32_t I = 0; I < NumEndians; ++I) { - auto InByteStream = - llvm::make_unique(InputData, Endians[I]); - auto InBrokenStream = llvm::make_unique( - BrokenInputData, Endians[I], Align); - - Streams[I * 2].Input = std::move(InByteStream); - Streams[I * 2 + 1].Input = std::move(InBrokenStream); - } - } - - void initializeOutput(uint32_t Size, uint32_t Align) { - OutputData.resize(Size); - BrokenOutputData.resize(Size); - - for (uint32_t I = 0; I < NumEndians; ++I) { - Streams[I * 2].Output = - llvm::make_unique(OutputData, Endians[I]); - Streams[I * 2 + 1].Output = llvm::make_unique( - BrokenOutputData, Endians[I], Align); - } - } - - void initializeOutputFromInput(uint32_t Align) { - for (uint32_t I = 0; I < NumEndians; ++I) { - Streams[I * 2].Output = - llvm::make_unique(InputData, Endians[I]); - Streams[I * 2 + 1].Output = llvm::make_unique( - BrokenInputData, Endians[I], Align); - } - } - - void initializeInputFromOutput(uint32_t Align) { - for (uint32_t I = 0; I < NumEndians; ++I) { - Streams[I * 2].Input = - llvm::make_unique(OutputData, Endians[I]); - Streams[I * 2 + 1].Input = llvm::make_unique( - BrokenOutputData, Endians[I], Align); - } - } - - std::vector InputData; - std::vector BrokenInputData; - - std::vector OutputData; - std::vector BrokenOutputData; - - std::vector Streams; -}; - -// Tests that a we can read from a BinaryByteStream without a StreamReader. -TEST_F(BinaryStreamTest, BinaryByteStreamBounds) { - std::vector InputData = {1, 2, 3, 4, 5}; - initializeInput(InputData, 1); - - for (auto &Stream : Streams) { - ArrayRef Buffer; - - // 1. If the read fits it should work. - ASSERT_EQ(InputData.size(), Stream.Input->getLength()); - ASSERT_NO_ERROR(Stream.Input->readBytes(2, 1, Buffer)); - EXPECT_EQ(makeArrayRef(InputData).slice(2, 1), Buffer); - ASSERT_NO_ERROR(Stream.Input->readBytes(0, 4, Buffer)); - EXPECT_EQ(makeArrayRef(InputData).slice(0, 4), Buffer); - - // 2. Reading past the bounds of the input should fail. - EXPECT_ERROR(Stream.Input->readBytes(4, 2, Buffer)); - } -} - -TEST_F(BinaryStreamTest, StreamRefBounds) { - std::vector InputData = {1, 2, 3, 4, 5}; - initializeInput(InputData, 1); - - for (const auto &Stream : Streams) { - ArrayRef Buffer; - BinaryStreamRef Ref(*Stream.Input); - - // Read 1 byte from offset 2 should work - ASSERT_EQ(InputData.size(), Ref.getLength()); - ASSERT_NO_ERROR(Ref.readBytes(2, 1, Buffer)); - EXPECT_EQ(makeArrayRef(InputData).slice(2, 1), Buffer); - - // Reading everything from offset 2 on. - ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer)); - if (Stream.IsContiguous) - EXPECT_EQ(makeArrayRef(InputData).slice(2), Buffer); - else - EXPECT_FALSE(Buffer.empty()); - - // Reading 6 bytes from offset 0 is too big. - EXPECT_ERROR(Ref.readBytes(0, 6, Buffer)); - EXPECT_ERROR(Ref.readLongestContiguousChunk(6, Buffer)); - - // Reading 1 byte from offset 2 after dropping 1 byte is the same as reading - // 1 byte from offset 3. - Ref = Ref.drop_front(1); - ASSERT_NO_ERROR(Ref.readBytes(2, 1, Buffer)); - if (Stream.IsContiguous) - EXPECT_EQ(makeArrayRef(InputData).slice(3, 1), Buffer); - else - EXPECT_FALSE(Buffer.empty()); - - // Reading everything from offset 2 on after dropping 1 byte. - ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer)); - if (Stream.IsContiguous) - EXPECT_EQ(makeArrayRef(InputData).slice(3), Buffer); - else - EXPECT_FALSE(Buffer.empty()); - - // Reading 2 bytes from offset 2 after dropping 2 bytes is the same as - // reading 2 bytes from offset 4, and should fail. - Ref = Ref.drop_front(1); - EXPECT_ERROR(Ref.readBytes(2, 2, Buffer)); - - // But if we read the longest contiguous chunk instead, we should still - // get the 1 byte at the end. - ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer)); - EXPECT_EQ(makeArrayRef(InputData).take_back(), Buffer); - } -} - -// Test that we can write to a BinaryStream without a StreamWriter. -TEST_F(BinaryStreamTest, MutableBinaryByteStreamBounds) { - std::vector InputData = {'T', 'e', 's', 't', '\0'}; - initializeInput(InputData, 1); - initializeOutput(InputData.size(), 1); - - // For every combination of input stream and output stream. - for (auto &Stream : Streams) { - MutableArrayRef Buffer; - ASSERT_EQ(InputData.size(), Stream.Input->getLength()); - - // 1. Try two reads that are supposed to work. One from offset 0, and one - // from the middle. - uint32_t Offsets[] = {0, 3}; - for (auto Offset : Offsets) { - uint32_t ExpectedSize = Stream.Input->getLength() - Offset; - - // Read everything from Offset until the end of the input data. - ArrayRef Data; - ASSERT_NO_ERROR(Stream.Input->readBytes(Offset, ExpectedSize, Data)); - ASSERT_EQ(ExpectedSize, Data.size()); - - // Then write it to the destination. - ASSERT_NO_ERROR(Stream.Output->writeBytes(0, Data)); - - // Then we read back what we wrote, it should match the corresponding - // slice of the original input data. - ArrayRef Data2; - ASSERT_NO_ERROR(Stream.Output->readBytes(Offset, ExpectedSize, Data2)); - EXPECT_EQ(makeArrayRef(InputData).drop_front(Offset), Data2); - } - - std::vector BigData = {0, 1, 2, 3, 4}; - // 2. If the write is too big, it should fail. - EXPECT_ERROR(Stream.Output->writeBytes(3, BigData)); - } -} - -// Test that FixedStreamArray works correctly. -TEST_F(BinaryStreamTest, FixedStreamArray) { - std::vector Ints = {90823, 12908, 109823, 209823}; - ArrayRef IntBytes(reinterpret_cast(Ints.data()), - Ints.size() * sizeof(uint32_t)); - - initializeInput(IntBytes, alignof(uint32_t)); - - for (auto &Stream : Streams) { - MutableArrayRef Buffer; - ASSERT_EQ(InputData.size(), Stream.Input->getLength()); - - FixedStreamArray Array(*Stream.Input); - auto Iter = Array.begin(); - ASSERT_EQ(Ints[0], *Iter++); - ASSERT_EQ(Ints[1], *Iter++); - ASSERT_EQ(Ints[2], *Iter++); - ASSERT_EQ(Ints[3], *Iter++); - ASSERT_EQ(Array.end(), Iter); - } -} - -// Test that VarStreamArray works correctly. -TEST_F(BinaryStreamTest, VarStreamArray) { - StringLiteral Strings("1. Test2. Longer Test3. Really Long Test4. Super " - "Extra Longest Test Of All"); - ArrayRef StringBytes( - reinterpret_cast(Strings.data()), Strings.size()); - initializeInput(StringBytes, 1); - - struct StringExtractor { - public: - Error operator()(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item) { - if (Index == 0) - Len = strlen("1. Test"); - else if (Index == 1) - Len = strlen("2. Longer Test"); - else if (Index == 2) - Len = strlen("3. Really Long Test"); - else - Len = strlen("4. Super Extra Longest Test Of All"); - ArrayRef Bytes; - if (auto EC = Stream.readBytes(0, Len, Bytes)) - return EC; - Item = - StringRef(reinterpret_cast(Bytes.data()), Bytes.size()); - ++Index; - return Error::success(); - } - - private: - uint32_t Index = 0; - }; - - for (auto &Stream : Streams) { - VarStreamArray Array(*Stream.Input); - auto Iter = Array.begin(); - ASSERT_EQ("1. Test", *Iter++); - ASSERT_EQ("2. Longer Test", *Iter++); - ASSERT_EQ("3. Really Long Test", *Iter++); - ASSERT_EQ("4. Super Extra Longest Test Of All", *Iter++); - ASSERT_EQ(Array.end(), Iter); - } -} - -TEST_F(BinaryStreamTest, StreamReaderBounds) { - std::vector Bytes; - - initializeInput(Bytes, 1); - for (auto &Stream : Streams) { - StringRef S; - BinaryStreamReader Reader(*Stream.Input); - EXPECT_EQ(0U, Reader.bytesRemaining()); - EXPECT_ERROR(Reader.readFixedString(S, 1)); - } - - Bytes.resize(5); - initializeInput(Bytes, 1); - for (auto &Stream : Streams) { - StringRef S; - BinaryStreamReader Reader(*Stream.Input); - EXPECT_EQ(Bytes.size(), Reader.bytesRemaining()); - EXPECT_NO_ERROR(Reader.readFixedString(S, 5)); - EXPECT_ERROR(Reader.readFixedString(S, 6)); - } -} - -TEST_F(BinaryStreamTest, StreamReaderIntegers) { - support::ulittle64_t Little{908234}; - support::ubig32_t Big{28907823}; - short NS = 2897; - int NI = -89723; - unsigned long NUL = 902309023UL; - constexpr uint32_t Size = - sizeof(Little) + sizeof(Big) + sizeof(NS) + sizeof(NI) + sizeof(NUL); - - initializeOutput(Size, alignof(support::ulittle64_t)); - initializeInputFromOutput(alignof(support::ulittle64_t)); - - for (auto &Stream : Streams) { - BinaryStreamWriter Writer(*Stream.Output); - ASSERT_NO_ERROR(Writer.writeObject(Little)); - ASSERT_NO_ERROR(Writer.writeObject(Big)); - ASSERT_NO_ERROR(Writer.writeInteger(NS)); - ASSERT_NO_ERROR(Writer.writeInteger(NI)); - ASSERT_NO_ERROR(Writer.writeInteger(NUL)); - - const support::ulittle64_t *Little2; - const support::ubig32_t *Big2; - short NS2; - int NI2; - unsigned long NUL2; - - // 1. Reading fields individually. - BinaryStreamReader Reader(*Stream.Input); - ASSERT_NO_ERROR(Reader.readObject(Little2)); - ASSERT_NO_ERROR(Reader.readObject(Big2)); - ASSERT_NO_ERROR(Reader.readInteger(NS2)); - ASSERT_NO_ERROR(Reader.readInteger(NI2)); - ASSERT_NO_ERROR(Reader.readInteger(NUL2)); - ASSERT_EQ(0U, Reader.bytesRemaining()); - - EXPECT_EQ(Little, *Little2); - EXPECT_EQ(Big, *Big2); - EXPECT_EQ(NS, NS2); - EXPECT_EQ(NI, NI2); - EXPECT_EQ(NUL, NUL2); - } -} - -TEST_F(BinaryStreamTest, StreamReaderIntegerArray) { - // 1. Arrays of integers - std::vector Ints = {1, 2, 3, 4, 5}; - ArrayRef IntBytes(reinterpret_cast(&Ints[0]), - Ints.size() * sizeof(int)); - - initializeInput(IntBytes, alignof(int)); - for (auto &Stream : Streams) { - BinaryStreamReader Reader(*Stream.Input); - ArrayRef IntsRef; - ASSERT_NO_ERROR(Reader.readArray(IntsRef, Ints.size())); - ASSERT_EQ(0U, Reader.bytesRemaining()); - EXPECT_EQ(makeArrayRef(Ints), IntsRef); - - Reader.setOffset(0); - FixedStreamArray FixedIntsRef; - ASSERT_NO_ERROR(Reader.readArray(FixedIntsRef, Ints.size())); - ASSERT_EQ(0U, Reader.bytesRemaining()); - ASSERT_EQ(Ints, std::vector(FixedIntsRef.begin(), FixedIntsRef.end())); - } -} - -TEST_F(BinaryStreamTest, StreamReaderEnum) { - enum class MyEnum : int64_t { Foo = -10, Bar = 0, Baz = 10 }; - - std::vector Enums = {MyEnum::Bar, MyEnum::Baz, MyEnum::Foo}; - - initializeOutput(Enums.size() * sizeof(MyEnum), alignof(MyEnum)); - initializeInputFromOutput(alignof(MyEnum)); - for (auto &Stream : Streams) { - BinaryStreamWriter Writer(*Stream.Output); - for (auto Value : Enums) - ASSERT_NO_ERROR(Writer.writeEnum(Value)); - - BinaryStreamReader Reader(*Stream.Input); - - ArrayRef Array; - FixedStreamArray FSA; - - for (size_t I = 0; I < Enums.size(); ++I) { - MyEnum Value; - ASSERT_NO_ERROR(Reader.readEnum(Value)); - EXPECT_EQ(Enums[I], Value); - } - ASSERT_EQ(0U, Reader.bytesRemaining()); - } -} - -TEST_F(BinaryStreamTest, StreamReaderObject) { - struct Foo { - int X; - double Y; - char Z; - - bool operator==(const Foo &Other) const { - return X == Other.X && Y == Other.Y && Z == Other.Z; - } - }; - - std::vector Foos; - Foos.push_back({-42, 42.42, 42}); - Foos.push_back({100, 3.1415, static_cast(-89)}); - Foos.push_back({200, 2.718, static_cast(-12) }); - - const uint8_t *Bytes = reinterpret_cast(&Foos[0]); - - initializeInput(makeArrayRef(Bytes, 3 * sizeof(Foo)), alignof(Foo)); - - for (auto &Stream : Streams) { - // 1. Reading object pointers. - BinaryStreamReader Reader(*Stream.Input); - const Foo *FPtrOut = nullptr; - const Foo *GPtrOut = nullptr; - const Foo *HPtrOut = nullptr; - ASSERT_NO_ERROR(Reader.readObject(FPtrOut)); - ASSERT_NO_ERROR(Reader.readObject(GPtrOut)); - ASSERT_NO_ERROR(Reader.readObject(HPtrOut)); - EXPECT_EQ(0U, Reader.bytesRemaining()); - EXPECT_EQ(Foos[0], *FPtrOut); - EXPECT_EQ(Foos[1], *GPtrOut); - EXPECT_EQ(Foos[2], *HPtrOut); - } -} - -TEST_F(BinaryStreamTest, StreamReaderStrings) { - std::vector Bytes = {'O', 'n', 'e', '\0', 'T', 'w', 'o', - '\0', 'T', 'h', 'r', 'e', 'e', '\0', - 'F', 'o', 'u', 'r', '\0'}; - initializeInput(Bytes, 1); - - for (auto &Stream : Streams) { - BinaryStreamReader Reader(*Stream.Input); - - StringRef S1; - StringRef S2; - StringRef S3; - StringRef S4; - ASSERT_NO_ERROR(Reader.readCString(S1)); - ASSERT_NO_ERROR(Reader.readCString(S2)); - ASSERT_NO_ERROR(Reader.readCString(S3)); - ASSERT_NO_ERROR(Reader.readCString(S4)); - ASSERT_EQ(0U, Reader.bytesRemaining()); - - EXPECT_EQ("One", S1); - EXPECT_EQ("Two", S2); - EXPECT_EQ("Three", S3); - EXPECT_EQ("Four", S4); - - S1 = S2 = S3 = S4 = ""; - Reader.setOffset(0); - ASSERT_NO_ERROR(Reader.readFixedString(S1, 3)); - ASSERT_NO_ERROR(Reader.skip(1)); - ASSERT_NO_ERROR(Reader.readFixedString(S2, 3)); - ASSERT_NO_ERROR(Reader.skip(1)); - ASSERT_NO_ERROR(Reader.readFixedString(S3, 5)); - ASSERT_NO_ERROR(Reader.skip(1)); - ASSERT_NO_ERROR(Reader.readFixedString(S4, 4)); - ASSERT_NO_ERROR(Reader.skip(1)); - ASSERT_EQ(0U, Reader.bytesRemaining()); - - EXPECT_EQ("One", S1); - EXPECT_EQ("Two", S2); - EXPECT_EQ("Three", S3); - EXPECT_EQ("Four", S4); - } -} - -TEST_F(BinaryStreamTest, StreamWriterBounds) { - initializeOutput(5, 1); - - for (auto &Stream : Streams) { - BinaryStreamWriter Writer(*Stream.Output); - - // 1. Can write a string that exactly fills the buffer. - EXPECT_EQ(5U, Writer.bytesRemaining()); - EXPECT_NO_ERROR(Writer.writeFixedString("abcde")); - EXPECT_EQ(0U, Writer.bytesRemaining()); - - // 2. Can write an empty string even when you're full - EXPECT_NO_ERROR(Writer.writeFixedString("")); - EXPECT_ERROR(Writer.writeFixedString("a")); - - // 3. Can't write a string that is one character too long. - Writer.setOffset(0); - EXPECT_ERROR(Writer.writeFixedString("abcdef")); - } -} - -TEST_F(BinaryStreamTest, StreamWriterIntegerArrays) { - // 3. Arrays of integers - std::vector SourceInts = {1, 2, 3, 4, 5}; - ArrayRef SourceBytes(reinterpret_cast(&SourceInts[0]), - SourceInts.size() * sizeof(int)); - - initializeInput(SourceBytes, alignof(int)); - initializeOutputFromInput(alignof(int)); - - for (auto &Stream : Streams) { - BinaryStreamReader Reader(*Stream.Input); - BinaryStreamWriter Writer(*Stream.Output); - ArrayRef Ints; - ArrayRef Ints2; - // First read them, then write them, then read them back. - ASSERT_NO_ERROR(Reader.readArray(Ints, SourceInts.size())); - ASSERT_NO_ERROR(Writer.writeArray(Ints)); - - BinaryStreamReader ReaderBacker(*Stream.Output); - ASSERT_NO_ERROR(ReaderBacker.readArray(Ints2, SourceInts.size())); - - EXPECT_EQ(makeArrayRef(SourceInts), Ints2); - } -} - -TEST_F(BinaryStreamTest, StringWriterStrings) { - StringRef Strings[] = {"First", "Second", "Third", "Fourth"}; - - size_t Length = 0; - for (auto S : Strings) - Length += S.size() + 1; - initializeOutput(Length, 1); - initializeInputFromOutput(1); - - for (auto &Stream : Streams) { - BinaryStreamWriter Writer(*Stream.Output); - for (auto S : Strings) - ASSERT_NO_ERROR(Writer.writeCString(S)); - std::vector InStrings; - BinaryStreamReader Reader(*Stream.Input); - while (!Reader.empty()) { - StringRef S; - ASSERT_NO_ERROR(Reader.readCString(S)); - InStrings.push_back(S); - } - EXPECT_EQ(makeArrayRef(Strings), makeArrayRef(InStrings)); - } -} -} - -namespace { -struct BinaryItemStreamObject { - explicit BinaryItemStreamObject(ArrayRef Bytes) : Bytes(Bytes) {} - - ArrayRef Bytes; -}; -} - -namespace llvm { -template <> struct BinaryItemTraits { - static size_t length(const BinaryItemStreamObject &Item) { - return Item.Bytes.size(); - } - - static ArrayRef bytes(const BinaryItemStreamObject &Item) { - return Item.Bytes; - } -}; -} - -namespace { - -TEST_F(BinaryStreamTest, BinaryItemStream) { - std::vector Objects; - - struct Foo { - int X; - double Y; - }; - std::vector Foos = {{1, 1.0}, {2, 2.0}, {3, 3.0}}; - BumpPtrAllocator Allocator; - for (const auto &F : Foos) { - uint8_t *Ptr = Allocator.Allocate(sizeof(Foo)); - MutableArrayRef Buffer(Ptr, sizeof(Foo)); - MutableBinaryByteStream Stream(Buffer, llvm::support::big); - BinaryStreamWriter Writer(Stream); - ASSERT_NO_ERROR(Writer.writeObject(F)); - Objects.push_back(BinaryItemStreamObject(Buffer)); - } - - BinaryItemStream ItemStream(big); - ItemStream.setItems(Objects); - BinaryStreamReader Reader(ItemStream); - - for (const auto &F : Foos) { - const Foo *F2; - ASSERT_NO_ERROR(Reader.readObject(F2)); - - EXPECT_EQ(F.X, F2->X); - EXPECT_DOUBLE_EQ(F.Y, F2->Y); - } -} - -} // end anonymous namespace Index: llvm/trunk/unittests/DebugInfo/PDB/CMakeLists.txt =================================================================== --- llvm/trunk/unittests/DebugInfo/PDB/CMakeLists.txt +++ llvm/trunk/unittests/DebugInfo/PDB/CMakeLists.txt @@ -5,7 +5,6 @@ ) set(DebugInfoPDBSources - BinaryStreamTest.cpp HashTableTest.cpp MappedBlockStreamTest.cpp StringTableBuilderTest.cpp Index: llvm/trunk/unittests/DebugInfo/PDB/HashTableTest.cpp =================================================================== --- llvm/trunk/unittests/DebugInfo/PDB/HashTableTest.cpp +++ llvm/trunk/unittests/DebugInfo/PDB/HashTableTest.cpp @@ -10,10 +10,10 @@ #include "ErrorChecking.h" #include "gtest/gtest.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" #include "llvm/DebugInfo/PDB/Native/HashTable.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" #include Index: llvm/trunk/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp =================================================================== --- llvm/trunk/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp +++ llvm/trunk/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp @@ -9,14 +9,14 @@ #include "ErrorChecking.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" -#include "llvm/DebugInfo/MSF/BinaryStreamRef.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" #include "llvm/DebugInfo/MSF/IMSFFile.h" #include "llvm/DebugInfo/MSF/MSFError.h" #include "llvm/DebugInfo/MSF/MSFStreamLayout.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "gtest/gtest.h" #include Index: llvm/trunk/unittests/DebugInfo/PDB/StringTableBuilderTest.cpp =================================================================== --- llvm/trunk/unittests/DebugInfo/PDB/StringTableBuilderTest.cpp +++ llvm/trunk/unittests/DebugInfo/PDB/StringTableBuilderTest.cpp @@ -9,11 +9,11 @@ #include "ErrorChecking.h" -#include "llvm/DebugInfo/MSF/BinaryByteStream.h" -#include "llvm/DebugInfo/MSF/BinaryStreamReader.h" -#include "llvm/DebugInfo/MSF/BinaryStreamWriter.h" #include "llvm/DebugInfo/PDB/Native/StringTable.h" #include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "gtest/gtest.h" Index: llvm/trunk/unittests/Support/BinaryStreamTest.cpp =================================================================== --- llvm/trunk/unittests/Support/BinaryStreamTest.cpp +++ llvm/trunk/unittests/Support/BinaryStreamTest.cpp @@ -0,0 +1,710 @@ +//===- llvm/unittest/Support/BinaryStreamTest.cpp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryItemStream.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "gtest/gtest.h" + +#include + +using namespace llvm; +using namespace llvm::support; + +#define EXPECT_NO_ERROR(Err) \ + { \ + auto E = Err; \ + EXPECT_FALSE(static_cast(E)); \ + if (E) \ + consumeError(std::move(E)); \ + } + +#define ASSERT_NO_ERROR(Err) \ + { \ + auto E = Err; \ + ASSERT_FALSE(static_cast(E)); \ + if (E) \ + consumeError(std::move(E)); \ + } + +#define EXPECT_ERROR(Err) \ + { \ + auto E = Err; \ + EXPECT_TRUE(static_cast(E)); \ + if (E) \ + consumeError(std::move(E)); \ + } + +namespace { + +class BrokenStream : public WritableBinaryStream { +public: + BrokenStream(MutableArrayRef Data, endianness Endian, + uint32_t Align) + : Data(Data), PartitionIndex(alignDown(Data.size() / 2, Align)), + Endian(Endian) {} + + endianness getEndian() const override { return Endian; } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) override { + if (auto EC = checkOffset(Offset, Size)) + return EC; + uint32_t S = startIndex(Offset); + auto Ref = Data.drop_front(S); + if (Ref.size() >= Size) { + Buffer = Ref.take_front(Size); + return Error::success(); + } + + uint32_t BytesLeft = Size - Ref.size(); + uint8_t *Ptr = Allocator.Allocate(Size); + ::memcpy(Ptr, Ref.data(), Ref.size()); + ::memcpy(Ptr + Ref.size(), Data.data(), BytesLeft); + Buffer = makeArrayRef(Ptr, Size); + return Error::success(); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) override { + if (auto EC = checkOffset(Offset, 1)) + return EC; + uint32_t S = startIndex(Offset); + Buffer = Data.drop_front(S); + return Error::success(); + } + + uint32_t getLength() override { return Data.size(); } + + Error writeBytes(uint32_t Offset, ArrayRef SrcData) override { + if (auto EC = checkOffset(Offset, SrcData.size())) + return EC; + if (SrcData.empty()) + return Error::success(); + + uint32_t S = startIndex(Offset); + MutableArrayRef Ref(Data); + Ref = Ref.drop_front(S); + if (Ref.size() >= SrcData.size()) { + ::memcpy(Ref.data(), SrcData.data(), SrcData.size()); + return Error::success(); + } + + uint32_t BytesLeft = SrcData.size() - Ref.size(); + ::memcpy(Ref.data(), SrcData.data(), Ref.size()); + ::memcpy(&Data[0], SrcData.data() + Ref.size(), BytesLeft); + return Error::success(); + } + Error commit() override { return Error::success(); } + +private: + uint32_t startIndex(uint32_t Offset) const { + return (Offset + PartitionIndex) % Data.size(); + } + + uint32_t endIndex(uint32_t Offset, uint32_t Size) const { + return (startIndex(Offset) + Size - 1) % Data.size(); + } + + // Buffer is organized like this: + // ------------------------------------------------- + // | N/2 | N/2+1 | ... | N-1 | 0 | 1 | ... | N-2-1 | + // ------------------------------------------------- + // So reads from the beginning actually come from the middle. + MutableArrayRef Data; + uint32_t PartitionIndex = 0; + endianness Endian; + BumpPtrAllocator Allocator; +}; + +constexpr endianness Endians[] = {big, little, native}; +constexpr uint32_t NumEndians = llvm::array_lengthof(Endians); +constexpr uint32_t NumStreams = 2 * NumEndians; + +class BinaryStreamTest : public testing::Test { + +public: + BinaryStreamTest() {} + + void SetUp() override { + Streams.clear(); + Streams.resize(NumStreams); + for (uint32_t I = 0; I < NumStreams; ++I) + Streams[I].IsContiguous = (I % 2 == 0); + + InputData.clear(); + OutputData.clear(); + } + +protected: + struct StreamPair { + bool IsContiguous; + std::unique_ptr Input; + std::unique_ptr Output; + }; + + void initializeInput(ArrayRef Input, uint32_t Align) { + InputData = Input; + + BrokenInputData.resize(InputData.size()); + if (!Input.empty()) { + uint32_t PartitionIndex = alignDown(InputData.size() / 2, Align); + uint32_t RightBytes = InputData.size() - PartitionIndex; + uint32_t LeftBytes = PartitionIndex; + if (RightBytes > 0) + ::memcpy(&BrokenInputData[PartitionIndex], Input.data(), RightBytes); + if (LeftBytes > 0) + ::memcpy(&BrokenInputData[0], Input.data() + RightBytes, LeftBytes); + } + + for (uint32_t I = 0; I < NumEndians; ++I) { + auto InByteStream = + llvm::make_unique(InputData, Endians[I]); + auto InBrokenStream = llvm::make_unique( + BrokenInputData, Endians[I], Align); + + Streams[I * 2].Input = std::move(InByteStream); + Streams[I * 2 + 1].Input = std::move(InBrokenStream); + } + } + + void initializeOutput(uint32_t Size, uint32_t Align) { + OutputData.resize(Size); + BrokenOutputData.resize(Size); + + for (uint32_t I = 0; I < NumEndians; ++I) { + Streams[I * 2].Output = + llvm::make_unique(OutputData, Endians[I]); + Streams[I * 2 + 1].Output = llvm::make_unique( + BrokenOutputData, Endians[I], Align); + } + } + + void initializeOutputFromInput(uint32_t Align) { + for (uint32_t I = 0; I < NumEndians; ++I) { + Streams[I * 2].Output = + llvm::make_unique(InputData, Endians[I]); + Streams[I * 2 + 1].Output = llvm::make_unique( + BrokenInputData, Endians[I], Align); + } + } + + void initializeInputFromOutput(uint32_t Align) { + for (uint32_t I = 0; I < NumEndians; ++I) { + Streams[I * 2].Input = + llvm::make_unique(OutputData, Endians[I]); + Streams[I * 2 + 1].Input = llvm::make_unique( + BrokenOutputData, Endians[I], Align); + } + } + + std::vector InputData; + std::vector BrokenInputData; + + std::vector OutputData; + std::vector BrokenOutputData; + + std::vector Streams; +}; + +// Tests that a we can read from a BinaryByteStream without a StreamReader. +TEST_F(BinaryStreamTest, BinaryByteStreamBounds) { + std::vector InputData = {1, 2, 3, 4, 5}; + initializeInput(InputData, 1); + + for (auto &Stream : Streams) { + ArrayRef Buffer; + + // 1. If the read fits it should work. + ASSERT_EQ(InputData.size(), Stream.Input->getLength()); + ASSERT_NO_ERROR(Stream.Input->readBytes(2, 1, Buffer)); + EXPECT_EQ(makeArrayRef(InputData).slice(2, 1), Buffer); + ASSERT_NO_ERROR(Stream.Input->readBytes(0, 4, Buffer)); + EXPECT_EQ(makeArrayRef(InputData).slice(0, 4), Buffer); + + // 2. Reading past the bounds of the input should fail. + EXPECT_ERROR(Stream.Input->readBytes(4, 2, Buffer)); + } +} + +TEST_F(BinaryStreamTest, StreamRefBounds) { + std::vector InputData = {1, 2, 3, 4, 5}; + initializeInput(InputData, 1); + + for (const auto &Stream : Streams) { + ArrayRef Buffer; + BinaryStreamRef Ref(*Stream.Input); + + // Read 1 byte from offset 2 should work + ASSERT_EQ(InputData.size(), Ref.getLength()); + ASSERT_NO_ERROR(Ref.readBytes(2, 1, Buffer)); + EXPECT_EQ(makeArrayRef(InputData).slice(2, 1), Buffer); + + // Reading everything from offset 2 on. + ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer)); + if (Stream.IsContiguous) + EXPECT_EQ(makeArrayRef(InputData).slice(2), Buffer); + else + EXPECT_FALSE(Buffer.empty()); + + // Reading 6 bytes from offset 0 is too big. + EXPECT_ERROR(Ref.readBytes(0, 6, Buffer)); + EXPECT_ERROR(Ref.readLongestContiguousChunk(6, Buffer)); + + // Reading 1 byte from offset 2 after dropping 1 byte is the same as reading + // 1 byte from offset 3. + Ref = Ref.drop_front(1); + ASSERT_NO_ERROR(Ref.readBytes(2, 1, Buffer)); + if (Stream.IsContiguous) + EXPECT_EQ(makeArrayRef(InputData).slice(3, 1), Buffer); + else + EXPECT_FALSE(Buffer.empty()); + + // Reading everything from offset 2 on after dropping 1 byte. + ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer)); + if (Stream.IsContiguous) + EXPECT_EQ(makeArrayRef(InputData).slice(3), Buffer); + else + EXPECT_FALSE(Buffer.empty()); + + // Reading 2 bytes from offset 2 after dropping 2 bytes is the same as + // reading 2 bytes from offset 4, and should fail. + Ref = Ref.drop_front(1); + EXPECT_ERROR(Ref.readBytes(2, 2, Buffer)); + + // But if we read the longest contiguous chunk instead, we should still + // get the 1 byte at the end. + ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer)); + EXPECT_EQ(makeArrayRef(InputData).take_back(), Buffer); + } +} + +// Test that we can write to a BinaryStream without a StreamWriter. +TEST_F(BinaryStreamTest, MutableBinaryByteStreamBounds) { + std::vector InputData = {'T', 'e', 's', 't', '\0'}; + initializeInput(InputData, 1); + initializeOutput(InputData.size(), 1); + + // For every combination of input stream and output stream. + for (auto &Stream : Streams) { + MutableArrayRef Buffer; + ASSERT_EQ(InputData.size(), Stream.Input->getLength()); + + // 1. Try two reads that are supposed to work. One from offset 0, and one + // from the middle. + uint32_t Offsets[] = {0, 3}; + for (auto Offset : Offsets) { + uint32_t ExpectedSize = Stream.Input->getLength() - Offset; + + // Read everything from Offset until the end of the input data. + ArrayRef Data; + ASSERT_NO_ERROR(Stream.Input->readBytes(Offset, ExpectedSize, Data)); + ASSERT_EQ(ExpectedSize, Data.size()); + + // Then write it to the destination. + ASSERT_NO_ERROR(Stream.Output->writeBytes(0, Data)); + + // Then we read back what we wrote, it should match the corresponding + // slice of the original input data. + ArrayRef Data2; + ASSERT_NO_ERROR(Stream.Output->readBytes(Offset, ExpectedSize, Data2)); + EXPECT_EQ(makeArrayRef(InputData).drop_front(Offset), Data2); + } + + std::vector BigData = {0, 1, 2, 3, 4}; + // 2. If the write is too big, it should fail. + EXPECT_ERROR(Stream.Output->writeBytes(3, BigData)); + } +} + +// Test that FixedStreamArray works correctly. +TEST_F(BinaryStreamTest, FixedStreamArray) { + std::vector Ints = {90823, 12908, 109823, 209823}; + ArrayRef IntBytes(reinterpret_cast(Ints.data()), + Ints.size() * sizeof(uint32_t)); + + initializeInput(IntBytes, alignof(uint32_t)); + + for (auto &Stream : Streams) { + MutableArrayRef Buffer; + ASSERT_EQ(InputData.size(), Stream.Input->getLength()); + + FixedStreamArray Array(*Stream.Input); + auto Iter = Array.begin(); + ASSERT_EQ(Ints[0], *Iter++); + ASSERT_EQ(Ints[1], *Iter++); + ASSERT_EQ(Ints[2], *Iter++); + ASSERT_EQ(Ints[3], *Iter++); + ASSERT_EQ(Array.end(), Iter); + } +} + +// Test that VarStreamArray works correctly. +TEST_F(BinaryStreamTest, VarStreamArray) { + StringLiteral Strings("1. Test2. Longer Test3. Really Long Test4. Super " + "Extra Longest Test Of All"); + ArrayRef StringBytes( + reinterpret_cast(Strings.data()), Strings.size()); + initializeInput(StringBytes, 1); + + struct StringExtractor { + public: + Error operator()(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item) { + if (Index == 0) + Len = strlen("1. Test"); + else if (Index == 1) + Len = strlen("2. Longer Test"); + else if (Index == 2) + Len = strlen("3. Really Long Test"); + else + Len = strlen("4. Super Extra Longest Test Of All"); + ArrayRef Bytes; + if (auto EC = Stream.readBytes(0, Len, Bytes)) + return EC; + Item = + StringRef(reinterpret_cast(Bytes.data()), Bytes.size()); + ++Index; + return Error::success(); + } + + private: + uint32_t Index = 0; + }; + + for (auto &Stream : Streams) { + VarStreamArray Array(*Stream.Input); + auto Iter = Array.begin(); + ASSERT_EQ("1. Test", *Iter++); + ASSERT_EQ("2. Longer Test", *Iter++); + ASSERT_EQ("3. Really Long Test", *Iter++); + ASSERT_EQ("4. Super Extra Longest Test Of All", *Iter++); + ASSERT_EQ(Array.end(), Iter); + } +} + +TEST_F(BinaryStreamTest, StreamReaderBounds) { + std::vector Bytes; + + initializeInput(Bytes, 1); + for (auto &Stream : Streams) { + StringRef S; + BinaryStreamReader Reader(*Stream.Input); + EXPECT_EQ(0U, Reader.bytesRemaining()); + EXPECT_ERROR(Reader.readFixedString(S, 1)); + } + + Bytes.resize(5); + initializeInput(Bytes, 1); + for (auto &Stream : Streams) { + StringRef S; + BinaryStreamReader Reader(*Stream.Input); + EXPECT_EQ(Bytes.size(), Reader.bytesRemaining()); + EXPECT_NO_ERROR(Reader.readFixedString(S, 5)); + EXPECT_ERROR(Reader.readFixedString(S, 6)); + } +} + +TEST_F(BinaryStreamTest, StreamReaderIntegers) { + support::ulittle64_t Little{908234}; + support::ubig32_t Big{28907823}; + short NS = 2897; + int NI = -89723; + unsigned long NUL = 902309023UL; + constexpr uint32_t Size = + sizeof(Little) + sizeof(Big) + sizeof(NS) + sizeof(NI) + sizeof(NUL); + + initializeOutput(Size, alignof(support::ulittle64_t)); + initializeInputFromOutput(alignof(support::ulittle64_t)); + + for (auto &Stream : Streams) { + BinaryStreamWriter Writer(*Stream.Output); + ASSERT_NO_ERROR(Writer.writeObject(Little)); + ASSERT_NO_ERROR(Writer.writeObject(Big)); + ASSERT_NO_ERROR(Writer.writeInteger(NS)); + ASSERT_NO_ERROR(Writer.writeInteger(NI)); + ASSERT_NO_ERROR(Writer.writeInteger(NUL)); + + const support::ulittle64_t *Little2; + const support::ubig32_t *Big2; + short NS2; + int NI2; + unsigned long NUL2; + + // 1. Reading fields individually. + BinaryStreamReader Reader(*Stream.Input); + ASSERT_NO_ERROR(Reader.readObject(Little2)); + ASSERT_NO_ERROR(Reader.readObject(Big2)); + ASSERT_NO_ERROR(Reader.readInteger(NS2)); + ASSERT_NO_ERROR(Reader.readInteger(NI2)); + ASSERT_NO_ERROR(Reader.readInteger(NUL2)); + ASSERT_EQ(0U, Reader.bytesRemaining()); + + EXPECT_EQ(Little, *Little2); + EXPECT_EQ(Big, *Big2); + EXPECT_EQ(NS, NS2); + EXPECT_EQ(NI, NI2); + EXPECT_EQ(NUL, NUL2); + } +} + +TEST_F(BinaryStreamTest, StreamReaderIntegerArray) { + // 1. Arrays of integers + std::vector Ints = {1, 2, 3, 4, 5}; + ArrayRef IntBytes(reinterpret_cast(&Ints[0]), + Ints.size() * sizeof(int)); + + initializeInput(IntBytes, alignof(int)); + for (auto &Stream : Streams) { + BinaryStreamReader Reader(*Stream.Input); + ArrayRef IntsRef; + ASSERT_NO_ERROR(Reader.readArray(IntsRef, Ints.size())); + ASSERT_EQ(0U, Reader.bytesRemaining()); + EXPECT_EQ(makeArrayRef(Ints), IntsRef); + + Reader.setOffset(0); + FixedStreamArray FixedIntsRef; + ASSERT_NO_ERROR(Reader.readArray(FixedIntsRef, Ints.size())); + ASSERT_EQ(0U, Reader.bytesRemaining()); + ASSERT_EQ(Ints, std::vector(FixedIntsRef.begin(), FixedIntsRef.end())); + } +} + +TEST_F(BinaryStreamTest, StreamReaderEnum) { + enum class MyEnum : int64_t { Foo = -10, Bar = 0, Baz = 10 }; + + std::vector Enums = {MyEnum::Bar, MyEnum::Baz, MyEnum::Foo}; + + initializeOutput(Enums.size() * sizeof(MyEnum), alignof(MyEnum)); + initializeInputFromOutput(alignof(MyEnum)); + for (auto &Stream : Streams) { + BinaryStreamWriter Writer(*Stream.Output); + for (auto Value : Enums) + ASSERT_NO_ERROR(Writer.writeEnum(Value)); + + BinaryStreamReader Reader(*Stream.Input); + + ArrayRef Array; + FixedStreamArray FSA; + + for (size_t I = 0; I < Enums.size(); ++I) { + MyEnum Value; + ASSERT_NO_ERROR(Reader.readEnum(Value)); + EXPECT_EQ(Enums[I], Value); + } + ASSERT_EQ(0U, Reader.bytesRemaining()); + } +} + +TEST_F(BinaryStreamTest, StreamReaderObject) { + struct Foo { + int X; + double Y; + char Z; + + bool operator==(const Foo &Other) const { + return X == Other.X && Y == Other.Y && Z == Other.Z; + } + }; + + std::vector Foos; + Foos.push_back({-42, 42.42, 42}); + Foos.push_back({100, 3.1415, static_cast(-89)}); + Foos.push_back({200, 2.718, static_cast(-12) }); + + const uint8_t *Bytes = reinterpret_cast(&Foos[0]); + + initializeInput(makeArrayRef(Bytes, 3 * sizeof(Foo)), alignof(Foo)); + + for (auto &Stream : Streams) { + // 1. Reading object pointers. + BinaryStreamReader Reader(*Stream.Input); + const Foo *FPtrOut = nullptr; + const Foo *GPtrOut = nullptr; + const Foo *HPtrOut = nullptr; + ASSERT_NO_ERROR(Reader.readObject(FPtrOut)); + ASSERT_NO_ERROR(Reader.readObject(GPtrOut)); + ASSERT_NO_ERROR(Reader.readObject(HPtrOut)); + EXPECT_EQ(0U, Reader.bytesRemaining()); + EXPECT_EQ(Foos[0], *FPtrOut); + EXPECT_EQ(Foos[1], *GPtrOut); + EXPECT_EQ(Foos[2], *HPtrOut); + } +} + +TEST_F(BinaryStreamTest, StreamReaderStrings) { + std::vector Bytes = {'O', 'n', 'e', '\0', 'T', 'w', 'o', + '\0', 'T', 'h', 'r', 'e', 'e', '\0', + 'F', 'o', 'u', 'r', '\0'}; + initializeInput(Bytes, 1); + + for (auto &Stream : Streams) { + BinaryStreamReader Reader(*Stream.Input); + + StringRef S1; + StringRef S2; + StringRef S3; + StringRef S4; + ASSERT_NO_ERROR(Reader.readCString(S1)); + ASSERT_NO_ERROR(Reader.readCString(S2)); + ASSERT_NO_ERROR(Reader.readCString(S3)); + ASSERT_NO_ERROR(Reader.readCString(S4)); + ASSERT_EQ(0U, Reader.bytesRemaining()); + + EXPECT_EQ("One", S1); + EXPECT_EQ("Two", S2); + EXPECT_EQ("Three", S3); + EXPECT_EQ("Four", S4); + + S1 = S2 = S3 = S4 = ""; + Reader.setOffset(0); + ASSERT_NO_ERROR(Reader.readFixedString(S1, 3)); + ASSERT_NO_ERROR(Reader.skip(1)); + ASSERT_NO_ERROR(Reader.readFixedString(S2, 3)); + ASSERT_NO_ERROR(Reader.skip(1)); + ASSERT_NO_ERROR(Reader.readFixedString(S3, 5)); + ASSERT_NO_ERROR(Reader.skip(1)); + ASSERT_NO_ERROR(Reader.readFixedString(S4, 4)); + ASSERT_NO_ERROR(Reader.skip(1)); + ASSERT_EQ(0U, Reader.bytesRemaining()); + + EXPECT_EQ("One", S1); + EXPECT_EQ("Two", S2); + EXPECT_EQ("Three", S3); + EXPECT_EQ("Four", S4); + } +} + +TEST_F(BinaryStreamTest, StreamWriterBounds) { + initializeOutput(5, 1); + + for (auto &Stream : Streams) { + BinaryStreamWriter Writer(*Stream.Output); + + // 1. Can write a string that exactly fills the buffer. + EXPECT_EQ(5U, Writer.bytesRemaining()); + EXPECT_NO_ERROR(Writer.writeFixedString("abcde")); + EXPECT_EQ(0U, Writer.bytesRemaining()); + + // 2. Can write an empty string even when you're full + EXPECT_NO_ERROR(Writer.writeFixedString("")); + EXPECT_ERROR(Writer.writeFixedString("a")); + + // 3. Can't write a string that is one character too long. + Writer.setOffset(0); + EXPECT_ERROR(Writer.writeFixedString("abcdef")); + } +} + +TEST_F(BinaryStreamTest, StreamWriterIntegerArrays) { + // 3. Arrays of integers + std::vector SourceInts = {1, 2, 3, 4, 5}; + ArrayRef SourceBytes(reinterpret_cast(&SourceInts[0]), + SourceInts.size() * sizeof(int)); + + initializeInput(SourceBytes, alignof(int)); + initializeOutputFromInput(alignof(int)); + + for (auto &Stream : Streams) { + BinaryStreamReader Reader(*Stream.Input); + BinaryStreamWriter Writer(*Stream.Output); + ArrayRef Ints; + ArrayRef Ints2; + // First read them, then write them, then read them back. + ASSERT_NO_ERROR(Reader.readArray(Ints, SourceInts.size())); + ASSERT_NO_ERROR(Writer.writeArray(Ints)); + + BinaryStreamReader ReaderBacker(*Stream.Output); + ASSERT_NO_ERROR(ReaderBacker.readArray(Ints2, SourceInts.size())); + + EXPECT_EQ(makeArrayRef(SourceInts), Ints2); + } +} + +TEST_F(BinaryStreamTest, StringWriterStrings) { + StringRef Strings[] = {"First", "Second", "Third", "Fourth"}; + + size_t Length = 0; + for (auto S : Strings) + Length += S.size() + 1; + initializeOutput(Length, 1); + initializeInputFromOutput(1); + + for (auto &Stream : Streams) { + BinaryStreamWriter Writer(*Stream.Output); + for (auto S : Strings) + ASSERT_NO_ERROR(Writer.writeCString(S)); + std::vector InStrings; + BinaryStreamReader Reader(*Stream.Input); + while (!Reader.empty()) { + StringRef S; + ASSERT_NO_ERROR(Reader.readCString(S)); + InStrings.push_back(S); + } + EXPECT_EQ(makeArrayRef(Strings), makeArrayRef(InStrings)); + } +} +} + +namespace { +struct BinaryItemStreamObject { + explicit BinaryItemStreamObject(ArrayRef Bytes) : Bytes(Bytes) {} + + ArrayRef Bytes; +}; +} + +namespace llvm { +template <> struct BinaryItemTraits { + static size_t length(const BinaryItemStreamObject &Item) { + return Item.Bytes.size(); + } + + static ArrayRef bytes(const BinaryItemStreamObject &Item) { + return Item.Bytes; + } +}; +} + +namespace { + +TEST_F(BinaryStreamTest, BinaryItemStream) { + std::vector Objects; + + struct Foo { + int X; + double Y; + }; + std::vector Foos = {{1, 1.0}, {2, 2.0}, {3, 3.0}}; + BumpPtrAllocator Allocator; + for (const auto &F : Foos) { + uint8_t *Ptr = Allocator.Allocate(sizeof(Foo)); + MutableArrayRef Buffer(Ptr, sizeof(Foo)); + MutableBinaryByteStream Stream(Buffer, llvm::support::big); + BinaryStreamWriter Writer(Stream); + ASSERT_NO_ERROR(Writer.writeObject(F)); + Objects.push_back(BinaryItemStreamObject(Buffer)); + } + + BinaryItemStream ItemStream(big); + ItemStream.setItems(Objects); + BinaryStreamReader Reader(ItemStream); + + for (const auto &F : Foos) { + const Foo *F2; + ASSERT_NO_ERROR(Reader.readObject(F2)); + + EXPECT_EQ(F.X, F2->X); + EXPECT_DOUBLE_EQ(F.Y, F2->Y); + } +} + +} // end anonymous namespace Index: llvm/trunk/unittests/Support/CMakeLists.txt =================================================================== --- llvm/trunk/unittests/Support/CMakeLists.txt +++ llvm/trunk/unittests/Support/CMakeLists.txt @@ -7,6 +7,7 @@ AllocatorTest.cpp ARMAttributeParser.cpp ArrayRecyclerTest.cpp + BinaryStreamTest.cpp BlockFrequencyTest.cpp BranchProbabilityTest.cpp Casting.cpp