Index: lld/COFF/PDB.cpp =================================================================== --- lld/COFF/PDB.cpp +++ lld/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/ByteStream.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" @@ -93,9 +93,9 @@ if (Data.empty()) continue; - msf::ByteStream Stream(Data); + BinaryByteStream Stream(Data); codeview::CVTypeArray Types; - msf::StreamReader Reader(Stream); + BinaryStreamReader Reader(Stream); // Follow type servers. If the same type server is encountered more than // once for this instance of `PDBTypeServerHandler` (for example if many // object files reference the same TypeServer), the types from the @@ -137,9 +137,9 @@ if (Data.empty()) return; - msf::ByteStream Stream(Data); + BinaryByteStream Stream(Data); CVSymbolArray Symbols; - msf::StreamReader Reader(Stream); + BinaryStreamReader Reader(Stream); if (auto EC = Reader.readArray(Symbols, Reader.getLength())) fatal(EC, "StreamReader.readArray failed"); @@ -161,9 +161,9 @@ static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, ArrayRef Data) { - msf::ByteStream Stream(Data); + BinaryByteStream Stream(Data); codeview::CVTypeArray Records; - msf::StreamReader Reader(Stream); + BinaryStreamReader Reader(Stream); if (auto EC = Reader.readArray(Records, Reader.getLength())) fatal(EC, "Reader.readArray failed"); for (const codeview::CVType &Rec : Records) Index: llvm/include/llvm/ADT/ArrayRef.h =================================================================== --- llvm/include/llvm/ADT/ArrayRef.h +++ llvm/include/llvm/ADT/ArrayRef.h @@ -471,6 +471,12 @@ return Vec; } + /// Construct an ArrayRef from an iterator_range. + template + ArrayRef makeArrayRef(const iterator_range &Range) { + return makeArrayRef(Range.begin(), Range.end()); + } + /// Construct an ArrayRef from an ArrayRef (no-op) (const) template ArrayRef makeArrayRef(const ArrayRef &Vec) { return Vec; Index: llvm/include/llvm/DebugInfo/CodeView/CVRecord.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/CVRecord.h +++ llvm/include/llvm/DebugInfo/CodeView/CVRecord.h @@ -14,8 +14,9 @@ #include "llvm/ADT/Optional.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamRef.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 @@ -48,15 +49,13 @@ } // end namespace codeview -namespace msf { - template struct VarStreamArrayExtractor> { - Error operator()(ReadableStreamRef Stream, uint32_t &Len, + Error operator()(BinaryStreamRef Stream, uint32_t &Len, codeview::CVRecord &Item) const { using namespace codeview; const RecordPrefix *Prefix = nullptr; - StreamReader Reader(Stream); + BinaryStreamReader Reader(Stream, llvm::support::little); uint32_t Offset = Reader.getOffset(); if (auto EC = Reader.readObject(Prefix)) @@ -76,8 +75,6 @@ } }; -} // end namespace msf - } // end namespace llvm #endif // LLVM_DEBUGINFO_CODEVIEW_RECORDITERATOR_H Index: llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h +++ llvm/include/llvm/DebugInfo/CodeView/CVTypeVisitor.h @@ -34,7 +34,7 @@ Error visitTypeStream(CVTypeRange Types); Error visitFieldListMemberStream(ArrayRef FieldList); - Error visitFieldListMemberStream(msf::StreamReader Reader); + Error visitFieldListMemberStream(BinaryStreamReader Reader); private: /// The interface to the class that gets notified of each visitation. Index: llvm/include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/CodeViewRecordIO.h +++ llvm/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/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Error.h" #include #include @@ -33,8 +33,8 @@ } public: - explicit CodeViewRecordIO(msf::StreamReader &Reader) : Reader(&Reader) {} - explicit CodeViewRecordIO(msf::StreamWriter &Writer) : Writer(&Writer) {} + explicit CodeViewRecordIO(BinaryStreamReader &Reader) : Reader(&Reader) {} + explicit CodeViewRecordIO(BinaryStreamWriter &Writer) : Writer(&Writer) {} Error beginRecord(Optional MaxLength); Error endRecord(); @@ -59,9 +59,9 @@ template Error mapInteger(T &Value) { if (isWriting()) - return Writer->writeInteger(Value, llvm::support::little); + return Writer->writeInteger(Value); - return Reader->readInteger(Value, llvm::support::little); + return Reader->readInteger(Value); } template Error mapEnum(T &Value) { @@ -93,7 +93,7 @@ SizeType Size; if (isWriting()) { Size = static_cast(Items.size()); - if (auto EC = Writer->writeInteger(Size, llvm::support::little)) + if (auto EC = Writer->writeInteger(Size)) return EC; for (auto &X : Items) { @@ -101,7 +101,7 @@ return EC; } } else { - if (auto EC = Reader->readInteger(Size, llvm::support::little)) + if (auto EC = Reader->readInteger(Size)) return EC; for (SizeType I = 0; I < Size; ++I) { typename T::value_type Item; @@ -160,8 +160,8 @@ SmallVector Limits; - msf::StreamReader *Reader = nullptr; - msf::StreamWriter *Writer = nullptr; + BinaryStreamReader *Reader = nullptr; + BinaryStreamWriter *Writer = nullptr; }; } // end namespace codeview Index: llvm/include/llvm/DebugInfo/CodeView/ModuleSubstream.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/ModuleSubstream.h +++ llvm/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/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -59,23 +59,22 @@ class ModuleSubstream { public: ModuleSubstream(); - ModuleSubstream(ModuleSubstreamKind Kind, msf::ReadableStreamRef Data); - static Error initialize(msf::ReadableStreamRef Stream, ModuleSubstream &Info); + ModuleSubstream(ModuleSubstreamKind Kind, BinaryStreamRef Data); + static Error initialize(BinaryStreamRef Stream, ModuleSubstream &Info); uint32_t getRecordLength() const; ModuleSubstreamKind getSubstreamKind() const; - msf::ReadableStreamRef getRecordData() const; + BinaryStreamRef getRecordData() const; private: ModuleSubstreamKind Kind; - msf::ReadableStreamRef Data; + BinaryStreamRef Data; }; -typedef msf::VarStreamArray ModuleSubstreamArray; +typedef VarStreamArray ModuleSubstreamArray; } // namespace codeview -namespace msf { template <> struct VarStreamArrayExtractor { - Error operator()(ReadableStreamRef Stream, uint32_t &Length, + Error operator()(BinaryStreamRef Stream, uint32_t &Length, codeview::ModuleSubstream &Info) const { if (auto EC = codeview::ModuleSubstream::initialize(Stream, Info)) return EC; @@ -83,7 +82,6 @@ return Error::success(); } }; -} // namespace msf } // namespace llvm #endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAM_H Index: llvm/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h +++ llvm/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/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamRef.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 @@ -28,8 +28,8 @@ struct LineColumnEntry { support::ulittle32_t NameIndex; - msf::FixedStreamArray LineNumbers; - msf::FixedStreamArray Columns; + FixedStreamArray LineNumbers; + FixedStreamArray Columns; }; struct FileChecksumEntry { @@ -38,49 +38,47 @@ ArrayRef Checksum; // The bytes of the checksum. }; -typedef msf::VarStreamArray LineInfoArray; -typedef msf::VarStreamArray FileChecksumArray; +typedef VarStreamArray LineInfoArray; +typedef VarStreamArray FileChecksumArray; class IModuleSubstreamVisitor { public: virtual ~IModuleSubstreamVisitor() = default; virtual Error visitUnknown(ModuleSubstreamKind Kind, - msf::ReadableStreamRef Data) = 0; - virtual Error visitSymbols(msf::ReadableStreamRef Data); - virtual Error visitLines(msf::ReadableStreamRef Data, + BinaryStreamRef Data) = 0; + virtual Error visitSymbols(BinaryStreamRef Data); + virtual Error visitLines(BinaryStreamRef Data, const LineSubstreamHeader *Header, const LineInfoArray &Lines); - virtual Error visitStringTable(msf::ReadableStreamRef Data); - virtual Error visitFileChecksums(msf::ReadableStreamRef Data, + virtual Error visitStringTable(BinaryStreamRef Data); + virtual Error visitFileChecksums(BinaryStreamRef Data, const FileChecksumArray &Checksums); - virtual Error visitFrameData(msf::ReadableStreamRef Data); - virtual Error visitInlineeLines(msf::ReadableStreamRef Data); - virtual Error visitCrossScopeImports(msf::ReadableStreamRef Data); - virtual Error visitCrossScopeExports(msf::ReadableStreamRef Data); - virtual Error visitILLines(msf::ReadableStreamRef Data); - virtual Error visitFuncMDTokenMap(msf::ReadableStreamRef Data); - virtual Error visitTypeMDTokenMap(msf::ReadableStreamRef Data); - virtual Error visitMergedAssemblyInput(msf::ReadableStreamRef Data); - virtual Error visitCoffSymbolRVA(msf::ReadableStreamRef Data); + virtual Error visitFrameData(BinaryStreamRef Data); + virtual Error visitInlineeLines(BinaryStreamRef Data); + virtual Error visitCrossScopeImports(BinaryStreamRef Data); + virtual Error visitCrossScopeExports(BinaryStreamRef Data); + virtual Error visitILLines(BinaryStreamRef Data); + virtual Error visitFuncMDTokenMap(BinaryStreamRef Data); + virtual Error visitTypeMDTokenMap(BinaryStreamRef Data); + virtual Error visitMergedAssemblyInput(BinaryStreamRef Data); + virtual Error visitCoffSymbolRVA(BinaryStreamRef Data); }; Error visitModuleSubstream(const ModuleSubstream &R, IModuleSubstreamVisitor &V); } // end namespace codeview -namespace msf { - template <> class VarStreamArrayExtractor { public: VarStreamArrayExtractor(const codeview::LineSubstreamHeader *Header) : Header(Header) {} - Error operator()(ReadableStreamRef Stream, uint32_t &Len, + Error operator()(BinaryStreamRef Stream, uint32_t &Len, codeview::LineColumnEntry &Item) const { using namespace codeview; const LineFileBlockHeader *BlockHeader; - StreamReader Reader(Stream); + BinaryStreamReader Reader(Stream, llvm::support::little); if (auto EC = Reader.readObject(BlockHeader)) return EC; bool HasColumn = Header->Flags & LineFlags::HaveColumns; @@ -113,11 +111,11 @@ template <> class VarStreamArrayExtractor { public: - Error operator()(ReadableStreamRef Stream, uint32_t &Len, + Error operator()(BinaryStreamRef Stream, uint32_t &Len, codeview::FileChecksumEntry &Item) const { using namespace codeview; const FileChecksum *Header; - StreamReader Reader(Stream); + BinaryStreamReader Reader(Stream, llvm::support::little); if (auto EC = Reader.readObject(Header)) return EC; Item.FileNameOffset = Header->FileNameOffset; @@ -129,8 +127,6 @@ } }; -} // end namespace msf - } // end namespace llvm #endif // LLVM_DEBUGINFO_CODEVIEW_MODULESUBSTREAMVISITOR_H Index: llvm/include/llvm/DebugInfo/CodeView/RecordSerialization.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/RecordSerialization.h +++ llvm/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/StreamReader.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include @@ -41,37 +41,37 @@ StringRef getBytesAsCharacters(ArrayRef LeafData); StringRef getBytesAsCString(ArrayRef LeafData); -inline Error consume(msf::StreamReader &Reader) { return Error::success(); } +inline Error consume(BinaryStreamReader &Reader) { return Error::success(); } /// Decodes a numeric "leaf" value. These are integer literals encountered in /// the type stream. If the value is positive and less than LF_NUMERIC (1 << /// 15), it is emitted directly in Data. Otherwise, it has a tag like LF_CHAR /// that indicates the bitwidth and sign of the numeric data. -Error consume(msf::StreamReader &Reader, APSInt &Num); +Error consume(BinaryStreamReader &Reader, APSInt &Num); /// Decodes a numeric leaf value that is known to be a particular type. -Error consume_numeric(msf::StreamReader &Reader, uint64_t &Value); +Error consume_numeric(BinaryStreamReader &Reader, uint64_t &Value); /// Decodes signed and unsigned fixed-length integers. -Error consume(msf::StreamReader &Reader, uint32_t &Item); -Error consume(msf::StreamReader &Reader, int32_t &Item); +Error consume(BinaryStreamReader &Reader, uint32_t &Item); +Error consume(BinaryStreamReader &Reader, int32_t &Item); /// Decodes a null terminated string. -Error consume(msf::StreamReader &Reader, StringRef &Item); +Error consume(BinaryStreamReader &Reader, StringRef &Item); Error consume(StringRef &Data, APSInt &Num); Error consume(StringRef &Data, uint32_t &Item); /// Decodes an arbitrary object whose layout matches that of the underlying /// byte sequence, and returns a pointer to the object. -template Error consume(msf::StreamReader &Reader, T *&Item) { +template Error consume(BinaryStreamReader &Reader, T *&Item) { return Reader.readObject(Item); } template struct serialize_conditional_impl { serialize_conditional_impl(T &Item, U Func) : Item(Item), Func(Func) {} - Error deserialize(msf::StreamReader &Reader) const { + Error deserialize(BinaryStreamReader &Reader) const { if (!Func()) return Error::success(); return consume(Reader, Item); @@ -89,7 +89,7 @@ template struct serialize_array_impl { serialize_array_impl(ArrayRef &Item, U Func) : Item(Item), Func(Func) {} - Error deserialize(msf::StreamReader &Reader) const { + Error deserialize(BinaryStreamReader &Reader) const { return Reader.readArray(Item, Func()); } @@ -100,7 +100,7 @@ template struct serialize_vector_tail_impl { serialize_vector_tail_impl(std::vector &Item) : Item(Item) {} - Error deserialize(msf::StreamReader &Reader) const { + Error deserialize(BinaryStreamReader &Reader) const { T Field; // Stop when we run out of bytes or we hit record padding bytes. while (!Reader.empty() && Reader.peek() < LF_PAD0) { @@ -118,7 +118,7 @@ serialize_null_term_string_array_impl(std::vector &Item) : Item(Item) {} - Error deserialize(msf::StreamReader &Reader) const { + Error deserialize(BinaryStreamReader &Reader) const { if (Reader.empty()) return make_error(cv_error_code::insufficient_buffer, "Null terminated string is empty!"); @@ -138,7 +138,7 @@ template struct serialize_arrayref_tail_impl { serialize_arrayref_tail_impl(ArrayRef &Item) : Item(Item) {} - Error deserialize(msf::StreamReader &Reader) const { + Error deserialize(BinaryStreamReader &Reader) const { uint32_t Count = Reader.bytesRemaining() / sizeof(T); return Reader.readArray(Item, Count); } @@ -149,7 +149,7 @@ template struct serialize_numeric_impl { serialize_numeric_impl(T &Item) : Item(Item) {} - Error deserialize(msf::StreamReader &Reader) const { + Error deserialize(BinaryStreamReader &Reader) const { return consume_numeric(Reader, Item); } @@ -201,42 +201,42 @@ #define CV_NUMERIC_FIELD(I) serialize_numeric(I) template -Error consume(msf::StreamReader &Reader, +Error consume(BinaryStreamReader &Reader, const serialize_conditional_impl &Item) { return Item.deserialize(Reader); } template -Error consume(msf::StreamReader &Reader, +Error consume(BinaryStreamReader &Reader, const serialize_array_impl &Item) { return Item.deserialize(Reader); } -inline Error consume(msf::StreamReader &Reader, +inline Error consume(BinaryStreamReader &Reader, const serialize_null_term_string_array_impl &Item) { return Item.deserialize(Reader); } template -Error consume(msf::StreamReader &Reader, +Error consume(BinaryStreamReader &Reader, const serialize_vector_tail_impl &Item) { return Item.deserialize(Reader); } template -Error consume(msf::StreamReader &Reader, +Error consume(BinaryStreamReader &Reader, const serialize_arrayref_tail_impl &Item) { return Item.deserialize(Reader); } template -Error consume(msf::StreamReader &Reader, +Error consume(BinaryStreamReader &Reader, const serialize_numeric_impl &Item) { return Item.deserialize(Reader); } template -Error consume(msf::StreamReader &Reader, T &&X, U &&Y, Args &&... Rest) { +Error consume(BinaryStreamReader &Reader, T &&X, U &&Y, Args &&... Rest) { if (auto EC = consume(Reader, X)) return EC; return consume(Reader, Y, std::forward(Rest)...); Index: llvm/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h +++ llvm/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/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" namespace llvm { @@ -25,10 +25,11 @@ class SymbolDeserializer : public SymbolVisitorCallbacks { struct MappingInfo { explicit MappingInfo(ArrayRef RecordData) - : Stream(RecordData), Reader(Stream), Mapping(Reader) {} + : Stream(RecordData), Reader(Stream, llvm::support::little), + Mapping(Reader) {} - msf::ByteStream Stream; - msf::StreamReader Reader; + BinaryByteStream Stream; + BinaryStreamReader Reader; SymbolRecordMapping Mapping; }; Index: llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h +++ llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h @@ -13,13 +13,13 @@ #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" -#include "llvm/ADT/iterator_range.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include @@ -938,7 +938,7 @@ }; typedef CVRecord CVSymbol; -typedef msf::VarStreamArray CVSymbolArray; +typedef VarStreamArray CVSymbolArray; } // end namespace codeview } // end namespace llvm Index: llvm/include/llvm/DebugInfo/CodeView/SymbolRecordMapping.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/SymbolRecordMapping.h +++ llvm/include/llvm/DebugInfo/CodeView/SymbolRecordMapping.h @@ -14,16 +14,14 @@ #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" namespace llvm { -namespace msf { -class StreamReader; -class StreamWriter; -} +class BinaryStreamReader; +class BinaryStreamWriter; namespace codeview { class SymbolRecordMapping : public SymbolVisitorCallbacks { public: - explicit SymbolRecordMapping(msf::StreamReader &Reader) : IO(Reader) {} - explicit SymbolRecordMapping(msf::StreamWriter &Writer) : IO(Writer) {} + explicit SymbolRecordMapping(BinaryStreamReader &Reader) : IO(Reader) {} + explicit SymbolRecordMapping(BinaryStreamWriter &Writer) : IO(Writer) {} Error visitSymbolBegin(CVSymbol &Record) override; Error visitSymbolEnd(CVSymbol &Record) override; Index: llvm/include/llvm/DebugInfo/CodeView/SymbolSerializer.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/SymbolSerializer.h +++ llvm/include/llvm/DebugInfo/CodeView/SymbolSerializer.h @@ -12,8 +12,6 @@ #include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h" #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" @@ -21,6 +19,8 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Error.h" namespace llvm { @@ -28,7 +28,7 @@ class SymbolSerializer : public SymbolVisitorCallbacks { uint32_t RecordStart = 0; - msf::StreamWriter &Writer; + BinaryStreamWriter &Writer; SymbolRecordMapping Mapping; Optional CurrentSymbol; @@ -42,7 +42,7 @@ } public: - explicit SymbolSerializer(msf::StreamWriter &Writer) + explicit SymbolSerializer(BinaryStreamWriter &Writer) : Writer(Writer), Mapping(Writer) {} virtual Error visitSymbolBegin(CVSymbol &Record) override { Index: llvm/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h +++ llvm/include/llvm/DebugInfo/CodeView/SymbolVisitorDelegate.h @@ -15,9 +15,7 @@ namespace llvm { -namespace msf { -class StreamReader; -} // end namespace msf +class BinaryStreamReader; namespace codeview { @@ -25,7 +23,7 @@ public: virtual ~SymbolVisitorDelegate() = default; - virtual uint32_t getRecordOffset(msf::StreamReader Reader) = 0; + virtual uint32_t getRecordOffset(BinaryStreamReader Reader) = 0; virtual StringRef getFileNameForFileOffset(uint32_t FileOffset) = 0; virtual StringRef getStringTable() = 0; }; Index: llvm/include/llvm/DebugInfo/CodeView/TypeDeserializer.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/TypeDeserializer.h +++ llvm/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/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" #include #include @@ -29,10 +29,11 @@ class TypeDeserializer : public TypeVisitorCallbacks { struct MappingInfo { explicit MappingInfo(ArrayRef RecordData) - : Stream(RecordData), Reader(Stream), Mapping(Reader) {} + : Stream(RecordData), Reader(Stream, llvm::support::little), + Mapping(Reader) {} - msf::ByteStream Stream; - msf::StreamReader Reader; + BinaryByteStream Stream; + BinaryStreamReader Reader; TypeRecordMapping Mapping; }; @@ -72,16 +73,16 @@ class FieldListDeserializer : public TypeVisitorCallbacks { struct MappingInfo { - explicit MappingInfo(msf::StreamReader &R) + explicit MappingInfo(BinaryStreamReader &R) : Reader(R), Mapping(Reader), StartOffset(0) {} - msf::StreamReader &Reader; + BinaryStreamReader &Reader; TypeRecordMapping Mapping; uint32_t StartOffset; }; public: - explicit FieldListDeserializer(msf::StreamReader &Reader) : Mapping(Reader) { + explicit FieldListDeserializer(BinaryStreamReader &Reader) : Mapping(Reader) { CVType FieldList; FieldList.Type = TypeLeafKind::LF_FIELDLIST; consumeError(Mapping.Mapping.visitTypeBegin(FieldList)); Index: llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/TypeRecord.h +++ llvm/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/StreamArray.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Endian.h" #include #include @@ -26,9 +26,7 @@ namespace llvm { -namespace msf { -class StreamReader; -} // end namespace msf +class BinaryStreamReader; namespace codeview { @@ -42,7 +40,7 @@ TypeLeafKind Kind; ArrayRef Data; }; -typedef msf::VarStreamArray CVTypeArray; +typedef VarStreamArray CVTypeArray; typedef iterator_range CVTypeRange; /// Equvalent to CV_fldattr_t in cvinfo.h. Index: llvm/include/llvm/DebugInfo/CodeView/TypeRecordMapping.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/TypeRecordMapping.h +++ llvm/include/llvm/DebugInfo/CodeView/TypeRecordMapping.h @@ -16,15 +16,14 @@ #include "llvm/Support/Error.h" namespace llvm { -namespace msf { -class StreamReader; -class StreamWriter; -} +class BinaryStreamReader; +class BinaryStreamWriter; + namespace codeview { class TypeRecordMapping : public TypeVisitorCallbacks { public: - explicit TypeRecordMapping(msf::StreamReader &Reader) : IO(Reader) {} - explicit TypeRecordMapping(msf::StreamWriter &Writer) : IO(Writer) {} + explicit TypeRecordMapping(BinaryStreamReader &Reader) : IO(Reader) {} + explicit TypeRecordMapping(BinaryStreamWriter &Writer) : IO(Writer) {} Error visitTypeBegin(CVType &Record) override; Error visitTypeEnd(CVType &Record) override; Index: llvm/include/llvm/DebugInfo/CodeView/TypeSerializer.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/TypeSerializer.h +++ llvm/include/llvm/DebugInfo/CodeView/TypeSerializer.h @@ -12,14 +12,14 @@ #include "llvm/DebugInfo/CodeView/TypeRecordMapping.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamWriter.h" #include "llvm/Support/Error.h" namespace llvm { @@ -56,8 +56,8 @@ Optional TypeKind; Optional MemberKind; std::vector RecordBuffer; - msf::MutableByteStream Stream; - msf::StreamWriter Writer; + MutableBinaryByteStream Stream; + BinaryStreamWriter Writer; TypeRecordMapping Mapping; RecordList SeenRecords; @@ -109,7 +109,7 @@ Error visitKnownMemberImpl(CVMemberRecord &CVR, RecordType &Record) { assert(CVR.Kind == static_cast(Record.getKind())); - if (auto EC = Writer.writeEnum(CVR.Kind, llvm::support::little)) + if (auto EC = Writer.writeEnum(CVR.Kind)) return EC; if (auto EC = Mapping.visitKnownMember(CVR, Record)) Index: llvm/include/llvm/DebugInfo/MSF/ByteStream.h =================================================================== --- llvm/include/llvm/DebugInfo/MSF/ByteStream.h +++ /dev/null @@ -1,169 +0,0 @@ -//===- ByteStream.h - Reads stream data from a byte sequence ----*- 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_BYTESTREAM_H -#define LLVM_DEBUGINFO_MSF_BYTESTREAM_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/MemoryBuffer.h" -#include -#include -#include -#include - -namespace llvm { -namespace msf { - -class ByteStream : public ReadableStream { -public: - ByteStream() = default; - explicit ByteStream(ArrayRef Data) : Data(Data) {} - explicit ByteStream(StringRef Data) - : Data(Data.bytes_begin(), Data.bytes_end()) {} - - Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const override { - if (Offset > Data.size()) - return make_error(msf_error_code::insufficient_buffer); - if (Data.size() < Size + Offset) - return make_error(msf_error_code::insufficient_buffer); - Buffer = Data.slice(Offset, Size); - return Error::success(); - } - - Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) const override { - if (Offset >= Data.size()) - return make_error(msf_error_code::insufficient_buffer); - Buffer = Data.slice(Offset); - return Error::success(); - } - - uint32_t getLength() const 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: - ArrayRef Data; -}; - -// MemoryBufferByteStream behaves like a read-only ByteStream, but has its data -// backed by an llvm::MemoryBuffer. It also owns the underlying MemoryBuffer. -class MemoryBufferByteStream : public ByteStream { -public: - explicit MemoryBufferByteStream(std::unique_ptr Buffer) - : ByteStream(ArrayRef(Buffer->getBuffer().bytes_begin(), - Buffer->getBuffer().bytes_end())), - MemBuffer(std::move(Buffer)) {} - - std::unique_ptr MemBuffer; -}; - -class MutableByteStream : public WritableStream { -public: - MutableByteStream() = default; - explicit MutableByteStream(MutableArrayRef Data) - : Data(Data), ImmutableStream(Data) {} - - Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const override { - return ImmutableStream.readBytes(Offset, Size, Buffer); - } - - Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) const override { - return ImmutableStream.readLongestContiguousChunk(Offset, Buffer); - } - - uint32_t getLength() const override { return ImmutableStream.getLength(); } - - Error writeBytes(uint32_t Offset, ArrayRef Buffer) const override { - if (Buffer.empty()) - return Error::success(); - - if (Data.size() < Buffer.size()) - return make_error(msf_error_code::insufficient_buffer); - if (Offset > Buffer.size() - Data.size()) - return make_error(msf_error_code::insufficient_buffer); - - uint8_t *DataPtr = const_cast(Data.data()); - ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size()); - return Error::success(); - } - - Error commit() const override { return Error::success(); } - - MutableArrayRef data() const { return Data; } - -private: - MutableArrayRef Data; - ByteStream ImmutableStream; -}; - -// A simple adapter that acts like a ByteStream but holds ownership over -// and underlying FileOutputBuffer. -class FileBufferByteStream : public WritableStream { -private: - class StreamImpl : public MutableByteStream { - public: - StreamImpl(std::unique_ptr Buffer) - : MutableByteStream(MutableArrayRef(Buffer->getBufferStart(), - Buffer->getBufferEnd())), - FileBuffer(std::move(Buffer)) {} - - Error commit() const override { - if (FileBuffer->commit()) - return llvm::make_error(msf_error_code::not_writable); - return Error::success(); - } - - private: - std::unique_ptr FileBuffer; - }; - -public: - explicit FileBufferByteStream(std::unique_ptr Buffer) - : Impl(std::move(Buffer)) {} - - Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const override { - return Impl.readBytes(Offset, Size, Buffer); - } - - Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) const override { - return Impl.readLongestContiguousChunk(Offset, Buffer); - } - - uint32_t getLength() const override { return Impl.getLength(); } - - Error writeBytes(uint32_t Offset, ArrayRef Data) const override { - return Impl.writeBytes(Offset, Data); - } - - Error commit() const override { return Impl.commit(); } - -private: - StreamImpl Impl; -}; - -} // end namespace msf -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_BYTESTREAM_H Index: llvm/include/llvm/DebugInfo/MSF/MappedBlockStream.h =================================================================== --- llvm/include/llvm/DebugInfo/MSF/MappedBlockStream.h +++ llvm/include/llvm/DebugInfo/MSF/MappedBlockStream.h @@ -15,8 +15,9 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/MSF/MSFStreamLayout.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include @@ -37,29 +38,29 @@ /// the MSF. MappedBlockStream provides methods for reading from and writing /// to one of these streams transparently, as if it were a contiguous sequence /// of bytes. -class MappedBlockStream : public ReadableStream { +class MappedBlockStream : public BinaryStream { friend class WritableMappedBlockStream; public: static std::unique_ptr createStream(uint32_t BlockSize, uint32_t NumBlocks, - const MSFStreamLayout &Layout, const ReadableStream &MsfData); + const MSFStreamLayout &Layout, BinaryStreamRef MsfData); static std::unique_ptr - createIndexedStream(const MSFLayout &Layout, const ReadableStream &MsfData, + createIndexedStream(const MSFLayout &Layout, BinaryStreamRef MsfData, uint32_t StreamIndex); static std::unique_ptr - createFpmStream(const MSFLayout &Layout, const ReadableStream &MsfData); + createFpmStream(const MSFLayout &Layout, BinaryStreamRef MsfData); static std::unique_ptr - createDirectoryStream(const MSFLayout &Layout, const ReadableStream &MsfData); + createDirectoryStream(const MSFLayout &Layout, BinaryStreamRef MsfData); Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const override; + ArrayRef &Buffer) override; Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) const override; + ArrayRef &Buffer) override; - uint32_t getLength() const override; + uint32_t getLength() override; uint32_t getNumBytesCopied() const; @@ -74,51 +75,52 @@ protected: MappedBlockStream(uint32_t BlockSize, uint32_t NumBlocks, const MSFStreamLayout &StreamLayout, - const ReadableStream &MsfData); + BinaryStreamRef MsfData); private: const MSFStreamLayout &getStreamLayout() const { return StreamLayout; } void fixCacheAfterWrite(uint32_t Offset, ArrayRef Data) const; - Error readBytes(uint32_t Offset, MutableArrayRef Buffer) const; + Error readBytes(uint32_t Offset, MutableArrayRef Buffer); bool tryReadContiguously(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const; + ArrayRef &Buffer); const uint32_t BlockSize; const uint32_t NumBlocks; const MSFStreamLayout StreamLayout; - const ReadableStream &MsfData; + BinaryStreamRef MsfData; typedef MutableArrayRef CacheEntry; mutable llvm::BumpPtrAllocator Pool; mutable DenseMap> CacheMap; }; -class WritableMappedBlockStream : public WritableStream { +class WritableMappedBlockStream : public WritableBinaryStream { public: static std::unique_ptr createStream(uint32_t BlockSize, uint32_t NumBlocks, - const MSFStreamLayout &Layout, const WritableStream &MsfData); + const MSFStreamLayout &Layout, WritableBinaryStreamRef MsfData); static std::unique_ptr - createIndexedStream(const MSFLayout &Layout, const WritableStream &MsfData, + createIndexedStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData, uint32_t StreamIndex); static std::unique_ptr - createDirectoryStream(const MSFLayout &Layout, const WritableStream &MsfData); + createDirectoryStream(const MSFLayout &Layout, + WritableBinaryStreamRef MsfData); static std::unique_ptr - createFpmStream(const MSFLayout &Layout, const WritableStream &MsfData); + createFpmStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData); Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const override; + ArrayRef &Buffer) override; Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) const override; - uint32_t getLength() const override; + ArrayRef &Buffer) override; + uint32_t getLength() override; - Error writeBytes(uint32_t Offset, ArrayRef Buffer) const override; + Error writeBytes(uint32_t Offset, ArrayRef Buffer) override; - Error commit() const override; + Error commit() override; const MSFStreamLayout &getStreamLayout() const { return ReadInterface.getStreamLayout(); @@ -130,12 +132,12 @@ protected: WritableMappedBlockStream(uint32_t BlockSize, uint32_t NumBlocks, const MSFStreamLayout &StreamLayout, - const WritableStream &MsfData); + WritableBinaryStreamRef MsfData); private: MappedBlockStream ReadInterface; - const WritableStream &WriteInterface; + WritableBinaryStreamRef WriteInterface; }; } // end namespace pdb Index: llvm/include/llvm/DebugInfo/MSF/SequencedItemStream.h =================================================================== --- llvm/include/llvm/DebugInfo/MSF/SequencedItemStream.h +++ /dev/null @@ -1,93 +0,0 @@ -//===- SequencedItemStream.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_SEQUENCEDITEMSTREAM_H -#define LLVM_DEBUGINFO_MSF_SEQUENCEDITEMSTREAM_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" -#include "llvm/Support/Error.h" -#include -#include - -namespace llvm { -namespace msf { - -template struct SequencedItemTraits { - static size_t length(const T &Item) = delete; - static ArrayRef bytes(const T &Item) = delete; -}; - -/// SequencedItemStream represents a sequence of objects stored in a -/// standard 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 std::vector -/// of TPI records, where each record contains a byte sequence that -/// represents that one record serialized, but where each consecutive item -/// might not be allocated immediately after the previous item. Using a -/// SequencedItemStream, we can adapt the VarStreamArray class to trivially -/// extract one item at a time, allowing the data to be used anywhere a -/// VarStreamArray could be used. -template > -class SequencedItemStream : public ReadableStream { -public: - SequencedItemStream() = default; - - Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const override { - auto ExpectedIndex = translateOffsetIndex(Offset); - if (!ExpectedIndex) - return ExpectedIndex.takeError(); - const auto &Item = Items[*ExpectedIndex]; - if (Size > Traits::length(Item)) - return make_error(msf_error_code::insufficient_buffer); - Buffer = Traits::bytes(Item).take_front(Size); - return Error::success(); - } - - Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) const 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() const 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(msf_error_code::insufficient_buffer); - return CurrentIndex; - } - - ArrayRef Items; -}; - -} // end namespace msf -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_SEQUENCEDITEMSTREAM_H Index: llvm/include/llvm/DebugInfo/MSF/StreamArray.h =================================================================== --- llvm/include/llvm/DebugInfo/MSF/StreamArray.h +++ /dev/null @@ -1,304 +0,0 @@ -//===- StreamArray.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_STREAMARRAY_H -#define LLVM_DEBUGINFO_MSF_STREAMARRAY_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/iterator.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" -#include "llvm/Support/Error.h" -#include -#include - -namespace llvm { -namespace msf { - -/// VarStreamArrayExtractor is intended to be specialized to provide customized -/// extraction logic. On input it receives a StreamRef 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()(ReadableStreamRef 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 -/// 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, it expects you 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(ReadableStreamRef Stream) : Stream(Stream) {} - VarStreamArray(ReadableStreamRef 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; } - - ReadableStreamRef getUnderlyingStream() const { return Stream; } - -private: - ReadableStreamRef 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++() { - // 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; - ReadableStreamRef IterRef; - const ArrayType *Array{nullptr}; - uint32_t ThisLen{0}; - bool HasError{false}; - bool *HadError{nullptr}; - Extractor Extract; -}; - -template class FixedStreamArrayIterator; - -template class FixedStreamArray { - friend class FixedStreamArrayIterator; - -public: - FixedStreamArray() = default; - FixedStreamArray(ReadableStreamRef 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)); - } - 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()); - } - - ReadableStreamRef getUnderlyingStream() const { return Stream; } - -private: - ReadableStreamRef 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 msf -} // namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_STREAMARRAY_H Index: llvm/include/llvm/DebugInfo/MSF/StreamInterface.h =================================================================== --- llvm/include/llvm/DebugInfo/MSF/StreamInterface.h +++ /dev/null @@ -1,53 +0,0 @@ -//===- StreamInterface.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_STREAMINTERFACE_H -#define LLVM_DEBUGINFO_MSF_STREAMINTERFACE_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/Error.h" -#include - -namespace llvm { -namespace msf { - -class ReadableStream { -public: - virtual ~ReadableStream() = default; - - // Given an offset into the stream and a number of bytes, attempt to read - // the bytes and set the output ArrayRef to point to a reference into the - // stream, without copying any data. - virtual Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const = 0; - - // Given an offset into the stream, read as much as possible without copying - // any data. - virtual Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) const = 0; - - virtual uint32_t getLength() const = 0; -}; - -class WritableStream : public ReadableStream { -public: - ~WritableStream() override = default; - - // 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) const = 0; - - virtual Error commit() const = 0; -}; - -} // end namespace msf -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_STREAMINTERFACE_H Index: llvm/include/llvm/DebugInfo/MSF/StreamReader.h =================================================================== --- llvm/include/llvm/DebugInfo/MSF/StreamReader.h +++ /dev/null @@ -1,135 +0,0 @@ -//===- StreamReader.h - Reads bytes and objects from 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_STREAMREADER_H -#define LLVM_DEBUGINFO_MSF_STREAMREADER_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/type_traits.h" - -#include -#include - -namespace llvm { -namespace msf { - -class StreamReader { -public: - StreamReader(ReadableStreamRef Stream); - - Error readLongestContiguousChunk(ArrayRef &Buffer); - Error readBytes(ArrayRef &Buffer, uint32_t Size); - - template - Error readInteger(T &Dest, - llvm::support::endianness Endian = llvm::support::native) { - 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(), Endian); - return Error::success(); - } - - Error readZeroString(StringRef &Dest); - Error readFixedString(StringRef &Dest, uint32_t Length); - Error readStreamRef(ReadableStreamRef &Ref); - Error readStreamRef(ReadableStreamRef &Ref, uint32_t Length); - - template - Error readEnum(T &Dest, - llvm::support::endianness Endian = llvm::support::native) { - static_assert(std::is_enum::value, - "Cannot call readEnum with non-enum value!"); - typename std::underlying_type::type N; - if (auto EC = readInteger(N, Endian)) - return EC; - Dest = static_cast(N); - return Error::success(); - } - - 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(); - } - - 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(msf_error_code::insufficient_buffer); - - if (auto EC = readBytes(Bytes, NumElements * sizeof(T))) - return EC; - Array = ArrayRef(reinterpret_cast(Bytes.data()), NumElements); - return Error::success(); - } - - template - Error readArray(VarStreamArray &Array, uint32_t Size) { - ReadableStreamRef S; - if (auto EC = readStreamRef(S, Size)) - return EC; - Array = VarStreamArray(S, Array.getExtractor()); - return Error::success(); - } - - template - Error readArray(FixedStreamArray &Array, uint32_t NumItems) { - if (NumItems == 0) { - Array = FixedStreamArray(); - return Error::success(); - } - uint32_t Length = NumItems * sizeof(T); - if (Length / sizeof(T) != NumItems) - return make_error(msf_error_code::invalid_format); - if (Offset + Length > Stream.getLength()) - return make_error(msf_error_code::insufficient_buffer); - ReadableStreamRef View = Stream.slice(Offset, Length); - Array = FixedStreamArray(View); - Offset += Length; - 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(); } - - Error skip(uint32_t Amount); - - uint8_t peek() const; - -private: - ReadableStreamRef Stream; - uint32_t Offset; -}; -} // namespace msf -} // namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_STREAMREADER_H Index: llvm/include/llvm/DebugInfo/MSF/StreamRef.h =================================================================== --- llvm/include/llvm/DebugInfo/MSF/StreamRef.h +++ /dev/null @@ -1,135 +0,0 @@ -//===- StreamRef.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_STREAMREF_H -#define LLVM_DEBUGINFO_MSF_STREAMREF_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" -#include "llvm/Support/Error.h" -#include -#include - -namespace llvm { -namespace msf { - -template class StreamRefBase { -public: - StreamRefBase() : Stream(nullptr), ViewOffset(0), Length(0) {} - StreamRefBase(const StreamType &Stream, uint32_t Offset, uint32_t Length) - : Stream(&Stream), ViewOffset(Offset), Length(Length) {} - - uint32_t getLength() const { return Length; } - const StreamType *getStream() const { return Stream; } - - RefType drop_front(uint32_t N) const { - if (!Stream) - return RefType(); - - N = std::min(N, Length); - return RefType(*Stream, ViewOffset + N, Length - N); - } - - RefType keep_front(uint32_t N) const { - if (!Stream) - return RefType(); - N = std::min(N, Length); - return RefType(*Stream, ViewOffset, N); - } - - 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: - const StreamType *Stream; - uint32_t ViewOffset; - uint32_t Length; -}; - -class ReadableStreamRef - : public StreamRefBase { -public: - ReadableStreamRef() = default; - ReadableStreamRef(const ReadableStream &Stream) - : StreamRefBase(Stream, 0, Stream.getLength()) {} - ReadableStreamRef(const ReadableStream &Stream, uint32_t Offset, - uint32_t Length) - : StreamRefBase(Stream, Offset, Length) {} - - // Use StreamRef.slice() instead. - ReadableStreamRef(const ReadableStreamRef &S, uint32_t Offset, - uint32_t Length) = delete; - - Error readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const { - if (ViewOffset + Offset < Offset) - return make_error(msf_error_code::insufficient_buffer); - if (Size + Offset > Length) - return make_error(msf_error_code::insufficient_buffer); - return Stream->readBytes(ViewOffset + Offset, Size, Buffer); - } - - // Given an offset into the stream, read as much as possible without copying - // any data. - Error readLongestContiguousChunk(uint32_t Offset, - ArrayRef &Buffer) const { - if (Offset >= Length) - return make_error(msf_error_code::insufficient_buffer); - - if (auto EC = Stream->readLongestContiguousChunk(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 WritableStreamRef - : public StreamRefBase { -public: - WritableStreamRef() = default; - WritableStreamRef(const WritableStream &Stream) - : StreamRefBase(Stream, 0, Stream.getLength()) {} - WritableStreamRef(const WritableStream &Stream, uint32_t Offset, - uint32_t Length) - : StreamRefBase(Stream, Offset, Length) {} - - // Use StreamRef.slice() instead. - WritableStreamRef(const WritableStreamRef &S, uint32_t Offset, - uint32_t Length) = delete; - - Error writeBytes(uint32_t Offset, ArrayRef Data) const { - if (Data.size() + Offset > Length) - return make_error(msf_error_code::insufficient_buffer); - return Stream->writeBytes(ViewOffset + Offset, Data); - } - - Error commit() const { return Stream->commit(); } -}; - -} // end namespace msf -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_STREAMREF_H Index: llvm/include/llvm/DebugInfo/MSF/StreamWriter.h =================================================================== --- llvm/include/llvm/DebugInfo/MSF/StreamWriter.h +++ /dev/null @@ -1,102 +0,0 @@ -//===- StreamWriter.h - Writes bytes and objects 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_STREAMWRITER_H -#define LLVM_DEBUGINFO_MSF_STREAMWRITER_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/Error.h" -#include -#include - -namespace llvm { -namespace msf { - -class StreamWriter { -public: - StreamWriter() = default; - explicit StreamWriter(WritableStreamRef Stream); - - Error writeBytes(ArrayRef Buffer); - - template - Error writeInteger(T Value, - llvm::support::endianness Endian = llvm::support::native) { - static_assert(std::is_integral::value, - "Cannot call writeInteger with non-integral value!"); - uint8_t Buffer[sizeof(T)]; - llvm::support::endian::write(Buffer, Value, - Endian); - return writeBytes(Buffer); - } - - Error writeZeroString(StringRef Str); - Error writeFixedString(StringRef Str); - Error writeStreamRef(ReadableStreamRef Ref); - Error writeStreamRef(ReadableStreamRef Ref, uint32_t Size); - - template - Error writeEnum(T Num, - llvm::support::endianness Endian = llvm::support::native) { - 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), Endian); - } - - 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))); - } - - template Error writeArray(ArrayRef Array) { - if (Array.empty()) - return Error::success(); - - if (Array.size() > UINT32_MAX / sizeof(T)) - return make_error(msf_error_code::insufficient_buffer); - - return writeBytes( - ArrayRef(reinterpret_cast(Array.data()), - Array.size() * sizeof(T))); - } - - template - Error writeArray(VarStreamArray Array) { - return writeStreamRef(Array.getUnderlyingStream()); - } - - 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(); } - -private: - WritableStreamRef Stream; - uint32_t Offset = 0; -}; - -} // end namespace msf -} // end namespace llvm - -#endif // LLVM_DEBUGINFO_MSF_STREAMWRITER_H Index: llvm/include/llvm/DebugInfo/PDB/Native/DbiStream.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/DbiStream.h +++ llvm/include/llvm/DebugInfo/PDB/Native/DbiStream.h @@ -12,13 +12,13 @@ #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.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/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -70,11 +70,11 @@ Expected getFileNameForIndex(uint32_t Index) const; - msf::FixedStreamArray getSectionHeaders(); + FixedStreamArray getSectionHeaders(); - msf::FixedStreamArray getFpoRecords(); + FixedStreamArray getFpoRecords(); - msf::FixedStreamArray getSectionMap() const; + FixedStreamArray getSectionMap() const; void visitSectionContributions(ISectionContribVisitor &Visitor) const; private: @@ -91,28 +91,28 @@ std::vector ModuleInfos; StringTable ECNames; - msf::ReadableStreamRef ModInfoSubstream; - msf::ReadableStreamRef SecContrSubstream; - msf::ReadableStreamRef SecMapSubstream; - msf::ReadableStreamRef FileInfoSubstream; - msf::ReadableStreamRef TypeServerMapSubstream; - msf::ReadableStreamRef ECSubstream; + BinaryStreamRef ModInfoSubstream; + BinaryStreamRef SecContrSubstream; + BinaryStreamRef SecMapSubstream; + BinaryStreamRef FileInfoSubstream; + BinaryStreamRef TypeServerMapSubstream; + BinaryStreamRef ECSubstream; - msf::ReadableStreamRef NamesBuffer; + BinaryStreamRef NamesBuffer; - msf::FixedStreamArray DbgStreams; + FixedStreamArray DbgStreams; PdbRaw_DbiSecContribVer SectionContribVersion; - msf::FixedStreamArray SectionContribs; - msf::FixedStreamArray SectionContribs2; - msf::FixedStreamArray SectionMap; - msf::FixedStreamArray FileNameOffsets; + FixedStreamArray SectionContribs; + FixedStreamArray SectionContribs2; + FixedStreamArray SectionMap; + FixedStreamArray FileNameOffsets; std::unique_ptr SectionHeaderStream; - msf::FixedStreamArray SectionHeaders; + FixedStreamArray SectionHeaders; std::unique_ptr FpoStream; - msf::FixedStreamArray FpoRecords; + FixedStreamArray FpoRecords; const DbiStreamHeader *Header; }; Index: llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h +++ llvm/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/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.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 { @@ -60,7 +60,7 @@ Error finalizeMsfLayout(); - Error commit(const msf::MSFLayout &Layout, const msf::WritableStream &Buffer); + Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef Buffer); // A helper function to create Section Contributions from COFF input // section headers. @@ -112,9 +112,9 @@ StringMap SourceFileNames; - msf::WritableStreamRef NamesBuffer; - msf::MutableByteStream ModInfoBuffer; - msf::MutableByteStream FileInfoBuffer; + WritableBinaryStreamRef NamesBuffer; + MutableBinaryByteStream ModInfoBuffer; + MutableBinaryByteStream FileInfoBuffer; ArrayRef SectionContribs; ArrayRef SectionMap; llvm::SmallVector DbgStreams; Index: llvm/include/llvm/DebugInfo/PDB/Native/GlobalsStream.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/GlobalsStream.h +++ llvm/include/llvm/DebugInfo/PDB/Native/GlobalsStream.h @@ -11,10 +11,10 @@ #define LLVM_DEBUGINFO_PDB_RAW_GLOBALS_STREAM_H #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.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 { @@ -27,15 +27,15 @@ explicit GlobalsStream(std::unique_ptr Stream); ~GlobalsStream(); Error commit(); - msf::FixedStreamArray getHashBuckets() const { + FixedStreamArray getHashBuckets() const { return HashBuckets; } uint32_t getNumBuckets() const { return NumBuckets; } Error reload(); private: - msf::FixedStreamArray HashBuckets; - msf::FixedStreamArray HashRecords; + FixedStreamArray HashBuckets; + FixedStreamArray HashRecords; uint32_t NumBuckets; std::unique_ptr Stream; }; Index: llvm/include/llvm/DebugInfo/PDB/Native/HashTable.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/HashTable.h +++ llvm/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/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamWriter.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" @@ -42,10 +42,10 @@ HashTable(); explicit HashTable(uint32_t Capacity); - Error load(msf::StreamReader &Stream); + Error load(BinaryStreamReader &Stream); uint32_t calculateSerializedLength() const; - Error commit(msf::StreamWriter &Writer) const; + Error commit(BinaryStreamWriter &Writer) const; void clear(); @@ -71,9 +71,9 @@ static uint32_t maxLoad(uint32_t capacity); void grow(); - static Error readSparseBitVector(msf::StreamReader &Stream, + static Error readSparseBitVector(BinaryStreamReader &Stream, SparseBitVector<> &V); - static Error writeSparseBitVector(msf::StreamWriter &Writer, + static Error writeSparseBitVector(BinaryStreamWriter &Writer, SparseBitVector<> &Vec); }; Index: llvm/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h +++ llvm/include/llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h @@ -19,9 +19,10 @@ #include "llvm/DebugInfo/PDB/PDBTypes.h" namespace llvm { +class WritableBinaryStream; + namespace msf { class MSFBuilder; -class StreamWriter; } namespace pdb { class PDBFile; @@ -43,7 +44,7 @@ Error finalizeMsfLayout(); Error commit(const msf::MSFLayout &Layout, - const msf::WritableStream &Buffer) const; + WritableBinaryStreamRef Buffer) const; private: msf::MSFBuilder &Msf; Index: llvm/include/llvm/DebugInfo/PDB/Native/ModInfo.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/ModInfo.h +++ llvm/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/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.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 @@ -30,7 +30,7 @@ ModInfo(const ModInfo &Info); ~ModInfo(); - static Error initialize(msf::ReadableStreamRef Stream, ModInfo &Info); + static Error initialize(BinaryStreamRef Stream, ModInfo &Info); bool hasECInfo() const; uint16_t getTypeServerIndex() const; @@ -63,10 +63,8 @@ } // end namespace pdb -namespace msf { - template <> struct VarStreamArrayExtractor { - Error operator()(ReadableStreamRef Stream, uint32_t &Length, + Error operator()(BinaryStreamRef Stream, uint32_t &Length, pdb::ModInfo &Info) const { if (auto EC = pdb::ModInfo::initialize(Stream, Info)) return EC; @@ -75,8 +73,6 @@ } }; -} // end namespace msf - } // end namespace llvm #endif // LLVM_DEBUGINFO_PDB_RAW_MODINFO_H Index: llvm/include/llvm/DebugInfo/PDB/Native/ModStream.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/ModStream.h +++ llvm/include/llvm/DebugInfo/PDB/Native/ModStream.h @@ -15,8 +15,8 @@ #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Error.h" namespace llvm { @@ -50,9 +50,9 @@ std::unique_ptr Stream; codeview::CVSymbolArray SymbolsSubstream; - msf::ReadableStreamRef LinesSubstream; - msf::ReadableStreamRef C13LinesSubstream; - msf::ReadableStreamRef GlobalRefsSubstream; + BinaryStreamRef LinesSubstream; + BinaryStreamRef C13LinesSubstream; + BinaryStreamRef GlobalRefsSubstream; codeview::ModuleSubstreamArray LineInfo; }; Index: llvm/include/llvm/DebugInfo/PDB/Native/NamedStreamMap.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/NamedStreamMap.h +++ llvm/include/llvm/DebugInfo/PDB/Native/NamedStreamMap.h @@ -17,10 +17,9 @@ #include namespace llvm { -namespace msf { -class StreamReader; -class StreamWriter; -} +class BinaryStreamReader; +class BinaryStreamWriter; + namespace pdb { class NamedStreamMapBuilder; class NamedStreamMap { @@ -33,8 +32,8 @@ public: NamedStreamMap(); - Error load(msf::StreamReader &Stream); - Error commit(msf::StreamWriter &Writer) const; + Error load(BinaryStreamReader &Stream); + Error commit(BinaryStreamWriter &Writer) const; uint32_t finalize(); bool get(StringRef Stream, uint32_t &StreamNo) const; Index: llvm/include/llvm/DebugInfo/PDB/Native/PDBFile.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/PDBFile.h +++ llvm/include/llvm/DebugInfo/PDB/Native/PDBFile.h @@ -13,9 +13,9 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/DebugInfo/MSF/IMSFFile.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/MathExtras.h" @@ -42,7 +42,7 @@ friend PDBFileBuilder; public: - PDBFile(StringRef Path, std::unique_ptr PdbFileBuffer, + PDBFile(StringRef Path, std::unique_ptr PdbFileBuffer, BumpPtrAllocator &Allocator); ~PDBFile() override; @@ -80,7 +80,7 @@ } const msf::MSFLayout &getMsfLayout() const { return ContainerLayout; } - const msf::ReadableStream &getMsfBuffer() const { return *Buffer; } + BinaryStreamRef getMsfBuffer() const { return *Buffer; } ArrayRef getDirectoryBlockArray() const; @@ -110,13 +110,13 @@ private: Expected> safelyCreateIndexedStream(const msf::MSFLayout &Layout, - const msf::ReadableStream &MsfData, + BinaryStreamRef MsfData, uint32_t StreamIndex) const; std::string FilePath; BumpPtrAllocator &Allocator; - std::unique_ptr Buffer; + std::unique_ptr Buffer; std::vector FpmPages; msf::MSFLayout ContainerLayout; Index: llvm/include/llvm/DebugInfo/PDB/Native/PublicsStream.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/PublicsStream.h +++ llvm/include/llvm/DebugInfo/PDB/Native/PublicsStream.h @@ -12,11 +12,11 @@ #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.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 { @@ -38,16 +38,16 @@ uint32_t getNumBuckets() const { return NumBuckets; } iterator_range getSymbols(bool *HadError) const; - msf::FixedStreamArray getHashBuckets() const { + FixedStreamArray getHashBuckets() const { return HashBuckets; } - msf::FixedStreamArray getAddressMap() const { + FixedStreamArray getAddressMap() const { return AddressMap; } - msf::FixedStreamArray getThunkMap() const { + FixedStreamArray getThunkMap() const { return ThunkMap; } - msf::FixedStreamArray getSectionOffsets() const { + FixedStreamArray getSectionOffsets() const { return SectionOffsets; } @@ -59,11 +59,11 @@ std::unique_ptr Stream; uint32_t NumBuckets = 0; ArrayRef Bitmap; - msf::FixedStreamArray HashRecords; - msf::FixedStreamArray HashBuckets; - msf::FixedStreamArray AddressMap; - msf::FixedStreamArray ThunkMap; - msf::FixedStreamArray SectionOffsets; + FixedStreamArray HashRecords; + FixedStreamArray HashBuckets; + FixedStreamArray AddressMap; + FixedStreamArray ThunkMap; + FixedStreamArray SectionOffsets; const HeaderInfo *Header; const GSIHashHeader *HashHdr; Index: llvm/include/llvm/DebugInfo/PDB/Native/StringTable.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/StringTable.h +++ llvm/include/llvm/DebugInfo/PDB/Native/StringTable.h @@ -12,24 +12,23 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include #include namespace llvm { -namespace msf { -class StreamReader; -} +class BinaryStreamReader; + namespace pdb { class StringTable { public: StringTable(); - Error load(msf::StreamReader &Stream); + Error load(BinaryStreamReader &Stream); uint32_t getNameCount() const { return NameCount; } uint32_t getHashVersion() const { return HashVersion; } @@ -38,11 +37,11 @@ StringRef getStringForID(uint32_t ID) const; uint32_t getIDForString(StringRef Str) const; - msf::FixedStreamArray name_ids() const; + FixedStreamArray name_ids() const; private: - msf::ReadableStreamRef NamesBuffer; - msf::FixedStreamArray IDs; + BinaryStreamRef NamesBuffer; + FixedStreamArray IDs; uint32_t Signature; uint32_t HashVersion; uint32_t NameCount; Index: llvm/include/llvm/DebugInfo/PDB/Native/StringTableBuilder.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/StringTableBuilder.h +++ llvm/include/llvm/DebugInfo/PDB/Native/StringTableBuilder.h @@ -20,9 +20,8 @@ #include namespace llvm { -namespace msf { -class StreamWriter; -} +class BinaryStreamWriter; + namespace pdb { class StringTableBuilder { @@ -32,7 +31,7 @@ uint32_t insert(StringRef S); uint32_t finalize(); - Error commit(msf::StreamWriter &Writer) const; + Error commit(BinaryStreamWriter &Writer) const; private: DenseMap Strings; Index: llvm/include/llvm/DebugInfo/PDB/Native/TpiHashing.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/TpiHashing.h +++ llvm/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/StreamArray.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include @@ -57,7 +57,7 @@ class TpiHashVerifier : public codeview::TypeVisitorCallbacks { public: - TpiHashVerifier(msf::FixedStreamArray &HashValues, + TpiHashVerifier(FixedStreamArray &HashValues, uint32_t NumHashBuckets) : HashValues(HashValues), NumHashBuckets(NumHashBuckets) {} @@ -83,7 +83,7 @@ utohexstr(codeview::TypeIndex::FirstNonSimpleIndex + Index)); } - msf::FixedStreamArray HashValues; + FixedStreamArray HashValues; codeview::CVType RawRecord; uint32_t NumHashBuckets; uint32_t Index = -1; Index: llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h +++ llvm/include/llvm/DebugInfo/PDB/Native/TpiStream.h @@ -11,11 +11,12 @@ #define LLVM_DEBUGINFO_PDB_RAW_PDBTPISTREAM_H #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/StreamArray.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/BinaryStream.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Error.h" @@ -46,8 +47,8 @@ uint32_t getHashKeySize() const; uint32_t NumHashBuckets() const; - msf::FixedStreamArray getHashValues() const; - msf::FixedStreamArray getTypeIndexOffsets() const; + FixedStreamArray getHashValues() const; + FixedStreamArray getTypeIndexOffsets() const; HashTable &getHashAdjusters(); codeview::CVTypeRange types(bool *HadError) const; @@ -62,9 +63,9 @@ codeview::CVTypeArray TypeRecords; - std::unique_ptr HashStream; - msf::FixedStreamArray HashValues; - msf::FixedStreamArray TypeIndexOffsets; + std::unique_ptr HashStream; + FixedStreamArray HashValues; + FixedStreamArray TypeIndexOffsets; HashTable HashAdjusters; const TpiStreamHeader *Header; Index: llvm/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h +++ llvm/include/llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h @@ -12,31 +12,31 @@ #include "llvm/ADT/Optional.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" -#include "llvm/DebugInfo/MSF/SequencedItemStream.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/Error.h" #include namespace llvm { -namespace codeview { -class TypeRecord; -} -namespace msf { -class ByteStream; -class MSFBuilder; -struct MSFLayout; -class ReadableStreamRef; -class WritableStream; +class BinaryStreamRef; +class WritableBinaryStream; -template <> struct SequencedItemTraits { +template <> struct BinaryItemTraits { static size_t length(const codeview::CVType &Item) { return Item.length(); } static ArrayRef bytes(const codeview::CVType &Item) { return Item.data(); } }; + +namespace codeview { +class TypeRecord; +} +namespace msf { +class MSFBuilder; +struct MSFLayout; } namespace pdb { class PDBFile; @@ -56,9 +56,9 @@ Error finalizeMsfLayout(); - Error commit(const msf::MSFLayout &Layout, const msf::WritableStream &Buffer); + Error commit(const msf::MSFLayout &Layout, WritableBinaryStreamRef Buffer); - uint32_t calculateSerializedLength() const; + uint32_t calculateSerializedLength(); private: uint32_t calculateHashBufferSize() const; @@ -69,9 +69,9 @@ Optional VerHeader; std::vector TypeRecords; - msf::SequencedItemStream TypeRecordStream; + BinaryItemStream TypeRecordStream; uint32_t HashStreamIndex = kInvalidStreamIndex; - std::unique_ptr HashValueStream; + std::unique_ptr HashValueStream; const TpiStreamHeader *Header; uint32_t Idx; Index: llvm/include/llvm/Support/BinaryByteStream.h =================================================================== --- /dev/null +++ llvm/include/llvm/Support/BinaryByteStream.h @@ -0,0 +1,176 @@ +//===- 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/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; + explicit BinaryByteStream(ArrayRef Data) : Data(Data) {} + explicit BinaryByteStream(StringRef Data) + : Data(Data.bytes_begin(), Data.bytes_end()) {} + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) override { + if (Offset > Data.size()) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + if (Data.size() < Size + Offset) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + Buffer = Data.slice(Offset, Size); + return Error::success(); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) override { + if (Offset >= Data.size()) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + 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: + 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: + explicit MemoryBufferByteStream(std::unique_ptr Buffer) + : BinaryByteStream(makeArrayRef(Buffer->getBuffer().bytes())), + 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; + explicit MutableBinaryByteStream(MutableArrayRef Data) + : Data(Data), ImmutableStream(Data) {} + + 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 (Data.size() < Buffer.size()) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + if (Offset > Buffer.size() - Data.size()) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + + 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) + : MutableBinaryByteStream(MutableArrayRef( + Buffer->getBufferStart(), Buffer->getBufferEnd())), + FileBuffer(std::move(Buffer)) {} + + Error commit() override { + if (FileBuffer->commit()) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + return Error::success(); + } + + private: + std::unique_ptr FileBuffer; + }; + +public: + explicit FileBufferByteStream(std::unique_ptr Buffer) + : Impl(std::move(Buffer)) {} + + 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_BINARYBYTESTREAM_H Index: llvm/include/llvm/Support/BinaryItemStream.h =================================================================== --- /dev/null +++ llvm/include/llvm/Support/BinaryItemStream.h @@ -0,0 +1,98 @@ +//===- 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/Error.h" +#include +#include + +namespace llvm { + +template struct BinaryItemTraits { + size_t length(const T &Item) = delete; + 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: + BinaryItemStream() = default; + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) override { + if (auto EC = readLongestContiguousChunk(Offset, Buffer)) + return EC; + + if (Size > Buffer.size()) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + + Buffer = Buffer.take_front(Size); + return Error::success(); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) override { + uint32_t Index; + uint32_t ByteOffset; + if (auto EC = translateOffsetIndex(Offset, Index, ByteOffset)) + return EC; + const auto &Item = Items[Index]; + Buffer = Traits.bytes(Item).drop_front(ByteOffset); + 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: + Error translateOffsetIndex(uint32_t Offset, uint32_t &ItemIndex, + uint32_t &ByteOffset) { + ItemIndex = 0; + ByteOffset = 0; + uint32_t PrevOffset = 0; + uint32_t CurrentOffset = 0; + if (Offset > 0) { + for (const auto &Item : Items) { + PrevOffset = CurrentOffset; + CurrentOffset += Traits.length(Item); + if (CurrentOffset > Offset) + break; + ++ItemIndex; + } + } + if (CurrentOffset < Offset) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + ByteOffset = Offset - PrevOffset; + return Error::success(); + } + + ItemTraits Traits; + ArrayRef Items; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_BINARYITEMSTREAM_H Index: llvm/include/llvm/Support/BinaryStream.h =================================================================== --- /dev/null +++ llvm/include/llvm/Support/BinaryStream.h @@ -0,0 +1,65 @@ +//===- 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/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; + + /// \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; +}; + +/// \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/include/llvm/Support/BinaryStreamArray.h =================================================================== --- /dev/null +++ llvm/include/llvm/Support/BinaryStreamArray.h @@ -0,0 +1,319 @@ +//===- 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)); + } + 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/include/llvm/Support/BinaryStreamReader.h =================================================================== --- /dev/null +++ llvm/include/llvm/Support/BinaryStreamReader.h @@ -0,0 +1,228 @@ +//===- 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/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.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: + BinaryStreamReader(BinaryStreamRef Stream, llvm::support::endianness Endian); + 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(), Endian); + 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 readZeroString(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 errorCodeToError(make_error_code(std::errc::no_buffer_space)); + + if (auto EC = readBytes(Bytes, NumElements * sizeof(T))) + return EC; + 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(); + } + uint32_t Length = NumItems * sizeof(T); + if (Length / sizeof(T) != NumItems) + return errorCodeToError( + make_error_code(std::errc::illegal_byte_sequence)); + if (Offset + Length > Stream.getLength()) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + BinaryStreamRef View = Stream.slice(Offset, Length); + Array = FixedStreamArray(View); + Offset += Length; + 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; + llvm::support::endianness Endian; +}; +} // namespace llvm + +#endif // LLVM_SUPPORT_BINARYSTREAMREADER_H Index: llvm/include/llvm/Support/BinaryStreamRef.h =================================================================== --- /dev/null +++ llvm/include/llvm/Support/BinaryStreamRef.h @@ -0,0 +1,162 @@ +//===- 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/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) {} + + 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: + 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 (ViewOffset + Offset < Offset) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + if (Size + Offset > Length) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + 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 (Offset >= Length) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + + if (auto EC = Stream->readLongestContiguousChunk(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 (Data.size() + Offset > Length) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + 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/include/llvm/Support/BinaryStreamWriter.h =================================================================== --- /dev/null +++ llvm/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/StringRef.h" +#include "llvm/Support/BinaryStreamArray.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; + BinaryStreamWriter(WritableBinaryStreamRef Stream, + llvm::support::endianness Endian); + 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, + Endian); + 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. + /// + /// \returns a success error code if the data was successfully written, + /// otherwise returns an appropriate error code. + Error writeZeroString(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 errorCodeToError(make_error_code(std::errc::no_buffer_space)); + + 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; + llvm::support::endianness Endian; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_BINARYSTREAMWRITER_H Index: llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ llvm/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/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.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" @@ -38,7 +38,6 @@ using namespace llvm; using namespace llvm::codeview; -using namespace llvm::msf; CodeViewDebug::CodeViewDebug(AsmPrinter *AP) : DebugHandlerBase(AP), OS(*Asm->OutStreamer), Allocator(), @@ -495,9 +494,9 @@ // comments. The MSVC linker doesn't do much type record validation, // so the first link of an invalid type record can succeed while // subsequent links will fail with LNK1285. - ByteStream Stream(Record); + BinaryByteStream Stream(Record); CVTypeArray Types; - StreamReader Reader(Stream); + BinaryStreamReader Reader(Stream, llvm::support::little); Error E = Reader.readArray(Types, Reader.getLength()); if (!E) { TypeVisitorCallbacks C; Index: llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp +++ llvm/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp @@ -11,7 +11,6 @@ #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" using namespace llvm; using namespace llvm::codeview; Index: llvm/lib/DebugInfo/CodeView/CVTypeDumper.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/CVTypeDumper.cpp +++ llvm/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/ByteStream.h" +#include "llvm/Support/BinaryByteStream.h" using namespace llvm; using namespace llvm::codeview; @@ -56,9 +56,9 @@ } Error CVTypeDumper::dump(ArrayRef Data, TypeVisitorCallbacks &Dumper) { - msf::ByteStream Stream(Data); + BinaryByteStream Stream(Data); CVTypeArray Types; - msf::StreamReader Reader(Stream); + BinaryStreamReader Reader(Stream, llvm::support::little); if (auto EC = Reader.readArray(Types, Reader.getLength())) return EC; Index: llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ llvm/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/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" using namespace llvm; using namespace llvm::codeview; @@ -174,7 +174,7 @@ return Error::success(); } -Error CVTypeVisitor::visitFieldListMemberStream(msf::StreamReader Reader) { +Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader Reader) { FieldListDeserializer Deserializer(Reader); TypeVisitorCallbackPipeline Pipeline; Pipeline.addCallbackToPipeline(Deserializer); @@ -182,7 +182,7 @@ TypeLeafKind Leaf; while (!Reader.empty()) { - if (auto EC = Reader.readEnum(Leaf, llvm::support::little)) + if (auto EC = Reader.readEnum(Leaf)) return EC; CVMemberRecord Record; @@ -195,7 +195,7 @@ } Error CVTypeVisitor::visitFieldListMemberStream(ArrayRef Data) { - msf::ByteStream S(Data); - msf::StreamReader SR(S); + BinaryByteStream S(Data); + BinaryStreamReader SR(S, llvm::support::little); return visitFieldListMemberStream(SR); } Index: llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp +++ llvm/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/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" using namespace llvm; using namespace llvm::codeview; @@ -87,14 +87,13 @@ Error CodeViewRecordIO::mapInteger(TypeIndex &TypeInd) { if (isWriting()) { - if (auto EC = - Writer->writeInteger(TypeInd.getIndex(), llvm::support::little)) + if (auto EC = Writer->writeInteger(TypeInd.getIndex())) return EC; return Error::success(); } uint32_t I; - if (auto EC = Reader->readInteger(I, llvm::support::little)) + if (auto EC = Reader->readInteger(I)) return EC; TypeInd.setIndex(I); return Error::success(); @@ -177,7 +176,7 @@ if (auto EC = mapStringZ(V)) return EC; } - if (auto EC = Writer->writeInteger(0, llvm::support::little)) + if (auto EC = Writer->writeInteger(0)) return EC; } else { StringRef S; @@ -195,28 +194,24 @@ Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) { assert(Value < 0 && "Encoded integer is not signed!"); if (Value >= std::numeric_limits::min()) { - if (auto EC = - Writer->writeInteger(LF_CHAR, llvm::support::little)) + if (auto EC = Writer->writeInteger(LF_CHAR)) return EC; - if (auto EC = Writer->writeInteger(Value, llvm::support::little)) + if (auto EC = Writer->writeInteger(Value)) return EC; } else if (Value >= std::numeric_limits::min()) { - if (auto EC = - Writer->writeInteger(LF_SHORT, llvm::support::little)) + if (auto EC = Writer->writeInteger(LF_SHORT)) return EC; - if (auto EC = Writer->writeInteger(Value, llvm::support::little)) + if (auto EC = Writer->writeInteger(Value)) return EC; } else if (Value >= std::numeric_limits::min()) { - if (auto EC = - Writer->writeInteger(LF_LONG, llvm::support::little)) + if (auto EC = Writer->writeInteger(LF_LONG)) return EC; - if (auto EC = Writer->writeInteger(Value, llvm::support::little)) + if (auto EC = Writer->writeInteger(Value)) return EC; } else { - if (auto EC = - Writer->writeInteger(LF_QUADWORD, llvm::support::little)) + if (auto EC = Writer->writeInteger(LF_QUADWORD)) return EC; - if (auto EC = Writer->writeInteger(Value, llvm::support::little)) + if (auto EC = Writer->writeInteger(Value)) return EC; } return Error::success(); @@ -224,25 +219,22 @@ Error CodeViewRecordIO::writeEncodedUnsignedInteger(const uint64_t &Value) { if (Value < LF_NUMERIC) { - if (auto EC = Writer->writeInteger(Value, llvm::support::little)) + if (auto EC = Writer->writeInteger(Value)) return EC; } else if (Value <= std::numeric_limits::max()) { - if (auto EC = - Writer->writeInteger(LF_USHORT, llvm::support::little)) + if (auto EC = Writer->writeInteger(LF_USHORT)) return EC; - if (auto EC = Writer->writeInteger(Value, llvm::support::little)) + if (auto EC = Writer->writeInteger(Value)) return EC; } else if (Value <= std::numeric_limits::max()) { - if (auto EC = - Writer->writeInteger(LF_ULONG, llvm::support::little)) + if (auto EC = Writer->writeInteger(LF_ULONG)) return EC; - if (auto EC = Writer->writeInteger(Value, llvm::support::little)) + if (auto EC = Writer->writeInteger(Value)) return EC; } else { - if (auto EC = - Writer->writeInteger(LF_UQUADWORD, llvm::support::little)) + if (auto EC = Writer->writeInteger(LF_UQUADWORD)) return EC; - if (auto EC = Writer->writeInteger(Value, llvm::support::little)) + if (auto EC = Writer->writeInteger(Value)) return EC; } Index: llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp +++ llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp @@ -9,22 +9,20 @@ #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/Support/BinaryStreamReader.h" using namespace llvm; using namespace llvm::codeview; -using namespace llvm::msf; ModuleSubstream::ModuleSubstream() : Kind(ModuleSubstreamKind::None) {} -ModuleSubstream::ModuleSubstream(ModuleSubstreamKind Kind, - ReadableStreamRef Data) +ModuleSubstream::ModuleSubstream(ModuleSubstreamKind Kind, BinaryStreamRef Data) : Kind(Kind), Data(Data) {} -Error ModuleSubstream::initialize(ReadableStreamRef Stream, +Error ModuleSubstream::initialize(BinaryStreamRef Stream, ModuleSubstream &Info) { const ModuleSubsectionHeader *Header; - StreamReader Reader(Stream); + BinaryStreamReader Reader(Stream, llvm::support::little); if (auto EC = Reader.readObject(Header)) return EC; @@ -42,4 +40,4 @@ ModuleSubstreamKind ModuleSubstream::getSubstreamKind() const { return Kind; } -ReadableStreamRef ModuleSubstream::getRecordData() const { return Data; } +BinaryStreamRef ModuleSubstream::getRecordData() const { return Data; } Index: llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp +++ llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp @@ -8,54 +8,52 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/CodeView/ModuleSubstreamVisitor.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" using namespace llvm; using namespace llvm::codeview; -using namespace llvm::msf; -Error IModuleSubstreamVisitor::visitSymbols(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitSymbols(BinaryStreamRef Data) { return visitUnknown(ModuleSubstreamKind::Symbols, Data); } -Error IModuleSubstreamVisitor::visitLines(ReadableStreamRef Data, +Error IModuleSubstreamVisitor::visitLines(BinaryStreamRef Data, const LineSubstreamHeader *Header, const LineInfoArray &Lines) { return visitUnknown(ModuleSubstreamKind::Lines, Data); } -Error IModuleSubstreamVisitor::visitStringTable(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitStringTable(BinaryStreamRef Data) { return visitUnknown(ModuleSubstreamKind::StringTable, Data); } Error IModuleSubstreamVisitor::visitFileChecksums( - ReadableStreamRef Data, const FileChecksumArray &Checksums) { + BinaryStreamRef Data, const FileChecksumArray &Checksums) { return visitUnknown(ModuleSubstreamKind::FileChecksums, Data); } -Error IModuleSubstreamVisitor::visitFrameData(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitFrameData(BinaryStreamRef Data) { return visitUnknown(ModuleSubstreamKind::FrameData, Data); } -Error IModuleSubstreamVisitor::visitInlineeLines(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitInlineeLines(BinaryStreamRef Data) { return visitUnknown(ModuleSubstreamKind::InlineeLines, Data); } -Error IModuleSubstreamVisitor::visitCrossScopeImports(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitCrossScopeImports(BinaryStreamRef Data) { return visitUnknown(ModuleSubstreamKind::CrossScopeExports, Data); } -Error IModuleSubstreamVisitor::visitCrossScopeExports(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitCrossScopeExports(BinaryStreamRef Data) { return visitUnknown(ModuleSubstreamKind::CrossScopeImports, Data); } -Error IModuleSubstreamVisitor::visitILLines(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitILLines(BinaryStreamRef Data) { return visitUnknown(ModuleSubstreamKind::ILLines, Data); } -Error IModuleSubstreamVisitor::visitFuncMDTokenMap(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitFuncMDTokenMap(BinaryStreamRef Data) { return visitUnknown(ModuleSubstreamKind::FuncMDTokenMap, Data); } -Error IModuleSubstreamVisitor::visitTypeMDTokenMap(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitTypeMDTokenMap(BinaryStreamRef Data) { return visitUnknown(ModuleSubstreamKind::TypeMDTokenMap, Data); } -Error IModuleSubstreamVisitor::visitMergedAssemblyInput( - ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitMergedAssemblyInput(BinaryStreamRef Data) { return visitUnknown(ModuleSubstreamKind::MergedAssemblyInput, Data); } -Error IModuleSubstreamVisitor::visitCoffSymbolRVA(ReadableStreamRef Data) { +Error IModuleSubstreamVisitor::visitCoffSymbolRVA(BinaryStreamRef Data) { return visitUnknown(ModuleSubstreamKind::CoffSymbolRVA, Data); } @@ -65,7 +63,7 @@ case ModuleSubstreamKind::Symbols: return V.visitSymbols(R.getRecordData()); case ModuleSubstreamKind::Lines: { - StreamReader Reader(R.getRecordData()); + BinaryStreamReader Reader(R.getRecordData(), llvm::support::little); const LineSubstreamHeader *Header; if (auto EC = Reader.readObject(Header)) return EC; @@ -78,7 +76,7 @@ case ModuleSubstreamKind::StringTable: return V.visitStringTable(R.getRecordData()); case ModuleSubstreamKind::FileChecksums: { - StreamReader Reader(R.getRecordData()); + BinaryStreamReader Reader(R.getRecordData(), llvm::support::little); FileChecksumArray Checksums; if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining())) return EC; Index: llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/RecordSerialization.cpp +++ llvm/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/ByteStream.h" +#include "llvm/Support/BinaryByteStream.h" using namespace llvm; using namespace llvm::codeview; @@ -33,11 +33,11 @@ return getBytesAsCharacters(LeafData).split('\0').first; } -Error llvm::codeview::consume(msf::StreamReader &Reader, APSInt &Num) { +Error llvm::codeview::consume(BinaryStreamReader &Reader, APSInt &Num) { // Used to avoid overload ambiguity on APInt construtor. bool FalseVal = false; uint16_t Short; - if (auto EC = Reader.readInteger(Short, llvm::support::little)) + if (auto EC = Reader.readInteger(Short)) return EC; if (Short < LF_NUMERIC) { @@ -49,49 +49,49 @@ switch (Short) { case LF_CHAR: { int8_t N; - if (auto EC = Reader.readInteger(N, llvm::support::little)) + if (auto EC = Reader.readInteger(N)) return EC; Num = APSInt(APInt(8, N, true), false); return Error::success(); } case LF_SHORT: { int16_t N; - if (auto EC = Reader.readInteger(N, llvm::support::little)) + if (auto EC = Reader.readInteger(N)) return EC; Num = APSInt(APInt(16, N, true), false); return Error::success(); } case LF_USHORT: { uint16_t N; - if (auto EC = Reader.readInteger(N, llvm::support::little)) + if (auto EC = Reader.readInteger(N)) return EC; Num = APSInt(APInt(16, N, false), true); return Error::success(); } case LF_LONG: { int32_t N; - if (auto EC = Reader.readInteger(N, llvm::support::little)) + if (auto EC = Reader.readInteger(N)) return EC; Num = APSInt(APInt(32, N, true), false); return Error::success(); } case LF_ULONG: { uint32_t N; - if (auto EC = Reader.readInteger(N, llvm::support::little)) + if (auto EC = Reader.readInteger(N)) return EC; Num = APSInt(APInt(32, N, FalseVal), true); return Error::success(); } case LF_QUADWORD: { int64_t N; - if (auto EC = Reader.readInteger(N, llvm::support::little)) + if (auto EC = Reader.readInteger(N)) return EC; Num = APSInt(APInt(64, N, true), false); return Error::success(); } case LF_UQUADWORD: { uint64_t N; - if (auto EC = Reader.readInteger(N, llvm::support::little)) + if (auto EC = Reader.readInteger(N)) return EC; Num = APSInt(APInt(64, N, false), true); return Error::success(); @@ -103,15 +103,15 @@ Error llvm::codeview::consume(StringRef &Data, APSInt &Num) { ArrayRef Bytes(Data.bytes_begin(), Data.bytes_end()); - msf::ByteStream S(Bytes); - msf::StreamReader SR(S); + BinaryByteStream S(Bytes); + BinaryStreamReader SR(S, llvm::support::little); auto EC = consume(SR, Num); Data = Data.take_back(SR.bytesRemaining()); return EC; } /// Decode a numeric leaf value that is known to be a uint64_t. -Error llvm::codeview::consume_numeric(msf::StreamReader &Reader, +Error llvm::codeview::consume_numeric(BinaryStreamReader &Reader, uint64_t &Num) { APSInt N; if (auto EC = consume(Reader, N)) @@ -123,24 +123,24 @@ return Error::success(); } -Error llvm::codeview::consume(msf::StreamReader &Reader, uint32_t &Item) { - return Reader.readInteger(Item, llvm::support::little); +Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) { + return Reader.readInteger(Item); } Error llvm::codeview::consume(StringRef &Data, uint32_t &Item) { ArrayRef Bytes(Data.bytes_begin(), Data.bytes_end()); - msf::ByteStream S(Bytes); - msf::StreamReader SR(S); + BinaryByteStream S(Bytes); + BinaryStreamReader SR(S, llvm::support::little); auto EC = consume(SR, Item); Data = Data.take_back(SR.bytesRemaining()); return EC; } -Error llvm::codeview::consume(msf::StreamReader &Reader, int32_t &Item) { - return Reader.readInteger(Item, llvm::support::little); +Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) { + return Reader.readInteger(Item); } -Error llvm::codeview::consume(msf::StreamReader &Reader, StringRef &Item) { +Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) { if (Reader.empty()) return make_error(cv_error_code::corrupt_record, "Null terminated string buffer is empty!"); Index: llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp +++ llvm/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp @@ -19,7 +19,6 @@ #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/ScopedPrinter.h" Index: llvm/lib/DebugInfo/CodeView/TypeRecord.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/TypeRecord.cpp +++ llvm/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/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" using namespace llvm; using namespace llvm::codeview; Index: llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp +++ llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp @@ -9,7 +9,7 @@ #include "llvm/DebugInfo/CodeView/TypeSerializer.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" +#include "llvm/Support/BinaryStreamWriter.h" #include @@ -76,7 +76,7 @@ int N = PaddingBytes; while (PaddingBytes > 0) { uint8_t Pad = static_cast(LF_PAD0 + PaddingBytes); - if (auto EC = Writer.writeInteger(Pad, llvm::support::little)) + if (auto EC = Writer.writeInteger(Pad)) return std::move(EC); --PaddingBytes; } @@ -85,8 +85,8 @@ TypeSerializer::TypeSerializer(BumpPtrAllocator &Storage) : RecordStorage(Storage), LastTypeIndex(), - RecordBuffer(MaxRecordLength * 2), Stream(RecordBuffer), Writer(Stream), - Mapping(Writer) { + RecordBuffer(MaxRecordLength * 2), Stream(RecordBuffer), + Writer(Stream, llvm::support::little), Mapping(Writer) { // RecordBuffer needs to be able to hold enough data so that if we are 1 // byte short of MaxRecordLen, and then we try to write MaxRecordLen bytes, // we won't overflow. @@ -203,15 +203,15 @@ uint8_t *SegmentBytes = RecordStorage.Allocate(LengthWithSize); auto SavedSegment = MutableArrayRef(SegmentBytes, LengthWithSize); - msf::MutableByteStream CS(SavedSegment); - msf::StreamWriter CW(CS); + MutableBinaryByteStream CS(SavedSegment); + BinaryStreamWriter CW(CS, llvm::support::little); if (auto EC = CW.writeBytes(CopyData)) return EC; - if (auto EC = CW.writeEnum(TypeLeafKind::LF_INDEX, llvm::support::little)) + if (auto EC = CW.writeEnum(TypeLeafKind::LF_INDEX)) return EC; - if (auto EC = CW.writeInteger(0, llvm::support::little)) + if (auto EC = CW.writeInteger(0)) return EC; - if (auto EC = CW.writeInteger(0xB0C0B0C0, llvm::support::little)) + if (auto EC = CW.writeInteger(0xB0C0B0C0)) return EC; FieldListSegments.push_back(SavedSegment); Index: llvm/lib/DebugInfo/MSF/CMakeLists.txt =================================================================== --- llvm/lib/DebugInfo/MSF/CMakeLists.txt +++ llvm/lib/DebugInfo/MSF/CMakeLists.txt @@ -3,8 +3,6 @@ MSFBuilder.cpp MSFCommon.cpp MSFError.cpp - StreamReader.cpp - StreamWriter.cpp ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/MSF" ) Index: llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp =================================================================== --- llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp +++ llvm/lib/DebugInfo/MSF/MappedBlockStream.cpp @@ -47,22 +47,20 @@ MappedBlockStream::MappedBlockStream(uint32_t BlockSize, uint32_t NumBlocks, const MSFStreamLayout &Layout, - const ReadableStream &MsfData) + BinaryStreamRef MsfData) : BlockSize(BlockSize), NumBlocks(NumBlocks), StreamLayout(Layout), MsfData(MsfData) {} std::unique_ptr MappedBlockStream::createStream(uint32_t BlockSize, uint32_t NumBlocks, const MSFStreamLayout &Layout, - const ReadableStream &MsfData) { + BinaryStreamRef MsfData) { return llvm::make_unique>( BlockSize, NumBlocks, Layout, MsfData); } -std::unique_ptr -MappedBlockStream::createIndexedStream(const MSFLayout &Layout, - const ReadableStream &MsfData, - uint32_t StreamIndex) { +std::unique_ptr MappedBlockStream::createIndexedStream( + const MSFLayout &Layout, BinaryStreamRef MsfData, uint32_t StreamIndex) { assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index"); MSFStreamLayout SL; SL.Blocks = Layout.StreamMap[StreamIndex]; @@ -73,7 +71,7 @@ std::unique_ptr MappedBlockStream::createDirectoryStream(const MSFLayout &Layout, - const ReadableStream &MsfData) { + BinaryStreamRef MsfData) { MSFStreamLayout SL; SL.Blocks = Layout.DirectoryBlocks; SL.Length = Layout.SB->NumDirectoryBytes; @@ -82,14 +80,14 @@ std::unique_ptr MappedBlockStream::createFpmStream(const MSFLayout &Layout, - const ReadableStream &MsfData) { + BinaryStreamRef MsfData) { MSFStreamLayout SL; initializeFpmStreamLayout(Layout, SL); return createStream(Layout.SB->BlockSize, Layout.SB->NumBlocks, SL, MsfData); } Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const { + ArrayRef &Buffer) { // Make sure we aren't trying to read beyond the end of the stream. if (Size > StreamLayout.Length) return make_error(msf_error_code::insufficient_buffer); @@ -168,8 +166,8 @@ return Error::success(); } -Error MappedBlockStream::readLongestContiguousChunk( - uint32_t Offset, ArrayRef &Buffer) const { +Error MappedBlockStream::readLongestContiguousChunk(uint32_t Offset, + ArrayRef &Buffer) { // Make sure we aren't trying to read beyond the end of the stream. if (Offset >= StreamLayout.Length) return make_error(msf_error_code::insufficient_buffer); @@ -197,10 +195,10 @@ return Error::success(); } -uint32_t MappedBlockStream::getLength() const { return StreamLayout.Length; } +uint32_t MappedBlockStream::getLength() { return StreamLayout.Length; } bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const { + ArrayRef &Buffer) { if (Size == 0) { Buffer = ArrayRef(); return true; @@ -241,7 +239,7 @@ } Error MappedBlockStream::readBytes(uint32_t Offset, - MutableArrayRef Buffer) const { + MutableArrayRef Buffer) { uint32_t BlockNum = Offset / BlockSize; uint32_t OffsetInBlock = Offset % BlockSize; @@ -319,21 +317,21 @@ WritableMappedBlockStream::WritableMappedBlockStream( uint32_t BlockSize, uint32_t NumBlocks, const MSFStreamLayout &Layout, - const WritableStream &MsfData) + WritableBinaryStreamRef MsfData) : ReadInterface(BlockSize, NumBlocks, Layout, MsfData), WriteInterface(MsfData) {} std::unique_ptr WritableMappedBlockStream::createStream(uint32_t BlockSize, uint32_t NumBlocks, const MSFStreamLayout &Layout, - const WritableStream &MsfData) { + WritableBinaryStreamRef MsfData) { return llvm::make_unique>( BlockSize, NumBlocks, Layout, MsfData); } std::unique_ptr WritableMappedBlockStream::createIndexedStream(const MSFLayout &Layout, - const WritableStream &MsfData, + WritableBinaryStreamRef MsfData, uint32_t StreamIndex) { assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index"); MSFStreamLayout SL; @@ -344,7 +342,7 @@ std::unique_ptr WritableMappedBlockStream::createDirectoryStream( - const MSFLayout &Layout, const WritableStream &MsfData) { + const MSFLayout &Layout, WritableBinaryStreamRef MsfData) { MSFStreamLayout SL; SL.Blocks = Layout.DirectoryBlocks; SL.Length = Layout.SB->NumDirectoryBytes; @@ -353,28 +351,28 @@ std::unique_ptr WritableMappedBlockStream::createFpmStream(const MSFLayout &Layout, - const WritableStream &MsfData) { + WritableBinaryStreamRef MsfData) { MSFStreamLayout SL; initializeFpmStreamLayout(Layout, SL); return createStream(Layout.SB->BlockSize, Layout.SB->NumBlocks, SL, MsfData); } Error WritableMappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const { + ArrayRef &Buffer) { return ReadInterface.readBytes(Offset, Size, Buffer); } Error WritableMappedBlockStream::readLongestContiguousChunk( - uint32_t Offset, ArrayRef &Buffer) const { + uint32_t Offset, ArrayRef &Buffer) { return ReadInterface.readLongestContiguousChunk(Offset, Buffer); } -uint32_t WritableMappedBlockStream::getLength() const { +uint32_t WritableMappedBlockStream::getLength() { return ReadInterface.getLength(); } Error WritableMappedBlockStream::writeBytes(uint32_t Offset, - ArrayRef Buffer) const { + ArrayRef Buffer) { // Make sure we aren't trying to write beyond the end of the stream. if (Buffer.size() > getStreamLength()) return make_error(msf_error_code::insufficient_buffer); @@ -410,6 +408,4 @@ return Error::success(); } -Error WritableMappedBlockStream::commit() const { - return WriteInterface.commit(); -} +Error WritableMappedBlockStream::commit() { return WriteInterface.commit(); } Index: llvm/lib/DebugInfo/MSF/StreamReader.cpp =================================================================== --- llvm/lib/DebugInfo/MSF/StreamReader.cpp +++ /dev/null @@ -1,92 +0,0 @@ -//===- StreamReader.cpp - Reads bytes and objects from a 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/StreamReader.h" - -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" - -using namespace llvm; -using namespace llvm::msf; - -StreamReader::StreamReader(ReadableStreamRef S) : Stream(S), Offset(0) {} - -Error StreamReader::readLongestContiguousChunk(ArrayRef &Buffer) { - if (auto EC = Stream.readLongestContiguousChunk(Offset, Buffer)) - return EC; - Offset += Buffer.size(); - return Error::success(); -} - -Error StreamReader::readBytes(ArrayRef &Buffer, uint32_t Size) { - if (auto EC = Stream.readBytes(Offset, Size, Buffer)) - return EC; - Offset += Size; - return Error::success(); -} - -Error StreamReader::readZeroString(StringRef &Dest) { - 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; - do { - if (auto EC = readObject(C)) - return EC; - if (*C != '\0') - ++Length; - } while (*C != '\0'); - // Now go back and request a reference for that many bytes. - uint32_t NewOffset = getOffset(); - setOffset(OriginalOffset); - - ArrayRef Data; - if (auto EC = readBytes(Data, Length)) - return EC; - Dest = StringRef(reinterpret_cast(Data.begin()), Data.size()); - - // Now set the offset back to where it was after we calculated the length. - setOffset(NewOffset); - return Error::success(); -} - -Error StreamReader::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 StreamReader::readStreamRef(ReadableStreamRef &Ref) { - return readStreamRef(Ref, bytesRemaining()); -} - -Error StreamReader::readStreamRef(ReadableStreamRef &Ref, uint32_t Length) { - if (bytesRemaining() < Length) - return make_error(msf_error_code::insufficient_buffer); - Ref = Stream.slice(Offset, Length); - Offset += Length; - return Error::success(); -} - -Error StreamReader::skip(uint32_t Amount) { - if (Amount > bytesRemaining()) - return make_error(msf_error_code::insufficient_buffer); - Offset += Amount; - return Error::success(); -} - -uint8_t StreamReader::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/lib/DebugInfo/MSF/StreamWriter.cpp =================================================================== --- llvm/lib/DebugInfo/MSF/StreamWriter.cpp +++ /dev/null @@ -1,70 +0,0 @@ -//===- StreamWrite.cpp - Writes bytes and objects to a 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/StreamWriter.h" - -#include "llvm/DebugInfo/MSF/MSFError.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" - -using namespace llvm; -using namespace llvm::msf; - -StreamWriter::StreamWriter(WritableStreamRef S) : Stream(S), Offset(0) {} - -Error StreamWriter::writeBytes(ArrayRef Buffer) { - if (auto EC = Stream.writeBytes(Offset, Buffer)) - return EC; - Offset += Buffer.size(); - return Error::success(); -} - -Error StreamWriter::writeZeroString(StringRef Str) { - if (auto EC = writeFixedString(Str)) - return EC; - if (auto EC = writeObject('\0')) - return EC; - - return Error::success(); -} - -Error StreamWriter::writeFixedString(StringRef Str) { - ArrayRef Bytes(Str.bytes_begin(), Str.bytes_end()); - if (auto EC = Stream.writeBytes(Offset, Bytes)) - return EC; - - Offset += Str.size(); - return Error::success(); -} - -Error StreamWriter::writeStreamRef(ReadableStreamRef Ref) { - if (auto EC = writeStreamRef(Ref, Ref.getLength())) - return EC; - // Don't increment Offset here, it is done by the overloaded call to - // writeStreamRef. - return Error::success(); -} - -Error StreamWriter::writeStreamRef(ReadableStreamRef Ref, uint32_t Length) { - Ref = Ref.slice(0, Length); - - StreamReader SrcReader(Ref); - // This is a bit tricky. If we just call readBytes, we are requiring that it - // return us the entire stream as a contiguous buffer. For large streams this - // will allocate a huge amount of space from the pool. Instead, iterate over - // each contiguous chunk until we've consumed the entire stream. - 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/lib/DebugInfo/PDB/Native/DbiStream.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/DbiStream.cpp +++ llvm/lib/DebugInfo/PDB/Native/DbiStream.cpp @@ -10,8 +10,6 @@ #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" #include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/ModInfo.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 @@ -34,7 +34,7 @@ template static Error loadSectionContribs(FixedStreamArray &Output, - StreamReader &Reader) { + BinaryStreamReader &Reader) { if (Reader.bytesRemaining() % sizeof(ContribType) != 0) return make_error( raw_error_code::corrupt_file, @@ -52,7 +52,7 @@ DbiStream::~DbiStream() = default; Error DbiStream::reload() { - StreamReader Reader(*Stream); + BinaryStreamReader Reader(*Stream, little); if (Stream->getLength() < sizeof(DbiStreamHeader)) return make_error(raw_error_code::corrupt_file, @@ -145,7 +145,7 @@ "Found unexpected bytes in DBI Stream."); if (ECSubstream.getLength() > 0) { - StreamReader ECReader(ECSubstream); + BinaryStreamReader ECReader(ECSubstream, little); if (auto EC = ECNames.load(ECReader)) return EC; } @@ -207,16 +207,16 @@ return static_cast(Machine); } -msf::FixedStreamArray DbiStream::getSectionHeaders() { +FixedStreamArray DbiStream::getSectionHeaders() { return SectionHeaders; } -msf::FixedStreamArray DbiStream::getFpoRecords() { +FixedStreamArray DbiStream::getFpoRecords() { return FpoRecords; } ArrayRef DbiStream::modules() const { return ModuleInfos; } -msf::FixedStreamArray DbiStream::getSectionMap() const { +FixedStreamArray DbiStream::getSectionMap() const { return SectionMap; } @@ -235,8 +235,8 @@ if (SecContrSubstream.getLength() == 0) return Error::success(); - StreamReader SCReader(SecContrSubstream); - if (auto EC = SCReader.readEnum(SectionContribVersion, llvm::support::little)) + BinaryStreamReader SCReader(SecContrSubstream, little); + if (auto EC = SCReader.readEnum(SectionContribVersion)) return EC; if (SectionContribVersion == DbiSecContribVer60) @@ -254,7 +254,7 @@ // Since each ModInfo in the stream is a variable length, we have to iterate // them to know how many there actually are. - StreamReader Reader(ModInfoSubstream); + BinaryStreamReader Reader(ModInfoSubstream, little); VarStreamArray ModInfoArray; if (auto EC = Reader.readArray(ModInfoArray, ModInfoSubstream.getLength())) @@ -284,7 +284,7 @@ "Corrupted section header stream."); size_t NumSections = StreamLen / sizeof(object::coff_section); - msf::StreamReader Reader(*SHS); + BinaryStreamReader Reader(*SHS, little); if (auto EC = Reader.readArray(SectionHeaders, NumSections)) return make_error(raw_error_code::corrupt_file, "Could not read a bitmap."); @@ -316,7 +316,7 @@ "Corrupted New FPO stream."); size_t NumRecords = StreamLen / sizeof(object::FpoData); - msf::StreamReader Reader(*FS); + BinaryStreamReader Reader(*FS, little); if (auto EC = Reader.readArray(FpoRecords, NumRecords)) return make_error(raw_error_code::corrupt_file, "Corrupted New FPO stream."); @@ -328,7 +328,7 @@ if (SecMapSubstream.getLength() == 0) return Error::success(); - StreamReader SMReader(SecMapSubstream); + BinaryStreamReader SMReader(SecMapSubstream, little); const SecMapHeader *Header; if (auto EC = SMReader.readObject(Header)) return EC; @@ -342,7 +342,7 @@ return Error::success(); const FileInfoSubstreamHeader *FH; - StreamReader FISR(FileInfoSubstream); + BinaryStreamReader FISR(FileInfoSubstream, little); if (auto EC = FISR.readObject(FH)) return EC; @@ -411,7 +411,7 @@ } Expected DbiStream::getFileNameForIndex(uint32_t Index) const { - StreamReader Names(NamesBuffer); + BinaryStreamReader Names(NamesBuffer, little); if (Index >= FileNameOffsets.size()) return make_error(raw_error_code::index_out_of_bounds); Index: llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp @@ -12,10 +12,10 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamWriter.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; @@ -153,9 +153,9 @@ uint32_t Size = calculateModiSubstreamSize(); auto Data = Allocator.Allocate(Size); - ModInfoBuffer = MutableByteStream(MutableArrayRef(Data, Size)); + ModInfoBuffer = MutableBinaryByteStream(MutableArrayRef(Data, Size)); - StreamWriter ModiWriter(ModInfoBuffer); + BinaryStreamWriter ModiWriter(ModInfoBuffer, llvm::support::little); for (const auto &M : ModuleInfoList) { ModuleInfoHeader Layout = {}; Layout.ModDiStream = kInvalidStreamIndex; @@ -179,29 +179,26 @@ auto Data = Allocator.Allocate(Size); uint32_t NamesOffset = Size - NameSize; - FileInfoBuffer = MutableByteStream(MutableArrayRef(Data, Size)); + FileInfoBuffer = + MutableBinaryByteStream(MutableArrayRef(Data, Size)); - WritableStreamRef MetadataBuffer = - WritableStreamRef(FileInfoBuffer).keep_front(NamesOffset); - StreamWriter MetadataWriter(MetadataBuffer); + WritableBinaryStreamRef MetadataBuffer = + WritableBinaryStreamRef(FileInfoBuffer).keep_front(NamesOffset); + BinaryStreamWriter MetadataWriter(MetadataBuffer, llvm::support::little); uint16_t ModiCount = std::min(UINT16_MAX, ModuleInfos.size()); uint16_t FileCount = std::min(UINT16_MAX, SourceFileNames.size()); - if (auto EC = MetadataWriter.writeInteger( - ModiCount, llvm::support::little)) // NumModules + if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules return EC; - if (auto EC = MetadataWriter.writeInteger( - FileCount, llvm::support::little)) // NumSourceFiles + if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles return EC; for (uint16_t I = 0; I < ModiCount; ++I) { - if (auto EC = MetadataWriter.writeInteger( - I, llvm::support::little)) // Mod Indices + if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices return EC; } for (const auto MI : ModuleInfoList) { FileCount = static_cast(MI->SourceFiles.size()); - if (auto EC = MetadataWriter.writeInteger( - FileCount, llvm::support::little)) // Mod File Counts + if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts return EC; } @@ -209,8 +206,8 @@ // A side effect of this is that this will actually compute the various // file name offsets, so we can then go back and write the FileNameOffsets // array to the other substream. - NamesBuffer = WritableStreamRef(FileInfoBuffer).drop_front(NamesOffset); - StreamWriter NameBufferWriter(NamesBuffer); + NamesBuffer = WritableBinaryStreamRef(FileInfoBuffer).drop_front(NamesOffset); + BinaryStreamWriter NameBufferWriter(NamesBuffer, llvm::support::little); for (auto &Name : SourceFileNames) { Name.second = NameBufferWriter.getOffset(); if (auto EC = NameBufferWriter.writeZeroString(Name.getKey())) @@ -223,8 +220,7 @@ if (Result == SourceFileNames.end()) return make_error(raw_error_code::no_entry, "The source file was not found."); - if (auto EC = MetadataWriter.writeInteger(Result->second, - llvm::support::little)) + if (auto EC = MetadataWriter.writeInteger(Result->second)) return EC; } } @@ -363,14 +359,14 @@ } Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout, - const msf::WritableStream &Buffer) { + WritableBinaryStreamRef Buffer) { if (auto EC = finalize()) return EC; auto InfoS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamDBI); - StreamWriter Writer(*InfoS); + BinaryStreamWriter Writer(*InfoS, llvm::support::little); if (auto EC = Writer.writeObject(*Header)) return EC; @@ -378,7 +374,7 @@ return EC; if (!SectionContribs.empty()) { - if (auto EC = Writer.writeEnum(DbiSecContribVer60, llvm::support::little)) + if (auto EC = Writer.writeEnum(DbiSecContribVer60)) return EC; if (auto EC = Writer.writeArray(SectionContribs)) return EC; @@ -397,8 +393,7 @@ return EC; for (auto &Stream : DbgStreams) - if (auto EC = - Writer.writeInteger(Stream.StreamNumber, llvm::support::little)) + if (auto EC = Writer.writeInteger(Stream.StreamNumber)) return EC; for (auto &Stream : DbgStreams) { @@ -406,7 +401,7 @@ continue; auto WritableStream = WritableMappedBlockStream::createIndexedStream( Layout, Buffer, Stream.StreamNumber); - StreamWriter DbgStreamWriter(*WritableStream); + BinaryStreamWriter DbgStreamWriter(*WritableStream, llvm::support::little); if (auto EC = DbgStreamWriter.writeArray(Stream.Data)) return EC; } Index: llvm/lib/DebugInfo/PDB/Native/GSI.h =================================================================== --- llvm/lib/DebugInfo/PDB/Native/GSI.h +++ llvm/lib/DebugInfo/PDB/Native/GSI.h @@ -25,17 +25,15 @@ #ifndef LLVM_LIB_DEBUGINFO_PDB_RAW_GSI_H #define LLVM_LIB_DEBUGINFO_PDB_RAW_GSI_H -#include "llvm/DebugInfo/MSF/StreamArray.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamArray.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" namespace llvm { -namespace msf { -class StreamReader; -} +class BinaryStreamReader; namespace pdb { @@ -56,14 +54,14 @@ support::ulittle32_t NumBuckets; }; -Error readGSIHashBuckets( - msf::FixedStreamArray &HashBuckets, - const GSIHashHeader *HashHdr, msf::StreamReader &Reader); +Error readGSIHashBuckets(FixedStreamArray &HashBuckets, + const GSIHashHeader *HashHdr, + BinaryStreamReader &Reader); Error readGSIHashHeader(const GSIHashHeader *&HashHdr, - msf::StreamReader &Reader); -Error readGSIHashRecords(msf::FixedStreamArray &HashRecords, + BinaryStreamReader &Reader); +Error readGSIHashRecords(FixedStreamArray &HashRecords, const GSIHashHeader *HashHdr, - msf::StreamReader &Reader); + BinaryStreamReader &Reader); } } Index: llvm/lib/DebugInfo/PDB/Native/GSI.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/GSI.cpp +++ llvm/lib/DebugInfo/PDB/Native/GSI.cpp @@ -9,11 +9,11 @@ #include "GSI.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamReader.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" namespace llvm { @@ -28,9 +28,9 @@ return Error::success(); } -Error readGSIHashBuckets( - msf::FixedStreamArray &HashBuckets, - const GSIHashHeader *HashHdr, msf::StreamReader &Reader) { +Error readGSIHashBuckets(FixedStreamArray &HashBuckets, + const GSIHashHeader *HashHdr, + BinaryStreamReader &Reader) { if (auto EC = checkHashHdrVersion(HashHdr)) return EC; @@ -57,7 +57,7 @@ } Error readGSIHashHeader(const GSIHashHeader *&HashHdr, - msf::StreamReader &Reader) { + BinaryStreamReader &Reader) { if (Reader.readObject(HashHdr)) return make_error(raw_error_code::corrupt_file, "Stream does not contain a GSIHashHeader."); @@ -70,9 +70,9 @@ return Error::success(); } -Error readGSIHashRecords(msf::FixedStreamArray &HashRecords, +Error readGSIHashRecords(FixedStreamArray &HashRecords, const GSIHashHeader *HashHdr, - msf::StreamReader &Reader) { + BinaryStreamReader &Reader) { if (auto EC = checkHashHdrVersion(HashHdr)) return EC; Index: llvm/lib/DebugInfo/PDB/Native/GlobalsStream.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/GlobalsStream.cpp +++ llvm/lib/DebugInfo/PDB/Native/GlobalsStream.cpp @@ -9,7 +9,7 @@ #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" #include "GSI.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Error.h" #include @@ -23,7 +23,7 @@ GlobalsStream::~GlobalsStream() = default; Error GlobalsStream::reload() { - StreamReader Reader(*Stream); + BinaryStreamReader Reader(*Stream, llvm::support::little); const GSIHashHeader *HashHdr; if (auto EC = readGSIHashHeader(HashHdr, Reader)) Index: llvm/lib/DebugInfo/PDB/Native/HashTable.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/HashTable.cpp +++ llvm/lib/DebugInfo/PDB/Native/HashTable.cpp @@ -22,7 +22,7 @@ HashTable::HashTable(uint32_t Capacity) { Buckets.resize(Capacity); } -Error HashTable::load(msf::StreamReader &Stream) { +Error HashTable::load(BinaryStreamReader &Stream) { const Header *H; if (auto EC = Stream.readObject(H)) return EC; @@ -48,9 +48,9 @@ "Present bit vector interesects deleted!"); for (uint32_t P : Present) { - if (auto EC = Stream.readInteger(Buckets[P].first, llvm::support::little)) + if (auto EC = Stream.readInteger(Buckets[P].first)) return EC; - if (auto EC = Stream.readInteger(Buckets[P].second, llvm::support::little)) + if (auto EC = Stream.readInteger(Buckets[P].second)) return EC; } @@ -77,7 +77,7 @@ return Size; } -Error HashTable::commit(msf::StreamWriter &Writer) const { +Error HashTable::commit(BinaryStreamWriter &Writer) const { Header H; H.Size = size(); H.Capacity = capacity(); @@ -91,9 +91,9 @@ return EC; for (const auto &Entry : *this) { - if (auto EC = Writer.writeInteger(Entry.first, llvm::support::little)) + if (auto EC = Writer.writeInteger(Entry.first)) return EC; - if (auto EC = Writer.writeInteger(Entry.second, llvm::support::little)) + if (auto EC = Writer.writeInteger(Entry.second)) return EC; } return Error::success(); @@ -209,10 +209,10 @@ assert(size() == S); } -Error HashTable::readSparseBitVector(msf::StreamReader &Stream, +Error HashTable::readSparseBitVector(BinaryStreamReader &Stream, SparseBitVector<> &V) { uint32_t NumWords; - if (auto EC = Stream.readInteger(NumWords, llvm::support::little)) + if (auto EC = Stream.readInteger(NumWords)) return joinErrors( std::move(EC), make_error(raw_error_code::corrupt_file, @@ -220,7 +220,7 @@ for (uint32_t I = 0; I != NumWords; ++I) { uint32_t Word; - if (auto EC = Stream.readInteger(Word, llvm::support::little)) + if (auto EC = Stream.readInteger(Word)) return joinErrors(std::move(EC), make_error(raw_error_code::corrupt_file, "Expected hash table word")); @@ -231,11 +231,11 @@ return Error::success(); } -Error HashTable::writeSparseBitVector(msf::StreamWriter &Writer, +Error HashTable::writeSparseBitVector(BinaryStreamWriter &Writer, SparseBitVector<> &Vec) { int ReqBits = Vec.find_last() + 1; uint32_t NumWords = alignTo(ReqBits, sizeof(uint32_t)) / sizeof(uint32_t); - if (auto EC = Writer.writeInteger(NumWords, llvm::support::little)) + if (auto EC = Writer.writeInteger(NumWords)) return joinErrors( std::move(EC), make_error(raw_error_code::corrupt_file, @@ -248,7 +248,7 @@ if (Vec.test(Idx)) Word |= (1 << WordIdx); } - if (auto EC = Writer.writeInteger(Word, llvm::support::little)) + if (auto EC = Writer.writeInteger(Word)) return joinErrors(std::move(EC), make_error( raw_error_code::corrupt_file, "Could not write linear map word")); Index: llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/InfoStream.cpp +++ llvm/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/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamWriter.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; @@ -26,7 +26,7 @@ : Stream(std::move(Stream)) {} Error InfoStream::reload() { - StreamReader Reader(*Stream); + BinaryStreamReader Reader(*Stream, llvm::support::little); const InfoStreamHeader *H; if (auto EC = Reader.readObject(H)) Index: llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp @@ -11,12 +11,12 @@ #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h" #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; @@ -44,10 +44,10 @@ } Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout, - const msf::WritableStream &Buffer) const { + WritableBinaryStreamRef Buffer) const { auto InfoS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StreamPDB); - StreamWriter Writer(*InfoS); + BinaryStreamWriter Writer(*InfoS, llvm::support::little); InfoStreamHeader H; H.Age = Age; Index: llvm/lib/DebugInfo/PDB/Native/ModInfo.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/ModInfo.cpp +++ llvm/lib/DebugInfo/PDB/Native/ModInfo.cpp @@ -8,15 +8,15 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Native/ModInfo.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" #include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/MathExtras.h" #include using namespace llvm; -using namespace llvm::msf; using namespace llvm::pdb; using namespace llvm::support; @@ -26,8 +26,8 @@ ModInfo::~ModInfo() = default; -Error ModInfo::initialize(ReadableStreamRef Stream, ModInfo &Info) { - StreamReader Reader(Stream); +Error ModInfo::initialize(BinaryStreamRef Stream, ModInfo &Info) { + BinaryStreamReader Reader(Stream, little); if (auto EC = Reader.readObject(Info.Layout)) return EC; Index: llvm/lib/DebugInfo/PDB/Native/ModStream.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/ModStream.cpp +++ llvm/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/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamRef.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 @@ -31,7 +31,7 @@ ModStream::~ModStream() = default; Error ModStream::reload() { - StreamReader Reader(*Stream); + BinaryStreamReader Reader(*Stream, llvm::support::little); uint32_t SymbolSize = Mod.getSymbolDebugInfoByteSize(); uint32_t C11Size = Mod.getLineInfoByteSize(); @@ -41,9 +41,9 @@ return make_error(raw_error_code::corrupt_file, "Module has both C11 and C13 line info"); - ReadableStreamRef S; + BinaryStreamRef S; - if (auto EC = Reader.readInteger(Signature, llvm::support::little)) + if (auto EC = Reader.readInteger(Signature)) return EC; if (auto EC = Reader.readArray(SymbolsSubstream, SymbolSize - 4)) return EC; @@ -53,12 +53,12 @@ if (auto EC = Reader.readStreamRef(C13LinesSubstream, C13Size)) return EC; - StreamReader LineReader(C13LinesSubstream); + BinaryStreamReader LineReader(C13LinesSubstream, llvm::support::little); if (auto EC = LineReader.readArray(LineInfo, LineReader.bytesRemaining())) return EC; uint32_t GlobalRefsSize; - if (auto EC = Reader.readInteger(GlobalRefsSize, llvm::support::little)) + if (auto EC = Reader.readInteger(GlobalRefsSize)) return EC; if (auto EC = Reader.readStreamRef(GlobalRefsSubstream, GlobalRefsSize)) return EC; Index: llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp +++ llvm/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp @@ -13,31 +13,30 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" -#include "llvm/DebugInfo/MSF/StreamReader.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 using namespace llvm; -using namespace llvm::msf; using namespace llvm::pdb; NamedStreamMap::NamedStreamMap() = default; -Error NamedStreamMap::load(StreamReader &Stream) { +Error NamedStreamMap::load(BinaryStreamReader &Stream) { Mapping.clear(); FinalizedHashTable.clear(); FinalizedInfo.reset(); uint32_t StringBufferSize; - if (auto EC = Stream.readInteger(StringBufferSize, llvm::support::little)) + if (auto EC = Stream.readInteger(StringBufferSize)) return joinErrors(std::move(EC), make_error(raw_error_code::corrupt_file, "Expected string buffer size")); - msf::ReadableStreamRef StringsBuffer; + BinaryStreamRef StringsBuffer; if (auto EC = Stream.readStreamRef(StringsBuffer, StringBufferSize)) return EC; @@ -51,7 +50,7 @@ std::tie(NameOffset, NameIndex) = Entry; // Compute the offset of the start of the string relative to the stream. - msf::StreamReader NameReader(StringsBuffer); + BinaryStreamReader NameReader(StringsBuffer, llvm::support::little); NameReader.setOffset(NameOffset); // Pump out our c-string from the stream. StringRef Str; @@ -67,12 +66,11 @@ return Error::success(); } -Error NamedStreamMap::commit(msf::StreamWriter &Writer) const { +Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const { assert(FinalizedInfo.hasValue()); // The first field is the number of bytes of string data. - if (auto EC = Writer.writeInteger(FinalizedInfo->StringDataBytes, - llvm::support::little)) + if (auto EC = Writer.writeInteger(FinalizedInfo->StringDataBytes)) return EC; // Now all of the string data itself. Index: llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp +++ llvm/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/ByteStream.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" @@ -19,6 +18,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/lib/DebugInfo/PDB/Native/PDBFile.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp +++ llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp @@ -12,9 +12,6 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.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" @@ -39,7 +39,7 @@ typedef FixedStreamArray ulittle_array; } // end anonymous namespace -PDBFile::PDBFile(StringRef Path, std::unique_ptr PdbFileBuffer, +PDBFile::PDBFile(StringRef Path, std::unique_ptr PdbFileBuffer, BumpPtrAllocator &Allocator) : FilePath(Path), Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {} @@ -113,7 +113,7 @@ } Error PDBFile::parseFileHeaders() { - StreamReader Reader(*Buffer); + BinaryStreamReader Reader(*Buffer, llvm::support::little); // Initialize SB. const msf::SuperBlock *SB = nullptr; @@ -147,7 +147,7 @@ // See the function fpmPn() for more information: // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489 auto FpmStream = MappedBlockStream::createFpmStream(ContainerLayout, *Buffer); - StreamReader FpmReader(*FpmStream); + BinaryStreamReader FpmReader(*FpmStream, llvm::support::little); ArrayRef FpmBytes; if (auto EC = FpmReader.readBytes(FpmBytes, msf::getFullFpmByteSize(ContainerLayout))) @@ -185,8 +185,8 @@ // subclass of IPDBStreamData which only accesses the fields that have already // been parsed, we can avoid this and reuse MappedBlockStream. auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer); - StreamReader Reader(*DS); - if (auto EC = Reader.readInteger(NumStreams, llvm::support::little)) + BinaryStreamReader Reader(*DS, llvm::support::little); + if (auto EC = Reader.readInteger(NumStreams)) return EC; if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams)) @@ -350,7 +350,7 @@ if (!NS) return NS.takeError(); - StreamReader Reader(**NS); + BinaryStreamReader Reader(**NS, llvm::support::little); auto N = llvm::make_unique(); if (auto EC = N->load(Reader)) return std::move(EC); @@ -403,7 +403,7 @@ /// contain the stream returned by createIndexedStream(). Expected> PDBFile::safelyCreateIndexedStream(const MSFLayout &Layout, - const ReadableStream &MsfData, + BinaryStreamRef MsfData, uint32_t StreamIndex) const { if (StreamIndex >= getNumStreams()) return make_error(raw_error_code::no_stream); Index: llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp @@ -12,8 +12,6 @@ #include "llvm/ADT/BitVector.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/DebugInfo/MSF/StreamInterface.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.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; @@ -119,7 +119,7 @@ return llvm::make_error(generic_error_code::invalid_path, Filename); FileBufferByteStream Buffer(std::move(*OutFileOrError)); - StreamWriter Writer(Buffer); + BinaryStreamWriter Writer(Buffer, llvm::support::little); if (auto EC = Writer.writeObject(*Layout.SB)) return EC; @@ -131,9 +131,8 @@ auto DirStream = WritableMappedBlockStream::createDirectoryStream(Layout, Buffer); - StreamWriter DW(*DirStream); - if (auto EC = DW.writeInteger(Layout.StreamSizes.size(), - llvm::support::little)) + BinaryStreamWriter DW(*DirStream, llvm::support::little); + if (auto EC = DW.writeInteger(Layout.StreamSizes.size())) return EC; if (auto EC = DW.writeArray(Layout.StreamSizes)) @@ -150,7 +149,7 @@ auto NS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, StringTableStreamNo); - StreamWriter NSWriter(*NS); + BinaryStreamWriter NSWriter(*NS, llvm::support::little); if (auto EC = Strings.commit(NSWriter)) return EC; Index: llvm/lib/DebugInfo/PDB/Native/PublicsStream.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/PublicsStream.cpp +++ llvm/lib/DebugInfo/PDB/Native/PublicsStream.cpp @@ -27,10 +27,10 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.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 @@ -69,7 +69,7 @@ // we skip over the hash table which we believe contains information about // public symbols. Error PublicsStream::reload() { - StreamReader Reader(*Stream); + BinaryStreamReader Reader(*Stream, llvm::support::little); // Check stream size. if (Reader.bytesRemaining() < sizeof(HeaderInfo) + sizeof(GSIHashHeader)) Index: llvm/lib/DebugInfo/PDB/Native/StringTable.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/StringTable.cpp +++ llvm/lib/DebugInfo/PDB/Native/StringTable.cpp @@ -10,20 +10,19 @@ #include "llvm/DebugInfo/PDB/Native/StringTable.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/MSF/StreamReader.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; -using namespace llvm::msf; using namespace llvm::support; using namespace llvm::pdb; StringTable::StringTable() : Signature(0), HashVersion(0), NameCount(0) {} -Error StringTable::load(StreamReader &Stream) { +Error StringTable::load(BinaryStreamReader &Stream) { const StringTableHeader *H; if (auto EC = Stream.readObject(H)) return EC; @@ -55,7 +54,7 @@ return make_error(raw_error_code::corrupt_file, "Missing name count"); - if (auto EC = Stream.readInteger(NameCount, llvm::support::little)) + if (auto EC = Stream.readInteger(NameCount)) return EC; return Error::success(); } @@ -68,7 +67,7 @@ // the starting offset of the string we're looking for. So just seek into // the desired offset and a read a null terminated stream from that offset. StringRef Result; - StreamReader NameReader(NamesBuffer); + BinaryStreamReader NameReader(NamesBuffer, llvm::support::little); NameReader.setOffset(ID); if (auto EC = NameReader.readZeroString(Result)) consumeError(std::move(EC)); Index: llvm/lib/DebugInfo/PDB/Native/StringTableBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/StringTableBuilder.cpp +++ llvm/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/StreamWriter.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; @@ -52,7 +52,7 @@ return Size; } -Error StringTableBuilder::commit(msf::StreamWriter &Writer) const { +Error StringTableBuilder::commit(BinaryStreamWriter &Writer) const { // Write a header StringTableHeader H; H.Signature = StringTableSignature; @@ -74,7 +74,7 @@ // Write a hash table. uint32_t BucketCount = computeBucketCount(Strings.size()); - if (auto EC = Writer.writeInteger(BucketCount, llvm::support::little)) + if (auto EC = Writer.writeInteger(BucketCount)) return EC; std::vector Buckets(BucketCount); @@ -96,8 +96,7 @@ if (auto EC = Writer.writeArray(ArrayRef(Buckets))) return EC; - if (auto EC = Writer.writeInteger(static_cast(Strings.size()), - llvm::support::little)) + if (auto EC = Writer.writeInteger(static_cast(Strings.size()))) return EC; return Error::success(); } Index: llvm/lib/DebugInfo/PDB/Native/SymbolStream.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/SymbolStream.cpp +++ llvm/lib/DebugInfo/PDB/Native/SymbolStream.cpp @@ -12,11 +12,11 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.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; @@ -30,7 +30,7 @@ SymbolStream::~SymbolStream() {} Error SymbolStream::reload() { - StreamReader Reader(*Stream); + BinaryStreamReader Reader(*Stream, llvm::support::little); if (auto EC = Reader.readArray(SymbolRecords, Stream->getLength())) return EC; Index: llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp +++ llvm/lib/DebugInfo/PDB/Native/TpiStream.cpp @@ -14,13 +14,13 @@ #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h" #include "llvm/DebugInfo/PDB/Native/RawConstants.h" #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 @@ -54,7 +54,7 @@ } Error TpiStream::reload() { - StreamReader Reader(*Stream); + BinaryStreamReader Reader(*Stream, llvm::support::little); if (Reader.bytesRemaining() < sizeof(TpiStreamHeader)) return make_error(raw_error_code::corrupt_file, @@ -93,7 +93,7 @@ auto HS = MappedBlockStream::createIndexedStream( Pdb.getMsfLayout(), Pdb.getMsfBuffer(), Header->HashStreamIndex); - StreamReader HSR(*HS); + BinaryStreamReader HSR(*HS, llvm::support::little); uint32_t NumHashValues = Header->HashValueBuffer.Length / sizeof(ulittle32_t); Index: llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp +++ llvm/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp @@ -12,17 +12,17 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamArray.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" #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 @@ -82,7 +82,7 @@ return Error::success(); } -uint32_t TpiStreamBuilder::calculateSerializedLength() const { +uint32_t TpiStreamBuilder::calculateSerializedLength() { return sizeof(TpiStreamHeader) + TypeRecordStream.getLength(); } @@ -113,19 +113,19 @@ } ArrayRef Bytes(reinterpret_cast(HashBuffer.data()), HashBufferSize); - HashValueStream = llvm::make_unique(Bytes); + HashValueStream = llvm::make_unique(Bytes); return Error::success(); } Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout, - const msf::WritableStream &Buffer) { + WritableBinaryStreamRef Buffer) { if (auto EC = finalize()) return EC; auto InfoS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, Idx); - StreamWriter Writer(*InfoS); + BinaryStreamWriter Writer(*InfoS, llvm::support::little); if (auto EC = Writer.writeObject(*Header)) return EC; @@ -136,7 +136,7 @@ if (HashStreamIndex != kInvalidStreamIndex) { auto HVS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer, HashStreamIndex); - StreamWriter HW(*HVS); + BinaryStreamWriter HW(*HVS, llvm::support::little); if (auto EC = HW.writeStreamRef(*HashValueStream)) return EC; } Index: llvm/lib/Support/BinaryStreamReader.cpp =================================================================== --- /dev/null +++ llvm/lib/Support/BinaryStreamReader.cpp @@ -0,0 +1,94 @@ +//===- 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/BinaryStreamRef.h" + +using namespace llvm; + +BinaryStreamReader::BinaryStreamReader(BinaryStreamRef S, + llvm::support::endianness Endian) + : Stream(S), Offset(0), Endian(Endian) {} + +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::readZeroString(StringRef &Dest) { + 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); + + ArrayRef Data; + if (auto EC = readBytes(Data, Length)) + return EC; + Dest = StringRef(reinterpret_cast(Data.begin()), Data.size()); + + // 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 errorCodeToError(make_error_code(std::errc::no_buffer_space)); + Ref = Stream.slice(Offset, Length); + Offset += Length; + return Error::success(); +} + +Error BinaryStreamReader::skip(uint32_t Amount) { + if (Amount > bytesRemaining()) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + 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/lib/Support/BinaryStreamWriter.cpp =================================================================== --- /dev/null +++ llvm/lib/Support/BinaryStreamWriter.cpp @@ -0,0 +1,71 @@ +//===- 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, + llvm::support::endianness Endian) + : Stream(S), Offset(0), Endian(Endian) {} + +Error BinaryStreamWriter::writeBytes(ArrayRef Buffer) { + if (auto EC = Stream.writeBytes(Offset, Buffer)) + return EC; + Offset += Buffer.size(); + return Error::success(); +} + +Error BinaryStreamWriter::writeZeroString(StringRef Str) { + if (auto EC = writeFixedString(Str)) + return EC; + if (auto EC = writeObject('\0')) + return EC; + + return Error::success(); +} + +Error BinaryStreamWriter::writeFixedString(StringRef Str) { + ArrayRef Bytes(Str.bytes_begin(), Str.bytes_end()); + if (auto EC = Stream.writeBytes(Offset, Bytes)) + return EC; + + Offset += Str.size(); + return Error::success(); +} + +Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref) { + if (auto EC = writeStreamRef(Ref, Ref.getLength())) + return EC; + // Don't increment Offset here, it is done by the overloaded call to + // writeStreamRef. + return Error::success(); +} + +Error BinaryStreamWriter::writeStreamRef(BinaryStreamRef Ref, uint32_t Length) { + Ref = Ref.slice(0, Length); + + BinaryStreamReader SrcReader(Ref, Endian); + // 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/lib/Support/CMakeLists.txt =================================================================== --- llvm/lib/Support/CMakeLists.txt +++ llvm/lib/Support/CMakeLists.txt @@ -94,6 +94,8 @@ SystemUtils.cpp TarWriter.cpp TargetParser.cpp + BinaryStreamReader.cpp + BinaryStreamWriter.cpp ThreadPool.cpp Timer.cpp ToolOutputFile.cpp Index: llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp =================================================================== --- llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp @@ -22,7 +22,6 @@ #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/EnumTables.h" #include "llvm/DebugInfo/PDB/Native/GlobalsStream.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 @@ -450,7 +450,7 @@ auto Blocks = File.getMsfLayout().StreamMap[SI]; P.printList("Blocks", Blocks); - StreamReader R(*S); + BinaryStreamReader R(*S, llvm::support::little); ArrayRef StreamData; if (auto EC = R.readBytes(StreamData, S->getLength())) return EC; @@ -745,10 +745,10 @@ public: RecordVisitor(ScopedPrinter &P, PDBFile &F) : P(P), F(F) {} Error visitUnknown(ModuleSubstreamKind Kind, - ReadableStreamRef Stream) override { + BinaryStreamRef Stream) override { DictScope DD(P, "Unknown"); ArrayRef Data; - StreamReader R(Stream); + BinaryStreamReader R(Stream, llvm::support::little); if (auto EC = R.readBytes(Data, R.bytesRemaining())) { return make_error( raw_error_code::corrupt_file, @@ -758,7 +758,7 @@ return Error::success(); } Error - visitFileChecksums(ReadableStreamRef Data, + visitFileChecksums(BinaryStreamRef Data, const FileChecksumArray &Checksums) override { DictScope DD(P, "FileChecksums"); for (const auto &C : Checksums) { @@ -774,7 +774,7 @@ return Error::success(); } - Error visitLines(ReadableStreamRef Data, + Error visitLines(BinaryStreamRef Data, const LineSubstreamHeader *Header, const LineInfoArray &Lines) override { DictScope DD(P, "Lines"); Index: llvm/tools/llvm-pdbdump/YamlTypeDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/YamlTypeDumper.cpp +++ llvm/tools/llvm-pdbdump/YamlTypeDumper.cpp @@ -573,8 +573,8 @@ assert(IO.outputting()); codeview::TypeVisitorCallbackPipeline Pipeline; - msf::ByteStream Data(Obj.Record.Data); - msf::StreamReader FieldReader(Data); + BinaryByteStream Data(Obj.Record.Data); + BinaryStreamReader FieldReader(Data, llvm::support::little); codeview::FieldListDeserializer Deserializer(FieldReader); // For PDB to Yaml, deserialize into a high level record type, then dump Index: llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ llvm/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/ByteStream.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" Index: llvm/tools/llvm-readobj/COFFDumper.cpp =================================================================== --- llvm/tools/llvm-readobj/COFFDumper.cpp +++ llvm/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/ByteStream.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" @@ -56,7 +56,6 @@ using namespace llvm; using namespace llvm::object; using namespace llvm::codeview; -using namespace llvm::msf; using namespace llvm::support; using namespace llvm::Win64EH; @@ -155,7 +154,7 @@ Sec = Obj->getCOFFSection(SR); } - uint32_t getRecordOffset(msf::StreamReader Reader) override { + uint32_t getRecordOffset(BinaryStreamReader Reader) override { ArrayRef Data; if (auto EC = Reader.readLongestContiguousChunk(Data)) { llvm::consumeError(std::move(EC)); @@ -841,8 +840,8 @@ } case ModuleSubstreamKind::FrameData: { // First four bytes is a relocation against the function. - msf::ByteStream S(Contents); - msf::StreamReader SR(S); + BinaryByteStream S(Contents); + BinaryStreamReader SR(S, llvm::support::little); const uint32_t *CodePtr; error(SR.readObject(CodePtr)); StringRef LinkageName; @@ -966,9 +965,9 @@ CVSymbolDumper CVSD(W, TypeDB, std::move(CODD), opts::CodeViewSubsectionBytes); - ByteStream Stream(BinaryData); + BinaryByteStream Stream(BinaryData); CVSymbolArray Symbols; - StreamReader Reader(Stream); + BinaryStreamReader Reader(Stream, llvm::support::little); if (auto EC = Reader.readArray(Symbols, Reader.getLength())) { consumeError(std::move(EC)); W.flush(); @@ -983,8 +982,8 @@ } void COFFDumper::printCodeViewFileChecksums(StringRef Subsection) { - msf::ByteStream S(Subsection); - msf::StreamReader SR(S); + BinaryByteStream S(Subsection); + BinaryStreamReader SR(S, llvm::support::little); while (!SR.empty()) { DictScope S(W, "FileChecksum"); const FileChecksum *FC; @@ -1012,10 +1011,10 @@ } void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) { - msf::ByteStream S(Subsection); - msf::StreamReader SR(S); + BinaryByteStream S(Subsection); + BinaryStreamReader SR(S, llvm::support::little); uint32_t Signature; - error(SR.readInteger(Signature, llvm::support::little)); + error(SR.readInteger(Signature)); bool HasExtraFiles = Signature == unsigned(InlineeLinesSignature::ExtraFiles); while (!SR.empty()) { @@ -1028,12 +1027,12 @@ if (HasExtraFiles) { uint32_t ExtraFileCount; - error(SR.readInteger(ExtraFileCount, llvm::support::little)); + error(SR.readInteger(ExtraFileCount)); W.printNumber("ExtraFileCount", ExtraFileCount); ListScope ExtraFiles(W, "ExtraFiles"); for (unsigned I = 0; I < ExtraFileCount; ++I) { uint32_t FileID; - error(SR.readInteger(FileID, llvm::support::little)); + error(SR.readInteger(FileID)); printFileNameForOffset("FileID", FileID); } } @@ -1078,9 +1077,9 @@ error(object_error::parse_failed); ArrayRef Bytes(reinterpret_cast(Data.data()), Data.size()); - ByteStream Stream(Bytes); + BinaryByteStream Stream(Bytes); CVTypeArray Types; - StreamReader Reader(Stream); + BinaryStreamReader Reader(Stream, llvm::support::little); if (auto EC = Reader.readArray(Types, Reader.getLength())) { consumeError(std::move(EC)); W.flush(); Index: llvm/unittests/DebugInfo/PDB/HashTableTest.cpp =================================================================== --- llvm/unittests/DebugInfo/PDB/HashTableTest.cpp +++ llvm/unittests/DebugInfo/PDB/HashTableTest.cpp @@ -10,10 +10,10 @@ #include "ErrorChecking.h" #include "gtest/gtest.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamWriter.h" #include "llvm/DebugInfo/PDB/Native/HashTable.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamWriter.h" #include @@ -147,14 +147,14 @@ } std::vector Buffer(Table.calculateSerializedLength()); - msf::MutableByteStream Stream(Buffer); - msf::StreamWriter Writer(Stream); + MutableBinaryByteStream Stream(Buffer); + BinaryStreamWriter Writer(Stream, llvm::support::little); EXPECT_NO_ERROR(Table.commit(Writer)); // We should have written precisely the number of bytes we calculated earlier. EXPECT_EQ(Buffer.size(), Writer.getOffset()); HashTableInternals Table2; - msf::StreamReader Reader(Stream); + BinaryStreamReader Reader(Stream, llvm::support::little); EXPECT_NO_ERROR(Table2.load(Reader)); // We should have read precisely the number of bytes we calculated earlier. EXPECT_EQ(Buffer.size(), Reader.getOffset()); Index: llvm/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp =================================================================== --- llvm/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp +++ llvm/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp @@ -9,13 +9,13 @@ #include "ErrorChecking.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" #include "llvm/DebugInfo/MSF/IMSFFile.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" #include "llvm/DebugInfo/MSF/MSFStreamLayout.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamRef.h" -#include "llvm/DebugInfo/MSF/StreamWriter.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 @@ -28,7 +28,7 @@ static const uint32_t BlocksAry[] = {0, 1, 2, 5, 4, 3, 6, 7, 8, 9}; static uint8_t DataAry[] = {'A', 'B', 'C', 'F', 'E', 'D', 'G', 'H', 'I', 'J'}; -class DiscontiguousStream : public WritableStream { +class DiscontiguousStream : public WritableBinaryStream { public: DiscontiguousStream(ArrayRef Blocks, MutableArrayRef Data) : Blocks(Blocks.begin(), Blocks.end()), Data(Data.begin(), Data.end()) {} @@ -39,7 +39,7 @@ Error readBytes(uint32_t Offset, uint32_t Size, ArrayRef &Buffer) const override { if (Offset + Size > Data.size()) - return make_error(msf_error_code::insufficient_buffer); + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); Buffer = Data.slice(Offset, Size); return Error::success(); } @@ -47,7 +47,7 @@ Error readLongestContiguousChunk(uint32_t Offset, ArrayRef &Buffer) const override { if (Offset >= Data.size()) - return make_error(msf_error_code::insufficient_buffer); + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); Buffer = Data.drop_front(Offset); return Error::success(); } @@ -56,7 +56,7 @@ Error writeBytes(uint32_t Offset, ArrayRef SrcData) const override { if (Offset + SrcData.size() > Data.size()) - return make_error(msf_error_code::insufficient_buffer); + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); ::memcpy(&Data[Offset], SrcData.data(), SrcData.size()); return Error::success(); } @@ -78,8 +78,8 @@ auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(), F.layout(), F); - StreamReader R(*S); - ReadableStreamRef SR; + BinaryStreamReader R(*S, llvm::support::little); + BinaryStreamRef SR; EXPECT_NO_ERROR(R.readStreamRef(SR, 0U)); ArrayRef Buffer; EXPECT_ERROR(SR.readBytes(0U, 1U, Buffer)); @@ -94,7 +94,7 @@ auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(), F.layout(), F); - StreamReader R(*S); + BinaryStreamReader R(*S, llvm::support::little); StringRef Str = "ZYXWVUTSRQPONMLKJIHGFEDCBA"; EXPECT_NO_ERROR(R.readFixedString(Str, 1)); EXPECT_EQ(Str, StringRef("A")); @@ -108,7 +108,7 @@ DiscontiguousStream F(BlocksAry, DataAry); auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(), F.layout(), F); - StreamReader R(*S); + BinaryStreamReader R(*S, llvm::support::little); StringRef Str; EXPECT_NO_ERROR(R.readFixedString(Str, 2)); EXPECT_EQ(Str, StringRef("AB")); @@ -127,7 +127,7 @@ DiscontiguousStream F(BlocksAry, DataAry); auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(), F.layout(), F); - StreamReader R(*S); + BinaryStreamReader R(*S, llvm::support::little); StringRef Str; EXPECT_NO_ERROR(R.readFixedString(Str, 10)); EXPECT_EQ(Str, StringRef("ABCDEFGHIJ")); @@ -140,7 +140,7 @@ DiscontiguousStream F(BlocksAry, DataAry); auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(), F.layout(), F); - StreamReader R(*S); + BinaryStreamReader R(*S, llvm::support::little); StringRef Str; R.setOffset(10); @@ -154,7 +154,7 @@ DiscontiguousStream F(BlocksAry, DataAry); auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(), F.layout(), F); - StreamReader R(*S); + BinaryStreamReader R(*S, llvm::support::little); StringRef Str; R.setOffset(6); @@ -168,7 +168,7 @@ DiscontiguousStream F(BlocksAry, DataAry); auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(), F.layout(), F); - StreamReader R(*S); + BinaryStreamReader R(*S, llvm::support::little); StringRef Str; EXPECT_ERROR(R.readFixedString(Str, 11)); @@ -181,7 +181,7 @@ DiscontiguousStream F(BlocksAry, DataAry); auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(), F.layout(), F); - StreamReader R(*S); + BinaryStreamReader R(*S, llvm::support::little); StringRef Str; EXPECT_NO_ERROR(R.readFixedString(Str, 1)); EXPECT_EQ(Str, StringRef("A")); @@ -195,7 +195,7 @@ DiscontiguousStream F(BlocksAry, DataAry); auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(), F.layout(), F); - StreamReader R(*S); + BinaryStreamReader R(*S, llvm::support::little); StringRef Str1; StringRef Str2; EXPECT_NO_ERROR(R.readFixedString(Str1, 7)); @@ -216,7 +216,7 @@ DiscontiguousStream F(BlocksAry, DataAry); auto S = MappedBlockStream::createStream(F.block_size(), F.block_count(), F.layout(), F); - StreamReader R(*S); + BinaryStreamReader R(*S, llvm::support::little); StringRef Str1; StringRef Str2; EXPECT_NO_ERROR(R.readFixedString(Str1, 6)); @@ -323,10 +323,10 @@ uint32_t intArr1[] = {890723408, 29082234}; ArrayRef intArray[] = {intArr0, intArr1}; - StreamReader Reader(*S); - StreamWriter Writer(*S); - EXPECT_NO_ERROR(Writer.writeInteger(u16[0], llvm::support::little)); - EXPECT_NO_ERROR(Reader.readInteger(u16[1], llvm::support::little)); + BinaryStreamReader Reader(*S, llvm::support::little); + BinaryStreamWriter Writer(*S, llvm::support::little); + EXPECT_NO_ERROR(Writer.writeInteger(u16[0])); + EXPECT_NO_ERROR(Reader.readInteger(u16[1])); EXPECT_EQ(u16[0], u16[1]); EXPECT_EQ(std::vector({0, 0x7A, 0xEC, 0, 0, 0, 0, 0, 0, 0}), DataBytes); @@ -334,8 +334,8 @@ Reader.setOffset(0); Writer.setOffset(0); ::memset(DataBytes.data(), 0, 10); - EXPECT_NO_ERROR(Writer.writeInteger(u32[0], llvm::support::little)); - EXPECT_NO_ERROR(Reader.readInteger(u32[1], llvm::support::little)); + EXPECT_NO_ERROR(Writer.writeInteger(u32[0])); + EXPECT_NO_ERROR(Reader.readInteger(u32[1])); EXPECT_EQ(u32[0], u32[1]); EXPECT_EQ(std::vector({0x17, 0x5C, 0x50, 0, 0, 0, 0x35, 0, 0, 0}), DataBytes); @@ -343,8 +343,8 @@ Reader.setOffset(0); Writer.setOffset(0); ::memset(DataBytes.data(), 0, 10); - EXPECT_NO_ERROR(Writer.writeEnum(Enum[0], llvm::support::little)); - EXPECT_NO_ERROR(Reader.readEnum(Enum[1], llvm::support::little)); + EXPECT_NO_ERROR(Writer.writeEnum(Enum[0])); + EXPECT_NO_ERROR(Reader.readEnum(Enum[1])); EXPECT_EQ(Enum[0], Enum[1]); EXPECT_EQ(std::vector({0x2C, 0x60, 0x4A, 0, 0, 0, 0, 0, 0, 0}), DataBytes); @@ -399,21 +399,21 @@ F.block_size(), F.block_count(), F.layout(), F); // First write "Test Str" into the source stream. - MutableByteStream SourceStream(SrcData); - StreamWriter SourceWriter(SourceStream); + MutableBinaryByteStream SourceStream(SrcData); + BinaryStreamWriter SourceWriter(SourceStream, llvm::support::little); EXPECT_NO_ERROR(SourceWriter.writeZeroString("Test Str")); EXPECT_EQ(SrcDataBytes, std::vector( {'T', 'e', 's', 't', ' ', 'S', 't', 'r', 0, 0})); // Then write the source stream into the dest stream. - StreamWriter DestWriter(*DestStream); + BinaryStreamWriter DestWriter(*DestStream, llvm::support::little); EXPECT_NO_ERROR(DestWriter.writeStreamRef(SourceStream)); EXPECT_EQ(DestDataBytes, std::vector( {'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0})); // Then read the string back out of the dest stream. StringRef Result; - StreamReader DestReader(*DestStream); + BinaryStreamReader DestReader(*DestStream, llvm::support::little); EXPECT_NO_ERROR(DestReader.readZeroString(Result)); EXPECT_EQ(Result, "Test Str"); } @@ -436,20 +436,20 @@ SrcF.block_size(), SrcF.block_count(), SrcF.layout(), SrcF); // First write "Test Str" into the source stream. - StreamWriter SourceWriter(*Src); + BinaryStreamWriter SourceWriter(*Src, llvm::support::little); EXPECT_NO_ERROR(SourceWriter.writeZeroString("Test Str")); EXPECT_EQ(SrcDataBytes, std::vector( {'e', 'T', 't', 't', ' ', 'S', 's', 'r', 0, 0})); // Then write the source stream into the dest stream. - StreamWriter DestWriter(*Dest); + BinaryStreamWriter DestWriter(*Dest, llvm::support::little); EXPECT_NO_ERROR(DestWriter.writeStreamRef(*Src)); EXPECT_EQ(DestDataBytes, std::vector( {'s', 'e', 'T', ' ', 'S', 't', 't', 'r', 0, 0})); // Then read the string back out of the dest stream. StringRef Result; - StreamReader DestReader(*Dest); + BinaryStreamReader DestReader(*Dest, llvm::support::little); EXPECT_NO_ERROR(DestReader.readZeroString(Result)); EXPECT_EQ(Result, "Test Str"); } Index: llvm/unittests/DebugInfo/PDB/StringTableBuilderTest.cpp =================================================================== --- llvm/unittests/DebugInfo/PDB/StringTableBuilderTest.cpp +++ llvm/unittests/DebugInfo/PDB/StringTableBuilderTest.cpp @@ -9,11 +9,11 @@ #include "ErrorChecking.h" -#include "llvm/DebugInfo/MSF/ByteStream.h" -#include "llvm/DebugInfo/MSF/StreamReader.h" -#include "llvm/DebugInfo/MSF/StreamWriter.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" @@ -33,13 +33,13 @@ EXPECT_EQ(9U, Builder.insert("baz")); std::vector Buffer(Builder.finalize()); - msf::MutableByteStream OutStream(Buffer); - msf::StreamWriter Writer(OutStream); + MutableBinaryByteStream OutStream(Buffer); + BinaryStreamWriter Writer(OutStream, llvm::support::little); EXPECT_NO_ERROR(Builder.commit(Writer)); // Reads the contents back. - msf::ByteStream InStream(Buffer); - msf::StreamReader Reader(InStream); + BinaryByteStream InStream(Buffer); + BinaryStreamReader Reader(InStream, llvm::support::little); StringTable Table; EXPECT_NO_ERROR(Table.load(Reader)); Index: llvm/unittests/Support/BinaryStreamTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/Support/BinaryStreamTest.cpp @@ -0,0 +1,698 @@ +//===- 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 DiscontiguousStream : public WritableBinaryStream { +public: + explicit DiscontiguousStream(uint32_t Size = 0) : PartitionIndex(Size / 2) { + Data.resize(Size); + } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) override { + if (Offset + Size > Data.size()) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + uint32_t S = startIndex(Offset); + auto Ref = makeArrayRef(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 (Offset >= Data.size()) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + uint32_t S = startIndex(Offset); + Buffer = makeArrayRef(Data).drop_front(S); + return Error::success(); + } + + uint32_t getLength() override { return Data.size(); } + + Error writeBytes(uint32_t Offset, ArrayRef SrcData) override { + if (Offset + SrcData.size() > Data.size()) + return errorCodeToError(make_error_code(std::errc::no_buffer_space)); + 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(); + } + + uint32_t PartitionIndex = 0; + // 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. + mutable std::vector Data; + mutable BumpPtrAllocator Allocator; +}; + +class BinaryStreamTest : public testing::Test { +public: + BinaryStreamTest() {} + + void SetUp() override { + InputData.clear(); + OutputData.clear(); + InputByteStream = BinaryByteStream(); + InputBrokenStream = DiscontiguousStream(); + OutputByteStream = MutableBinaryByteStream(); + OutputBrokenStream = DiscontiguousStream(); + } + +protected: + void initialize(ArrayRef Input, uint32_t OutputSize) { + InputData = Input; + + InputByteStream = BinaryByteStream(InputData); + InputBrokenStream = DiscontiguousStream(InputData.size()); + consumeError(InputBrokenStream.writeBytes(0, Input)); + + OutputData.resize(OutputSize); + OutputByteStream = MutableBinaryByteStream(OutputData); + OutputBrokenStream = DiscontiguousStream(OutputSize); + + InputStreams.push_back(&InputByteStream); + InputStreams.push_back(&InputBrokenStream); + OutputStreams.push_back(&OutputByteStream); + OutputStreams.push_back(&OutputBrokenStream); + } + + void initialize(uint32_t OutputSize) { + initialize(std::vector(), OutputSize); + } + + std::vector InputData; + std::vector OutputData; + + BinaryByteStream InputByteStream; + DiscontiguousStream InputBrokenStream; + + MutableBinaryByteStream OutputByteStream; + DiscontiguousStream OutputBrokenStream; + + std::vector InputStreams; + std::vector OutputStreams; +}; + +// Tests that a we can read from a BinaryByteStream without a StreamReader. +TEST_F(BinaryStreamTest, BinaryByteStreamProperties) { + std::vector InputData = {1, 2, 3, 4, 5}; + initialize(InputData, InputData.size()); + + for (auto Stream : InputStreams) { + ArrayRef Buffer; + + // 1. If the read fits it should work. + ASSERT_EQ(InputData.size(), Stream->getLength()); + ASSERT_NO_ERROR(Stream->readBytes(2, 1, Buffer)); + EXPECT_EQ(makeArrayRef(InputData).slice(2, 1), Buffer); + ASSERT_NO_ERROR(Stream->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->readBytes(4, 2, Buffer)); + } +} + +// Test that we can write to a BinaryStream without a StreamWriter. +TEST_F(BinaryStreamTest, MutableBinaryByteStreamProperties) { + std::vector InputData = {'T', 'e', 's', 't', '\0'}; + initialize(InputData, InputData.size()); + ASSERT_EQ(2, InputStreams.size()); + ASSERT_EQ(2, OutputStreams.size()); + + // For every combination of input stream and output stream. + for (auto IS : InputStreams) { + MutableArrayRef Buffer; + ASSERT_EQ(InputData.size(), IS->getLength()); + + for (auto OS : OutputStreams) { + + // 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 = IS->getLength() - Offset; + + // Read everything from Offset until the end of the input data. + ArrayRef Data; + ASSERT_NO_ERROR(IS->readBytes(Offset, ExpectedSize, Data)); + ASSERT_EQ(ExpectedSize, Data.size()); + + // Then write it to the destination. + ASSERT_NO_ERROR(OS->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(OS->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(OS->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)); + + initialize(IntBytes, 0); + ASSERT_EQ(2, InputStreams.size()); + + for (auto IS : InputStreams) { + MutableArrayRef Buffer; + ASSERT_EQ(InputData.size(), IS->getLength()); + + FixedStreamArray Array(*IS); + 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()); + initialize(StringBytes, 0); + + 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 IS : InputStreams) { + VarStreamArray Array(*IS); + 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; + + initialize(Bytes, 0); + for (auto IS : InputStreams) { + StringRef S; + BinaryStreamReader Reader(*IS, little); + EXPECT_EQ(0, Reader.bytesRemaining()); + EXPECT_ERROR(Reader.readFixedString(S, 1)); + } + + Bytes.resize(5); + initialize(Bytes, 0); + for (auto IS : InputStreams) { + StringRef S; + BinaryStreamReader Reader(*IS, little); + 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); + std::vector Bytes(Size); + uint8_t *Ptr = &Bytes[0]; + memcpy(Ptr, &Little, sizeof(Little)); + Ptr += sizeof(Little); + memcpy(Ptr, &Big, sizeof(Big)); + Ptr += sizeof(Big); + memcpy(Ptr, &NS, sizeof(NS)); + Ptr += sizeof(NS); + memcpy(Ptr, &NI, sizeof(NI)); + Ptr += sizeof(NI); + memcpy(Ptr, &NUL, sizeof(NUL)); + Ptr += sizeof(NUL); + + initialize(Bytes, 0); + for (auto IS : InputStreams) { + const support::ulittle64_t *Little2; + const support::ubig32_t *Big2; + short NS2; + int NI2; + unsigned long NUL2; + + // 1. Reading fields individually. + BinaryStreamReader Reader(*IS, little); + 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(0, Reader.bytesRemaining()); + + EXPECT_EQ(Little, *Little2); + EXPECT_EQ(Big, *Big2); + EXPECT_EQ(NS, NS2); + EXPECT_EQ(NI, NI2); + EXPECT_EQ(NUL, NUL2); + + // 2. Reading with explicit endianness. + Reader.setOffset(0); + const ulittle64_t *Little3; + const ubig32_t *Big3; + ASSERT_NO_ERROR(Reader.readObject(Little3)); + ASSERT_NO_ERROR(Reader.readObject(Big3)); + EXPECT_EQ(Little, *Little3); + EXPECT_EQ(Big, *Big3); + } +} + +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)); + initialize(IntBytes, 0); + for (auto IS : InputStreams) { + BinaryStreamReader Reader(*IS, little); + ArrayRef IntsRef; + ASSERT_NO_ERROR(Reader.readArray(IntsRef, Ints.size())); + ASSERT_EQ(0, Reader.bytesRemaining()); + EXPECT_EQ(makeArrayRef(Ints), IntsRef); + + Reader.setOffset(0); + FixedStreamArray FixedIntsRef; + ASSERT_NO_ERROR(Reader.readArray(FixedIntsRef, Ints.size())); + ASSERT_EQ(0, 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}; + + ArrayRef Bytes(reinterpret_cast(&Enums[0]), + sizeof(MyEnum) * Enums.size()); + + initialize(Bytes, 0); + for (auto IS : InputStreams) { + BinaryStreamReader Reader(*IS, little); + + MyEnum V1; + MyEnum V2; + MyEnum V3; + ArrayRef Array; + FixedStreamArray FSA; + + ASSERT_NO_ERROR(Reader.readEnum(V1)); + ASSERT_NO_ERROR(Reader.readEnum(V2)); + ASSERT_NO_ERROR(Reader.readEnum(V3)); + ASSERT_EQ(0, Reader.bytesRemaining()); + + EXPECT_EQ(MyEnum::Bar, V1); + EXPECT_EQ(MyEnum::Baz, V2); + EXPECT_EQ(MyEnum::Foo, V3); + + Reader.setOffset(0); + ASSERT_NO_ERROR(Reader.readArray(Array, 3)); + EXPECT_EQ(makeArrayRef(Enums), Array); + + Reader.setOffset(0); + ASSERT_NO_ERROR(Reader.readArray(FSA, 3)); + EXPECT_EQ(Enums, std::vector(FSA.begin(), FSA.end())); + } +} + +TEST_F(BinaryStreamTest, StreamReaderObject) { + struct Foo { + int X; + double Y; + char Z; + }; + + std::vector Foos; + Foos.push_back({-42, 42.42, 42}); + Foos.push_back({100, 3.1415, -89}); + + std::vector Bytes; + Bytes.resize(2 * sizeof(Foo)); + Foo *FPtr = reinterpret_cast(&Bytes[0]); + Foo *GPtr = FPtr + 1; + + ::memcpy(FPtr, &Foos[0], sizeof(Foo)); + ::memcpy(GPtr + sizeof(Foo), &Foos[1], sizeof(Foo)); + + initialize(Bytes, 0); + + for (auto IS : InputStreams) { + // 1. Reading object pointers. + BinaryStreamReader Reader(*IS, little); + const Foo *FPtrOut = nullptr; + const Foo *GPtrOut = nullptr; + ASSERT_NO_ERROR(Reader.readObject(FPtrOut)); + ASSERT_NO_ERROR(Reader.readObject(GPtrOut)); + EXPECT_EQ(0, Reader.bytesRemaining()); + EXPECT_EQ(0, ::memcmp(FPtr, FPtrOut, sizeof(Foo))); + EXPECT_EQ(0, ::memcmp(GPtr, GPtrOut, sizeof(Foo))); + } +} + +TEST_F(BinaryStreamTest, StreamReaderStrings) { + StringLiteral Strings("One\0" + "Two\0" + "Three\0" + "Four\0"); + ArrayRef Bytes(Strings.bytes_begin(), Strings.bytes_end()); + initialize(Bytes, 0); + + for (auto IS : InputStreams) { + BinaryStreamReader Reader(*IS, little); + + StringRef S1; + StringRef S2; + StringRef S3; + StringRef S4; + ASSERT_NO_ERROR(Reader.readZeroString(S1)); + ASSERT_NO_ERROR(Reader.readZeroString(S2)); + ASSERT_NO_ERROR(Reader.readZeroString(S3)); + ASSERT_NO_ERROR(Reader.readZeroString(S4)); + ASSERT_EQ(0, 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(0, Reader.bytesRemaining()); + + EXPECT_EQ("One", S1); + EXPECT_EQ("Two", S2); + EXPECT_EQ("Three", S3); + EXPECT_EQ("Four", S4); + } +} + +TEST_F(BinaryStreamTest, StreamWriterBounds) { + initialize(5); + + for (auto OS : OutputStreams) { + BinaryStreamWriter Writer(*OS, little); + + // 1. Can write a string that exactly fills the buffer. + EXPECT_EQ(5, Writer.bytesRemaining()); + EXPECT_NO_ERROR(Writer.writeFixedString("abcde")); + EXPECT_EQ(0, 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, StreamWriterIntegers) { + 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); + + initialize(Size); + + for (auto OS : OutputStreams) { + BinaryStreamWriter Writer(*OS, little); + + // 1. Writing fields individually. + 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)); + ASSERT_EQ(0, Writer.bytesRemaining()); + + // Read them back in and confirm they're correct. + const ulittle64_t *Little2; + const ubig32_t *Big2; + short NS2; + int NI2; + unsigned long NUL2; + BinaryStreamReader Reader(*OS, little); + 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)); + EXPECT_EQ(Little, *Little2); + EXPECT_EQ(Big, *Big2); + EXPECT_EQ(NS, NS2); + EXPECT_EQ(NI, NI2); + EXPECT_EQ(NUL, NUL2); + } +} + +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)); + + initialize(SourceBytes, SourceBytes.size()); + + for (auto IS : InputStreams) { + for (auto OS : OutputStreams) { + BinaryStreamReader Reader(*IS, little); + BinaryStreamWriter Writer(*OS, little); + 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(*OS, little); + ASSERT_NO_ERROR(ReaderBacker.readArray(Ints2, SourceInts.size())); + + EXPECT_EQ(makeArrayRef(SourceInts), Ints2); + } + } +} + +TEST_F(BinaryStreamTest, StreamWriterEnum) { + enum class MyEnum : int64_t { Foo = -10, Bar = 0, Baz = 10 }; + + std::vector Expected = {MyEnum::Bar, MyEnum::Foo, MyEnum::Baz}; + + initialize(Expected.size() * sizeof(MyEnum)); + + for (auto OS : OutputStreams) { + BinaryStreamWriter Writer(*OS, little); + ArrayRef Enums; + ArrayRef Enums2; + + // First read them, then write them, then read them back. + for (auto ME : Expected) + ASSERT_NO_ERROR(Writer.writeEnum(ME)); + + ArrayRef Array; + BinaryStreamReader Reader(*OS, little); + ASSERT_NO_ERROR(Reader.readArray(Array, Expected.size())); + + EXPECT_EQ(makeArrayRef(Expected), Array); + } +} +} + +namespace { +struct BinaryItemStreamObject { + BinaryItemStreamObject(int X, StringRef Y, float Z) : X(X), Y(Y), Z(Z) {} + + // Note the use of std::string here, so this class cannot just be memcpy'ed. + int X; + std::string Y; + float Z; +}; +} + +namespace llvm { +template <> struct BinaryItemTraits> { + size_t length(const std::unique_ptr &Item) { + size_t S = sizeof(Item->X); // X + S += Item->Y.size() + 1; // Y + null terminator + S += sizeof(Item->Z); // Z + return S; + } + + ArrayRef bytes(const std::unique_ptr &Item) { + // In practice we probably would use a more cheaply serializable type, + // or at the very least not allocate every single time. This is just + // for illustration and testing though. + size_t Size = length(Item); + uint8_t *Buffer = Alloc.Allocate(Size); + MutableBinaryByteStream Stream(MutableArrayRef(Buffer, Size)); + BinaryStreamWriter Writer(Stream, llvm::support::little); + consumeError(Writer.writeInteger(Item->X)); + consumeError(Writer.writeZeroString(Item->Y)); + consumeError(Writer.writeObject(Item->Z)); + return makeArrayRef(Buffer, Size); + } + +private: + BumpPtrAllocator Alloc; +}; +} + +namespace { + +TEST_F(BinaryStreamTest, BinaryItemStream) { + // Note that this is a vector of pointers, so individual records do not live + // contiguously in memory. + std::vector> Objects; + Objects.push_back(llvm::make_unique(1, "First", 1.0)); + Objects.push_back( + llvm::make_unique(2, "Second", 2.0)); + Objects.push_back(llvm::make_unique(3, "Third", 3.0)); + + BinaryItemStream> ItemStream; + ItemStream.setItems(Objects); + BinaryStreamReader Reader(ItemStream, llvm::support::little); + + for (int I = 0; I < 3; ++I) { + int X; + StringRef Y; + const float *Z; + ASSERT_NO_ERROR(Reader.readInteger(X)); + ASSERT_NO_ERROR(Reader.readZeroString(Y)); + ASSERT_NO_ERROR(Reader.readObject(Z)); + + EXPECT_EQ(Objects[I]->X, X); + EXPECT_EQ(Objects[I]->Y, Y); + EXPECT_DOUBLE_EQ(Objects[I]->Z, *Z); + } +} + +} // end anonymous namespace Index: llvm/unittests/Support/CMakeLists.txt =================================================================== --- llvm/unittests/Support/CMakeLists.txt +++ llvm/unittests/Support/CMakeLists.txt @@ -7,6 +7,7 @@ AllocatorTest.cpp ARMAttributeParser.cpp ArrayRecyclerTest.cpp + BinaryStreamTest.cpp BlockFrequencyTest.cpp BranchProbabilityTest.cpp Casting.cpp