diff options
Diffstat (limited to 'clang-r353983/include/llvm/DebugInfo/MSF')
| -rw-r--r-- | clang-r353983/include/llvm/DebugInfo/MSF/IMSFFile.h | 41 | ||||
| -rw-r--r-- | clang-r353983/include/llvm/DebugInfo/MSF/MSFBuilder.h | 144 | ||||
| -rw-r--r-- | clang-r353983/include/llvm/DebugInfo/MSF/MSFCommon.h | 161 | ||||
| -rw-r--r-- | clang-r353983/include/llvm/DebugInfo/MSF/MSFError.h | 52 | ||||
| -rw-r--r-- | clang-r353983/include/llvm/DebugInfo/MSF/MappedBlockStream.h | 162 |
5 files changed, 560 insertions, 0 deletions
diff --git a/clang-r353983/include/llvm/DebugInfo/MSF/IMSFFile.h b/clang-r353983/include/llvm/DebugInfo/MSF/IMSFFile.h new file mode 100644 index 00000000..7e80f96b --- /dev/null +++ b/clang-r353983/include/llvm/DebugInfo/MSF/IMSFFile.h @@ -0,0 +1,41 @@ +//===- IMSFFile.h - Abstract base class for an MSF file ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_MSF_IMSFFILE_H +#define LLVM_DEBUGINFO_MSF_IMSFFILE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <cstdint> + +namespace llvm { +namespace msf { + +class IMSFFile { +public: + virtual ~IMSFFile() = default; + + 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; +}; + +} // end namespace msf +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_MSF_IMSFFILE_H diff --git a/clang-r353983/include/llvm/DebugInfo/MSF/MSFBuilder.h b/clang-r353983/include/llvm/DebugInfo/MSF/MSFBuilder.h new file mode 100644 index 00000000..282870f5 --- /dev/null +++ b/clang-r353983/include/llvm/DebugInfo/MSF/MSFBuilder.h @@ -0,0 +1,144 @@ +//===- MSFBuilder.h - MSF Directory & Metadata Builder ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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/Error.h" +#include <cstdint> +#include <utility> +#include <vector> + +namespace llvm { +class FileBufferByteStream; +class WritableBinaryStream; +namespace msf { + +class MSFBuilder { +public: + /// 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. + Expected<uint32_t> 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. + Expected<uint32_t> 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> generateLayout(); + + /// Write the MSF layout to the underlying file. + Expected<FileBufferByteStream> commit(StringRef Path, MSFLayout &Layout); + + BumpPtrAllocator &getAllocator() { return Allocator; } + +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; + + using BlockList = std::vector<uint32_t>; + + BumpPtrAllocator &Allocator; + + bool IsGrowable; + uint32_t FreePageMap; + uint32_t Unknown1 = 0; + uint32_t BlockSize; + uint32_t BlockMapAddr; + BitVector FreeBlocks; + std::vector<uint32_t> DirectoryBlocks; + std::vector<std::pair<uint32_t, BlockList>> StreamData; +}; + +} // end namespace msf +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_MSF_MSFBUILDER_H diff --git a/clang-r353983/include/llvm/DebugInfo/MSF/MSFCommon.h b/clang-r353983/include/llvm/DebugInfo/MSF/MSFCommon.h new file mode 100644 index 00000000..83331b14 --- /dev/null +++ b/clang-r353983/include/llvm/DebugInfo/MSF/MSFCommon.h @@ -0,0 +1,161 @@ +//===- MSFCommon.h - Common types and functions for MSF files ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_MSF_MSFCOMMON_H +#define LLVM_DEBUGINFO_MSF_MSFCOMMON_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" +#include <cstdint> +#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() = default; + + uint32_t mainFpmBlock() const { + assert(SB->FreeBlockMapBlock == 1 || SB->FreeBlockMapBlock == 2); + return SB->FreeBlockMapBlock; + } + + uint32_t alternateFpmBlock() const { + // If mainFpmBlock is 1, this is 2. If mainFpmBlock is 2, this is 1. + return 3U - mainFpmBlock(); + } + + const SuperBlock *SB = nullptr; + BitVector FreePageMap; + ArrayRef<support::ulittle32_t> DirectoryBlocks; + ArrayRef<support::ulittle32_t> StreamSizes; + std::vector<ArrayRef<support::ulittle32_t>> StreamMap; +}; + +/// 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; + std::vector<support::ulittle32_t> Blocks; +}; + +/// Determine the layout of the FPM stream, given the MSF layout. An FPM +/// stream spans 1 or more blocks, each at equally spaced intervals throughout +/// the file. +MSFStreamLayout getFpmStreamLayout(const MSFLayout &Msf, + bool IncludeUnusedFpmData = false, + bool AltFpm = false); + +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 divideCeil(NumBytes, BlockSize); +} + +inline uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize) { + return BlockNumber * BlockSize; +} + +inline uint32_t getFpmIntervalLength(const MSFLayout &L) { + return L.SB->BlockSize; +} + +/// Given an MSF with the specified block size and number of blocks, determine +/// how many pieces the specified Fpm is split into. +/// \p BlockSize - the block size of the MSF +/// \p NumBlocks - the total number of blocks in the MSF +/// \p IncludeUnusedFpmData - When true, this will count every block that is +/// both in the file and matches the form of an FPM block, even if some of +/// those FPM blocks are unused (a single FPM block can describe the +/// allocation status of up to 32,767 blocks, although one appears only +/// every 4,096 blocks). So there are 8x as many blocks that match the +/// form as there are blocks that are necessary to describe the allocation +/// status of the file. When this parameter is false, these extraneous +/// trailing blocks are not counted. +inline uint32_t getNumFpmIntervals(uint32_t BlockSize, uint32_t NumBlocks, + bool IncludeUnusedFpmData, int FpmNumber) { + assert(FpmNumber == 1 || FpmNumber == 2); + if (IncludeUnusedFpmData) { + // This calculation determines how many times a number of the form + // BlockSize * k + N appears in the range [0, NumBlocks). We only need to + // do this when unused data is included, since the number of blocks dwarfs + // the number of fpm blocks. + return divideCeil(NumBlocks - FpmNumber, BlockSize); + } + + // We want the minimum number of intervals required, where each interval can + // represent BlockSize * 8 blocks. + return divideCeil(NumBlocks, 8 * BlockSize); +} + +inline uint32_t getNumFpmIntervals(const MSFLayout &L, + bool IncludeUnusedFpmData = false, + bool AltFpm = false) { + return getNumFpmIntervals(L.SB->BlockSize, L.SB->NumBlocks, + IncludeUnusedFpmData, + AltFpm ? L.alternateFpmBlock() : L.mainFpmBlock()); +} + +Error validateSuperBlock(const SuperBlock &SB); + +} // end namespace msf +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_MSF_MSFCOMMON_H diff --git a/clang-r353983/include/llvm/DebugInfo/MSF/MSFError.h b/clang-r353983/include/llvm/DebugInfo/MSF/MSFError.h new file mode 100644 index 00000000..fbc4e692 --- /dev/null +++ b/clang-r353983/include/llvm/DebugInfo/MSF/MSFError.h @@ -0,0 +1,52 @@ +//===- MSFError.h - Error extensions for MSF Files --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#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 +}; +} // namespace msf +} // namespace llvm + +namespace std { +template <> +struct is_error_code_enum<llvm::msf::msf_error_code> : std::true_type {}; +} // namespace std + +namespace llvm { +namespace msf { +const std::error_category &MSFErrCategory(); + +inline std::error_code make_error_code(msf_error_code E) { + return std::error_code(static_cast<int>(E), MSFErrCategory()); +} + +/// Base class for errors originating when parsing raw PDB files +class MSFError : public ErrorInfo<MSFError, StringError> { +public: + using ErrorInfo<MSFError, StringError>::ErrorInfo; // inherit constructors + MSFError(const Twine &S) : ErrorInfo(S, msf_error_code::unspecified) {} + static char ID; +}; +} // namespace msf +} // namespace llvm + +#endif // LLVM_DEBUGINFO_MSF_MSFERROR_H diff --git a/clang-r353983/include/llvm/DebugInfo/MSF/MappedBlockStream.h b/clang-r353983/include/llvm/DebugInfo/MSF/MappedBlockStream.h new file mode 100644 index 00000000..593d781b --- /dev/null +++ b/clang-r353983/include/llvm/DebugInfo/MSF/MappedBlockStream.h @@ -0,0 +1,162 @@ +//==- MappedBlockStream.h - Discontiguous stream data in an MSF --*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_MSF_MAPPEDBLOCKSTREAM_H +#define LLVM_DEBUGINFO_MSF_MAPPEDBLOCKSTREAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/DebugInfo/MSF/MSFCommon.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 <cstdint> +#include <memory> +#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 BinaryStream { + friend class WritableMappedBlockStream; + +public: + static std::unique_ptr<MappedBlockStream> + createStream(uint32_t BlockSize, const MSFStreamLayout &Layout, + BinaryStreamRef MsfData, BumpPtrAllocator &Allocator); + + static std::unique_ptr<MappedBlockStream> + createIndexedStream(const MSFLayout &Layout, BinaryStreamRef MsfData, + uint32_t StreamIndex, BumpPtrAllocator &Allocator); + + static std::unique_ptr<MappedBlockStream> + createFpmStream(const MSFLayout &Layout, BinaryStreamRef MsfData, + BumpPtrAllocator &Allocator); + + static std::unique_ptr<MappedBlockStream> + createDirectoryStream(const MSFLayout &Layout, BinaryStreamRef MsfData, + BumpPtrAllocator &Allocator); + + support::endianness getEndian() const override { + return support::little; + } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override; + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override; + + uint32_t getLength() override; + + BumpPtrAllocator &getAllocator() { return Allocator; } + + void invalidateCache(); + + uint32_t getBlockSize() const { return BlockSize; } + uint32_t getNumBlocks() const { return StreamLayout.Blocks.size(); } + uint32_t getStreamLength() const { return StreamLayout.Length; } + +protected: + MappedBlockStream(uint32_t BlockSize, const MSFStreamLayout &StreamLayout, + BinaryStreamRef MsfData, BumpPtrAllocator &Allocator); + +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); + bool tryReadContiguously(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer); + + const uint32_t BlockSize; + const MSFStreamLayout StreamLayout; + BinaryStreamRef MsfData; + + using CacheEntry = MutableArrayRef<uint8_t>; + + // We just store the allocator by reference. We use this to allocate + // contiguous memory for things like arrays or strings that cross a block + // boundary, and this memory is expected to outlive the stream. For example, + // someone could create a stream, read some stuff, then close the stream, and + // we would like outstanding references to fields to remain valid since the + // entire file is mapped anyway. Because of that, the user must supply the + // allocator to allocate broken records from. + BumpPtrAllocator &Allocator; + DenseMap<uint32_t, std::vector<CacheEntry>> CacheMap; +}; + +class WritableMappedBlockStream : public WritableBinaryStream { +public: + static std::unique_ptr<WritableMappedBlockStream> + createStream(uint32_t BlockSize, const MSFStreamLayout &Layout, + WritableBinaryStreamRef MsfData, BumpPtrAllocator &Allocator); + + static std::unique_ptr<WritableMappedBlockStream> + createIndexedStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData, + uint32_t StreamIndex, BumpPtrAllocator &Allocator); + + static std::unique_ptr<WritableMappedBlockStream> + createDirectoryStream(const MSFLayout &Layout, + WritableBinaryStreamRef MsfData, + BumpPtrAllocator &Allocator); + + static std::unique_ptr<WritableMappedBlockStream> + createFpmStream(const MSFLayout &Layout, WritableBinaryStreamRef MsfData, + BumpPtrAllocator &Allocator, bool AltFpm = false); + + support::endianness getEndian() const override { + return support::little; + } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override; + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override; + uint32_t getLength() override; + + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override; + + Error commit() 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, + const MSFStreamLayout &StreamLayout, + WritableBinaryStreamRef MsfData, + BumpPtrAllocator &Allocator); + +private: + MappedBlockStream ReadInterface; + WritableBinaryStreamRef WriteInterface; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif // LLVM_DEBUGINFO_MSF_MAPPEDBLOCKSTREAM_H |
