summaryrefslogtreecommitdiffstats
path: root/llvm/include/llvm/DebugInfo/MSF
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/include/llvm/DebugInfo/MSF')
-rw-r--r--llvm/include/llvm/DebugInfo/MSF/ByteStream.h160
-rw-r--r--llvm/include/llvm/DebugInfo/MSF/IMsfFile.h44
-rw-r--r--llvm/include/llvm/DebugInfo/MSF/MappedBlockStream.h139
-rw-r--r--llvm/include/llvm/DebugInfo/MSF/MsfBuilder.h140
-rw-r--r--llvm/include/llvm/DebugInfo/MSF/MsfCommon.h89
-rw-r--r--llvm/include/llvm/DebugInfo/MSF/MsfError.h47
-rw-r--r--llvm/include/llvm/DebugInfo/MSF/MsfStreamLayout.h35
-rw-r--r--llvm/include/llvm/DebugInfo/MSF/StreamArray.h277
-rw-r--r--llvm/include/llvm/DebugInfo/MSF/StreamInterface.h53
-rw-r--r--llvm/include/llvm/DebugInfo/MSF/StreamReader.h110
-rw-r--r--llvm/include/llvm/DebugInfo/MSF/StreamRef.h130
-rw-r--r--llvm/include/llvm/DebugInfo/MSF/StreamWriter.h85
12 files changed, 1309 insertions, 0 deletions
diff --git a/llvm/include/llvm/DebugInfo/MSF/ByteStream.h b/llvm/include/llvm/DebugInfo/MSF/ByteStream.h
new file mode 100644
index 00000000000..737693aa009
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/MSF/ByteStream.h
@@ -0,0 +1,160 @@
+//===- 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 <cstdint>
+#include <memory>
+#include <type_traits>
+
+namespace llvm {
+namespace msf {
+
+class ByteStream : public ReadableStream {
+public:
+ ByteStream() {}
+ explicit ByteStream(ArrayRef<uint8_t> Data) : Data(Data) {}
+
+ Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) const override {
+ if (Offset > Data.size())
+ return make_error<MSFError>(msf_error_code::insufficient_buffer);
+ if (Data.size() < Size + Offset)
+ return make_error<MSFError>(msf_error_code::insufficient_buffer);
+ Buffer = Data.slice(Offset, Size);
+ return Error::success();
+ }
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) const override {
+ if (Offset >= Data.size())
+ return make_error<MSFError>(msf_error_code::insufficient_buffer);
+ Buffer = Data.slice(Offset);
+ return Error::success();
+ }
+
+ uint32_t getLength() const override { return Data.size(); }
+
+ ArrayRef<uint8_t> data() const { return Data; }
+
+ StringRef str() const {
+ const char *CharData = reinterpret_cast<const char *>(Data.data());
+ return StringRef(CharData, Data.size());
+ }
+
+protected:
+ ArrayRef<uint8_t> 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<MemoryBuffer> Buffer)
+ : ByteStream(ArrayRef<uint8_t>(Buffer->getBuffer().bytes_begin(),
+ Buffer->getBuffer().bytes_end())),
+ MemBuffer(std::move(Buffer)) {}
+
+ std::unique_ptr<MemoryBuffer> MemBuffer;
+};
+
+class MutableByteStream : public WritableStream {
+public:
+ MutableByteStream() {}
+ explicit MutableByteStream(MutableArrayRef<uint8_t> Data)
+ : Data(Data), ImmutableStream(Data) {}
+
+ Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) const override {
+ return ImmutableStream.readBytes(Offset, Size, Buffer);
+ }
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) const override {
+ return ImmutableStream.readLongestContiguousChunk(Offset, Buffer);
+ }
+
+ uint32_t getLength() const override { return ImmutableStream.getLength(); }
+
+ Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) const override {
+ if (Data.size() < Buffer.size())
+ return make_error<MSFError>(msf_error_code::insufficient_buffer);
+ if (Offset > Buffer.size() - Data.size())
+ return make_error<MSFError>(msf_error_code::insufficient_buffer);
+
+ uint8_t *DataPtr = const_cast<uint8_t *>(Data.data());
+ ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size());
+ return Error::success();
+ }
+
+ Error commit() const override { return Error::success(); }
+
+ MutableArrayRef<uint8_t> data() const { return Data; }
+
+private:
+ MutableArrayRef<uint8_t> 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<FileOutputBuffer> Buffer)
+ : MutableByteStream(MutableArrayRef<uint8_t>(Buffer->getBufferStart(),
+ Buffer->getBufferEnd())),
+ FileBuffer(std::move(Buffer)) {}
+
+ Error commit() const override {
+ if (FileBuffer->commit())
+ return llvm::make_error<MSFError>(msf_error_code::not_writable);
+ return Error::success();
+ }
+
+ private:
+ std::unique_ptr<FileOutputBuffer> FileBuffer;
+ };
+
+public:
+ explicit FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer)
+ : Impl(std::move(Buffer)) {}
+
+ Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) const override {
+ return Impl.readBytes(Offset, Size, Buffer);
+ }
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) const override {
+ return Impl.readLongestContiguousChunk(Offset, Buffer);
+ }
+
+ uint32_t getLength() const override { return Impl.getLength(); }
+
+ Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> 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
diff --git a/llvm/include/llvm/DebugInfo/MSF/IMsfFile.h b/llvm/include/llvm/DebugInfo/MSF/IMsfFile.h
new file mode 100644
index 00000000000..6c5754f11b9
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/MSF/IMsfFile.h
@@ -0,0 +1,44 @@
+//===- IMSFFile.h - Abstract base class for an MSF file ---------*- 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_IMSFFILE_H
+#define LLVM_DEBUGINFO_MSF_IMSFFILE_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/MSF/StreamArray.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+
+#include <stdint.h>
+
+namespace llvm {
+namespace msf {
+
+class IMSFFile {
+public:
+ virtual ~IMSFFile() {}
+
+ virtual uint32_t getBlockSize() const = 0;
+ virtual uint32_t getBlockCount() const = 0;
+
+ virtual uint32_t getNumStreams() const = 0;
+ virtual uint32_t getStreamByteSize(uint32_t StreamIndex) const = 0;
+ virtual ArrayRef<support::ulittle32_t>
+ getStreamBlockList(uint32_t StreamIndex) const = 0;
+
+ virtual Expected<ArrayRef<uint8_t>> getBlockData(uint32_t BlockIndex,
+ uint32_t NumBytes) const = 0;
+ virtual Error setBlockData(uint32_t BlockIndex, uint32_t Offset,
+ ArrayRef<uint8_t> Data) const = 0;
+};
+}
+}
+
+#endif // LLVM_DEBUGINFO_MSF_IMSFFILE_H
diff --git a/llvm/include/llvm/DebugInfo/MSF/MappedBlockStream.h b/llvm/include/llvm/DebugInfo/MSF/MappedBlockStream.h
new file mode 100644
index 00000000000..aef6b011153
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/MSF/MappedBlockStream.h
@@ -0,0 +1,139 @@
+//===- MappedBlockStream.h - Discontiguous stream data in an MSF -*- 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_MAPPEDBLOCKSTREAM_H
+#define LLVM_DEBUGINFO_MSF_MAPPEDBLOCKSTREAM_H
+
+#include "llvm/ADT/ArrayRef.h"
+#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/Endian.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+#include <vector>
+
+namespace llvm {
+namespace msf {
+
+struct MSFLayout;
+
+/// MappedBlockStream represents data stored in an MSF file into chunks of a
+/// particular size (called the Block Size), and whose chunks may not be
+/// necessarily contiguous. The arrangement of these chunks MSF the file
+/// is described by some other metadata contained within the MSF file. In
+/// the case of a standard MSF Stream, the layout of the stream's blocks
+/// is described by the MSF "directory", but in the case of the directory
+/// itself, the layout is described by an array at a fixed location within
+/// 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 {
+ friend class WritableMappedBlockStream;
+
+public:
+ static std::unique_ptr<MappedBlockStream>
+ createStream(uint32_t BlockSize, uint32_t NumBlocks,
+ const MSFStreamLayout &Layout, const ReadableStream &MsfData);
+
+ static std::unique_ptr<MappedBlockStream>
+ createIndexedStream(const MSFLayout &Layout, const ReadableStream &MsfData,
+ uint32_t StreamIndex);
+
+ static std::unique_ptr<MappedBlockStream>
+ createDirectoryStream(const MSFLayout &Layout, const ReadableStream &MsfData);
+
+ Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) const override;
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) const override;
+
+ uint32_t getLength() const override;
+
+ uint32_t getNumBytesCopied() const;
+
+ llvm::BumpPtrAllocator &getAllocator() { return Pool; }
+
+ void invalidateCache();
+
+ uint32_t getBlockSize() const { return BlockSize; }
+ uint32_t getNumBlocks() const { return NumBlocks; }
+ uint32_t getStreamLength() const { return StreamLayout.Length; }
+
+protected:
+ MappedBlockStream(uint32_t BlockSize, uint32_t NumBlocks,
+ const MSFStreamLayout &StreamLayout,
+ const ReadableStream &MsfData);
+
+private:
+ const MSFStreamLayout &getStreamLayout() const { return StreamLayout; }
+ void fixCacheAfterWrite(uint32_t Offset, ArrayRef<uint8_t> Data) const;
+
+ Error readBytes(uint32_t Offset, MutableArrayRef<uint8_t> Buffer) const;
+ bool tryReadContiguously(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) const;
+
+ const uint32_t BlockSize;
+ const uint32_t NumBlocks;
+ const MSFStreamLayout StreamLayout;
+ const ReadableStream &MsfData;
+
+ typedef MutableArrayRef<uint8_t> CacheEntry;
+ mutable llvm::BumpPtrAllocator Pool;
+ mutable DenseMap<uint32_t, std::vector<CacheEntry>> CacheMap;
+};
+
+class WritableMappedBlockStream : public WritableStream {
+public:
+ static std::unique_ptr<WritableMappedBlockStream>
+ createStream(uint32_t BlockSize, uint32_t NumBlocks,
+ const MSFStreamLayout &Layout, const WritableStream &MsfData);
+
+ static std::unique_ptr<WritableMappedBlockStream>
+ createIndexedStream(const MSFLayout &Layout, const WritableStream &MsfData,
+ uint32_t StreamIndex);
+
+ static std::unique_ptr<WritableMappedBlockStream>
+ createDirectoryStream(const MSFLayout &Layout, const WritableStream &MsfData);
+
+ Error readBytes(uint32_t Offset, uint32_t Size,
+ ArrayRef<uint8_t> &Buffer) const override;
+ Error readLongestContiguousChunk(uint32_t Offset,
+ ArrayRef<uint8_t> &Buffer) const override;
+ uint32_t getLength() const override;
+
+ Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) const override;
+
+ Error commit() const override;
+
+ const MSFStreamLayout &getStreamLayout() const {
+ return ReadInterface.getStreamLayout();
+ }
+ uint32_t getBlockSize() const { return ReadInterface.getBlockSize(); }
+ uint32_t getNumBlocks() const { return ReadInterface.getNumBlocks(); }
+ uint32_t getStreamLength() const { return ReadInterface.getStreamLength(); }
+
+protected:
+ WritableMappedBlockStream(uint32_t BlockSize, uint32_t NumBlocks,
+ const MSFStreamLayout &StreamLayout,
+ const WritableStream &MsfData);
+
+private:
+ MappedBlockStream ReadInterface;
+
+ const WritableStream &WriteInterface;
+};
+
+} // end namespace pdb
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_MSF_MAPPEDBLOCKSTREAM_H
diff --git a/llvm/include/llvm/DebugInfo/MSF/MsfBuilder.h b/llvm/include/llvm/DebugInfo/MSF/MsfBuilder.h
new file mode 100644
index 00000000000..bf29e626339
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/MSF/MsfBuilder.h
@@ -0,0 +1,140 @@
+//===- MSFBuilder.h - MSF Directory & Metadata Builder ----------*- 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_MSFBUILDER_H
+#define LLVM_DEBUGINFO_MSF_MSFBUILDER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitVector.h"
+
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
+
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+
+#include <utility>
+#include <vector>
+
+namespace llvm {
+namespace msf {
+class MSFBuilder {
+public:
+ /// \brief Create a new `MSFBuilder`.
+ ///
+ /// \param BlockSize The internal block size used by the PDB file. See
+ /// isValidBlockSize() for a list of valid block sizes.
+ ///
+ /// \param MinBlockCount Causes the builder to reserve up front space for
+ /// at least `MinBlockCount` blocks. This is useful when using `MSFBuilder`
+ /// to read an existing MSF that you want to write back out later. The
+ /// original MSF file's SuperBlock contains the exact number of blocks used
+ /// by the file, so is a good hint as to how many blocks the new MSF file
+ /// will contain. Furthermore, it is actually necessary in this case. To
+ /// preserve stability of the file's layout, it is helpful to try to keep
+ /// all streams mapped to their original block numbers. To ensure that this
+ /// is possible, space for all blocks must be allocated beforehand so that
+ /// streams can be assigned to them.
+ ///
+ /// \param CanGrow If true, any operation which results in an attempt to
+ /// locate a free block when all available blocks have been exhausted will
+ /// allocate a new block, thereby growing the size of the final MSF file.
+ /// When false, any such attempt will result in an error. This is especially
+ /// useful in testing scenarios when you know your test isn't going to do
+ /// anything to increase the size of the file, so having an Error returned if
+ /// it were to happen would catch a programming error
+ ///
+ /// \returns an llvm::Error representing whether the operation succeeded or
+ /// failed. Currently the only way this can fail is if an invalid block size
+ /// is specified, or `MinBlockCount` does not leave enough room for the
+ /// mandatory reserved blocks required by an MSF file.
+ static Expected<MSFBuilder> create(BumpPtrAllocator &Allocator,
+ uint32_t BlockSize,
+ uint32_t MinBlockCount = 0,
+ bool CanGrow = true);
+
+ /// Request the block map to be at a specific block address. This is useful
+ /// when editing a MSF and you want the layout to be as stable as possible.
+ Error setBlockMapAddr(uint32_t Addr);
+ Error setDirectoryBlocksHint(ArrayRef<uint32_t> DirBlocks);
+ void setFreePageMap(uint32_t Fpm);
+ void setUnknown1(uint32_t Unk1);
+
+ /// Add a stream to the MSF file with the given size, occupying the given
+ /// list of blocks. This is useful when reading a MSF file and you want a
+ /// particular stream to occupy the original set of blocks. If the given
+ /// blocks are already allocated, or if the number of blocks specified is
+ /// incorrect for the given stream size, this function will return an Error.
+ Error addStream(uint32_t Size, ArrayRef<uint32_t> Blocks);
+
+ /// Add a stream to the MSF file with the given size, occupying any available
+ /// blocks that the builder decides to use. This is useful when building a
+ /// new PDB file from scratch and you don't care what blocks a stream occupies
+ /// but you just want it to work.
+ Error addStream(uint32_t Size);
+
+ /// Update the size of an existing stream. This will allocate or deallocate
+ /// blocks as needed to match the requested size. This can fail if `CanGrow`
+ /// was set to false when initializing the `MSFBuilder`.
+ Error setStreamSize(uint32_t Idx, uint32_t Size);
+
+ /// Get the total number of streams in the MSF layout. This should return 1
+ /// for every call to `addStream`.
+ uint32_t getNumStreams() const;
+
+ /// Get the size of a stream by index.
+ uint32_t getStreamSize(uint32_t StreamIdx) const;
+
+ /// Get the list of blocks allocated to a particular stream.
+ ArrayRef<uint32_t> getStreamBlocks(uint32_t StreamIdx) const;
+
+ /// Get the total number of blocks that will be allocated to actual data in
+ /// this MSF file.
+ uint32_t getNumUsedBlocks() const;
+
+ /// Get the total number of blocks that exist in the MSF file but are not
+ /// allocated to any valid data.
+ uint32_t getNumFreeBlocks() const;
+
+ /// Get the total number of blocks in the MSF file. In practice this is equal
+ /// to `getNumUsedBlocks() + getNumFreeBlocks()`.
+ uint32_t getTotalBlockCount() const;
+
+ /// Check whether a particular block is allocated or free.
+ bool isBlockFree(uint32_t Idx) const;
+
+ /// Finalize the layout and build the headers and structures that describe the
+ /// MSF layout and can be written directly to the MSF file.
+ Expected<MSFLayout> build();
+
+private:
+ MSFBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow,
+ BumpPtrAllocator &Allocator);
+
+ Error allocateBlocks(uint32_t NumBlocks, MutableArrayRef<uint32_t> Blocks);
+ uint32_t computeDirectoryByteSize() const;
+
+ typedef std::vector<uint32_t> BlockList;
+
+ BumpPtrAllocator &Allocator;
+
+ bool IsGrowable;
+ uint32_t FreePageMap;
+ uint32_t Unknown1;
+ uint32_t BlockSize;
+ uint32_t MininumBlocks;
+ uint32_t BlockMapAddr;
+ BitVector FreeBlocks;
+ std::vector<uint32_t> DirectoryBlocks;
+ std::vector<std::pair<uint32_t, BlockList>> StreamData;
+};
+} // namespace msf
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_MSF_MSFBUILDER_H
diff --git a/llvm/include/llvm/DebugInfo/MSF/MsfCommon.h b/llvm/include/llvm/DebugInfo/MSF/MsfCommon.h
new file mode 100644
index 00000000000..58e6a1af426
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/MSF/MsfCommon.h
@@ -0,0 +1,89 @@
+//===- MSFCommon.h - Common types and functions for MSF files ---*- 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_MSFCOMMON_H
+#define LLVM_DEBUGINFO_MSF_MSFCOMMON_H
+
+#include "llvm/ADT/ArrayRef.h"
+
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MathExtras.h"
+
+#include <vector>
+
+namespace llvm {
+namespace msf {
+static const char Magic[] = {'M', 'i', 'c', 'r', 'o', 's', 'o', 'f',
+ 't', ' ', 'C', '/', 'C', '+', '+', ' ',
+ 'M', 'S', 'F', ' ', '7', '.', '0', '0',
+ '\r', '\n', '\x1a', 'D', 'S', '\0', '\0', '\0'};
+
+// The superblock is overlaid at the beginning of the file (offset 0).
+// It starts with a magic header and is followed by information which
+// describes the layout of the file system.
+struct SuperBlock {
+ char MagicBytes[sizeof(Magic)];
+ // The file system is split into a variable number of fixed size elements.
+ // These elements are referred to as blocks. The size of a block may vary
+ // from system to system.
+ support::ulittle32_t BlockSize;
+ // The index of the free block map.
+ support::ulittle32_t FreeBlockMapBlock;
+ // This contains the number of blocks resident in the file system. In
+ // practice, NumBlocks * BlockSize is equivalent to the size of the MSF
+ // file.
+ support::ulittle32_t NumBlocks;
+ // This contains the number of bytes which make up the directory.
+ support::ulittle32_t NumDirectoryBytes;
+ // This field's purpose is not yet known.
+ support::ulittle32_t Unknown1;
+ // This contains the block # of the block map.
+ support::ulittle32_t BlockMapAddr;
+};
+
+struct MSFLayout {
+ MSFLayout() : SB(nullptr) {}
+ const SuperBlock *SB;
+ ArrayRef<support::ulittle32_t> DirectoryBlocks;
+ ArrayRef<support::ulittle32_t> StreamSizes;
+ std::vector<ArrayRef<support::ulittle32_t>> StreamMap;
+};
+
+inline bool isValidBlockSize(uint32_t Size) {
+ switch (Size) {
+ case 512:
+ case 1024:
+ case 2048:
+ case 4096:
+ return true;
+ }
+ return false;
+}
+
+// Super Block, Fpm0, Fpm1, and Block Map
+inline uint32_t getMinimumBlockCount() { return 4; }
+
+// Super Block, Fpm0, and Fpm1 are reserved. The Block Map, although required
+// need not be at block 3.
+inline uint32_t getFirstUnreservedBlock() { return 3; }
+
+inline uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) {
+ return alignTo(NumBytes, BlockSize) / BlockSize;
+}
+
+inline uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize) {
+ return BlockNumber * BlockSize;
+}
+
+Error validateSuperBlock(const SuperBlock &SB);
+} // namespace msf
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_MSF_MSFCOMMON_H
diff --git a/llvm/include/llvm/DebugInfo/MSF/MsfError.h b/llvm/include/llvm/DebugInfo/MSF/MsfError.h
new file mode 100644
index 00000000000..e66aeca3cd4
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/MSF/MsfError.h
@@ -0,0 +1,47 @@
+//===- MSFError.h - Error extensions for MSF Files --------------*- 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_MSFERROR_H
+#define LLVM_DEBUGINFO_MSF_MSFERROR_H
+
+#include "llvm/Support/Error.h"
+
+#include <string>
+
+namespace llvm {
+namespace msf {
+enum class msf_error_code {
+ unspecified = 1,
+ insufficient_buffer,
+ not_writable,
+ no_stream,
+ invalid_format,
+ block_in_use
+};
+
+/// Base class for errors originating when parsing raw PDB files
+class MSFError : public ErrorInfo<MSFError> {
+public:
+ static char ID;
+ MSFError(msf_error_code C);
+ MSFError(const std::string &Context);
+ MSFError(msf_error_code C, const std::string &Context);
+
+ void log(raw_ostream &OS) const override;
+ const std::string &getErrorMessage() const;
+ std::error_code convertToErrorCode() const override;
+
+private:
+ std::string ErrMsg;
+ msf_error_code Code;
+};
+} // namespace msf
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_MSF_MSFERROR_H
diff --git a/llvm/include/llvm/DebugInfo/MSF/MsfStreamLayout.h b/llvm/include/llvm/DebugInfo/MSF/MsfStreamLayout.h
new file mode 100644
index 00000000000..1b987aa04cf
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/MSF/MsfStreamLayout.h
@@ -0,0 +1,35 @@
+//===- MSFStreamLayout.h - Describes the layout of 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_MSFSTREAMLAYOUT_H
+#define LLVM_DEBUGINFO_MSF_MSFSTREAMLAYOUT_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Endian.h"
+
+#include <cstdint>
+
+namespace llvm {
+namespace msf {
+
+/// \brief Describes the layout of a stream in an MSF layout. A "stream" here
+/// is defined as any logical unit of data which may be arranged inside the MSF
+/// file as a sequence of (possibly discontiguous) blocks. When we want to read
+/// from a particular MSF Stream, we fill out a stream layout structure and the
+/// reader uses it to determine which blocks in the underlying MSF file contain
+/// the data, so that it can be pieced together in the right order.
+class MSFStreamLayout {
+public:
+ uint32_t Length;
+ ArrayRef<support::ulittle32_t> Blocks;
+};
+} // namespace msf
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_MSF_MSFSTREAMLAYOUT_H
diff --git a/llvm/include/llvm/DebugInfo/MSF/StreamArray.h b/llvm/include/llvm/DebugInfo/MSF/StreamArray.h
new file mode 100644
index 00000000000..88f41ddfb52
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/MSF/StreamArray.h
@@ -0,0 +1,277 @@
+//===- StreamArray.h - Array backed by an arbitrary stream ----------------===//
+//
+// 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/DebugInfo/MSF/StreamRef.h"
+#include "llvm/Support/Error.h"
+
+#include <functional>
+#include <type_traits>
+
+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 <typename T> 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<T> 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<MyType> as the extractor.
+/// VarStreamArray<MyType> MyTypeArray;
+///
+/// // Will use a default-constructed MyExtractor as the extractor.
+/// VarStreamArray<MyType, MyExtractor> MyTypeArray2;
+///
+/// // Will use the specific instance of MyExtractor provided.
+/// // MyExtractor need not be default-constructible in this case.
+/// MyExtractor E(SomeContext);
+/// VarStreamArray<MyType, MyExtractor> MyTypeArray3(E);
+///
+template <typename ValueType, typename Extractor> class VarStreamArrayIterator;
+
+template <typename ValueType,
+ typename Extractor = VarStreamArrayExtractor<ValueType>>
+class VarStreamArray {
+ friend class VarStreamArrayIterator<ValueType, Extractor>;
+
+public:
+ typedef VarStreamArrayIterator<ValueType, Extractor> Iterator;
+
+ VarStreamArray() {}
+ 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<ValueType, Extractor> &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 <typename ValueType, typename Extractor> class VarStreamArrayIterator {
+ typedef VarStreamArrayIterator<ValueType, Extractor> IterType;
+ typedef VarStreamArray<ValueType, Extractor> 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() {}
+ explicit VarStreamArrayIterator(const Extractor &E) : Extract(E) {}
+ ~VarStreamArrayIterator() {}
+
+ 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;
+ }
+
+ bool operator!=(const IterType &R) { return !(*this == R); }
+
+ 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;
+ }
+
+ IterType operator++(int) {
+ IterType Original = *this;
+ ++*this;
+ return Original;
+ }
+
+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 <typename T> class FixedStreamArrayIterator;
+
+template <typename T> class FixedStreamArray {
+ friend class FixedStreamArrayIterator<T>;
+
+public:
+ FixedStreamArray() : Stream() {}
+ FixedStreamArray(ReadableStreamRef Stream) : Stream(Stream) {
+ assert(Stream.getLength() % sizeof(T) == 0);
+ }
+
+ const T &operator[](uint32_t Index) const {
+ assert(Index < size());
+ uint32_t Off = Index * sizeof(T);
+ ArrayRef<uint8_t> 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<const T *>(Data.data());
+ }
+
+ uint32_t size() const { return Stream.getLength() / sizeof(T); }
+
+ FixedStreamArrayIterator<T> begin() const {
+ return FixedStreamArrayIterator<T>(*this, 0);
+ }
+ FixedStreamArrayIterator<T> end() const {
+ return FixedStreamArrayIterator<T>(*this, size());
+ }
+
+ ReadableStreamRef getUnderlyingStream() const { return Stream; }
+
+private:
+ ReadableStreamRef Stream;
+};
+
+template <typename T> class FixedStreamArrayIterator {
+public:
+ FixedStreamArrayIterator(const FixedStreamArray<T> &Array, uint32_t Index)
+ : Array(Array), Index(Index) {}
+
+ bool operator==(const FixedStreamArrayIterator<T> &R) {
+ assert(&Array == &R.Array);
+ return Index == R.Index;
+ }
+
+ bool operator!=(const FixedStreamArrayIterator<T> &R) {
+ return !(*this == R);
+ }
+
+ const T &operator*() const { return Array[Index]; }
+
+ FixedStreamArrayIterator<T> &operator++() {
+ assert(Index < Array.size());
+ ++Index;
+ return *this;
+ }
+
+ FixedStreamArrayIterator<T> operator++(int) {
+ FixedStreamArrayIterator<T> Original = *this;
+ ++*this;
+ return Original;
+ }
+
+private:
+ const FixedStreamArray<T> &Array;
+ uint32_t Index;
+};
+
+} // namespace msf
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_MSF_STREAMARRAY_H
diff --git a/llvm/include/llvm/DebugInfo/MSF/StreamInterface.h b/llvm/include/llvm/DebugInfo/MSF/StreamInterface.h
new file mode 100644
index 00000000000..78347e46c22
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/MSF/StreamInterface.h
@@ -0,0 +1,53 @@
+//===- 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 <cstdint>
+
+namespace llvm {
+namespace msf {
+
+class ReadableStream {
+public:
+ virtual ~ReadableStream() {}
+
+ // 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<uint8_t> &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<uint8_t> &Buffer) const = 0;
+
+ virtual uint32_t getLength() const = 0;
+};
+
+class WritableStream : public ReadableStream {
+public:
+ virtual ~WritableStream() {}
+
+ // 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<uint8_t> Data) const = 0;
+
+ virtual Error commit() const = 0;
+};
+
+} // end namespace msf
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_MSF_STREAMINTERFACE_H
diff --git a/llvm/include/llvm/DebugInfo/MSF/StreamReader.h b/llvm/include/llvm/DebugInfo/MSF/StreamReader.h
new file mode 100644
index 00000000000..ac43aaa8447
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/MSF/StreamReader.h
@@ -0,0 +1,110 @@
+//===- 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 <string>
+
+namespace llvm {
+namespace msf {
+
+class StreamReader {
+public:
+ StreamReader(ReadableStreamRef Stream);
+
+ Error readLongestContiguousChunk(ArrayRef<uint8_t> &Buffer);
+ Error readBytes(ArrayRef<uint8_t> &Buffer, uint32_t Size);
+ Error readInteger(uint16_t &Dest);
+ Error readInteger(uint32_t &Dest);
+ Error readZeroString(StringRef &Dest);
+ Error readFixedString(StringRef &Dest, uint32_t Length);
+ Error readStreamRef(ReadableStreamRef &Ref);
+ Error readStreamRef(ReadableStreamRef &Ref, uint32_t Length);
+
+ template <typename T> Error readEnum(T &Dest) {
+ typename std::underlying_type<T>::type N;
+ if (auto EC = readInteger(N))
+ return EC;
+ Dest = static_cast<T>(N);
+ return Error::success();
+ }
+
+ template <typename T> Error readObject(const T *&Dest) {
+ ArrayRef<uint8_t> Buffer;
+ if (auto EC = readBytes(Buffer, sizeof(T)))
+ return EC;
+ Dest = reinterpret_cast<const T *>(Buffer.data());
+ return Error::success();
+ }
+
+ template <typename T>
+ Error readArray(ArrayRef<T> &Array, uint32_t NumElements) {
+ ArrayRef<uint8_t> Bytes;
+ if (NumElements == 0) {
+ Array = ArrayRef<T>();
+ return Error::success();
+ }
+
+ if (NumElements > UINT32_MAX / sizeof(T))
+ return make_error<MSFError>(msf_error_code::insufficient_buffer);
+
+ if (auto EC = readBytes(Bytes, NumElements * sizeof(T)))
+ return EC;
+ Array = ArrayRef<T>(reinterpret_cast<const T *>(Bytes.data()), NumElements);
+ return Error::success();
+ }
+
+ template <typename T, typename U>
+ Error readArray(VarStreamArray<T, U> &Array, uint32_t Size) {
+ ReadableStreamRef S;
+ if (auto EC = readStreamRef(S, Size))
+ return EC;
+ Array = VarStreamArray<T, U>(S, Array.getExtractor());
+ return Error::success();
+ }
+
+ template <typename T>
+ Error readArray(FixedStreamArray<T> &Array, uint32_t NumItems) {
+ if (NumItems == 0) {
+ Array = FixedStreamArray<T>();
+ return Error::success();
+ }
+ uint32_t Length = NumItems * sizeof(T);
+ if (Length / sizeof(T) != NumItems)
+ return make_error<MSFError>(msf_error_code::invalid_format);
+ if (Offset + Length > Stream.getLength())
+ return make_error<MSFError>(msf_error_code::insufficient_buffer);
+ ReadableStreamRef View = Stream.slice(Offset, Length);
+ Array = FixedStreamArray<T>(View);
+ Offset += Length;
+ return Error::success();
+ }
+
+ 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:
+ ReadableStreamRef Stream;
+ uint32_t Offset;
+};
+} // namespace msf
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_MSF_STREAMREADER_H
diff --git a/llvm/include/llvm/DebugInfo/MSF/StreamRef.h b/llvm/include/llvm/DebugInfo/MSF/StreamRef.h
new file mode 100644
index 00000000000..c25fd381ef2
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/MSF/StreamRef.h
@@ -0,0 +1,130 @@
+//===- 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/DebugInfo/MSF/MSFError.h"
+#include "llvm/DebugInfo/MSF/StreamInterface.h"
+
+namespace llvm {
+namespace msf {
+template <class StreamType, class RefType> 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<ReadableStream, ReadableStreamRef> {
+public:
+ ReadableStreamRef() : StreamRefBase() {}
+ 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<uint8_t> &Buffer) const {
+ if (ViewOffset + Offset < Offset)
+ return make_error<MSFError>(msf_error_code::insufficient_buffer);
+ if (Size + Offset > Length)
+ return make_error<MSFError>(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<uint8_t> &Buffer) const {
+ if (Offset >= Length)
+ return make_error<MSFError>(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<WritableStream, WritableStreamRef> {
+public:
+ WritableStreamRef() : StreamRefBase() {}
+ 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<uint8_t> Data) const {
+ if (Data.size() + Offset > Length)
+ return make_error<MSFError>(msf_error_code::insufficient_buffer);
+ return Stream->writeBytes(ViewOffset + Offset, Data);
+ }
+
+ Error commit() const { return Stream->commit(); }
+};
+
+} // namespace msf
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_MSF_STREAMREF_H
diff --git a/llvm/include/llvm/DebugInfo/MSF/StreamWriter.h b/llvm/include/llvm/DebugInfo/MSF/StreamWriter.h
new file mode 100644
index 00000000000..88043c737bd
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/MSF/StreamWriter.h
@@ -0,0 +1,85 @@
+//===- 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/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 <string>
+
+namespace llvm {
+namespace msf {
+
+class StreamWriter {
+public:
+ StreamWriter(WritableStreamRef Stream);
+
+ Error writeBytes(ArrayRef<uint8_t> Buffer);
+ Error writeInteger(uint16_t Dest);
+ Error writeInteger(uint32_t Dest);
+ Error writeZeroString(StringRef Str);
+ Error writeFixedString(StringRef Str);
+ Error writeStreamRef(ReadableStreamRef Ref);
+ Error writeStreamRef(ReadableStreamRef Ref, uint32_t Size);
+
+ template <typename T> Error writeEnum(T Num) {
+ return writeInteger(
+ static_cast<typename std::underlying_type<T>::type>(Num));
+ }
+
+ template <typename T> Error writeObject(const T &Obj) {
+ static_assert(!std::is_pointer<T>::value,
+ "writeObject should not be used with pointers, to write "
+ "the pointed-to value dereference the pointer before calling "
+ "writeObject");
+ return writeBytes(
+ ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&Obj), sizeof(T)));
+ }
+
+ template <typename T> Error writeArray(ArrayRef<T> Array) {
+ if (Array.size() == 0)
+ return Error::success();
+
+ if (Array.size() > UINT32_MAX / sizeof(T))
+ return make_error<MSFError>(msf_error_code::insufficient_buffer);
+
+ return writeBytes(
+ ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Array.data()),
+ Array.size() * sizeof(T)));
+ }
+
+ template <typename T, typename U>
+ Error writeArray(VarStreamArray<T, U> Array) {
+ return writeStreamRef(Array.getUnderlyingStream());
+ }
+
+ template <typename T> Error writeArray(FixedStreamArray<T> 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;
+};
+} // namespace msf
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_MSF_STREAMWRITER_H
OpenPOWER on IntegriCloud