Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[pdb] Introduce MsfBuilder for laying out PDB files.
Reviewed by: ruiu Differential Revision: https://reviews.llvm.org/D22308 llvm-svn: 275611
- Loading branch information
Zachary Turner
committed
Jul 15, 2016
1 parent
511f2e5
commit f52a899
Showing
9 changed files
with
854 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
//===- 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_PDB_RAW_MSFBUILDER_H | ||
#define LLVM_DEBUGINFO_PDB_RAW_MSFBUILDER_H | ||
|
||
#include "llvm/ADT/ArrayRef.h" | ||
#include "llvm/ADT/BitVector.h" | ||
|
||
#include "llvm/DebugInfo/PDB/Raw/MsfCommon.h" | ||
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" | ||
|
||
#include "llvm/Support/Allocator.h" | ||
#include "llvm/Support/Endian.h" | ||
#include "llvm/Support/Error.h" | ||
|
||
#include <utility> | ||
#include <vector> | ||
|
||
namespace llvm { | ||
namespace pdb { | ||
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 PDB that you want to write back out later. The | ||
/// original PDB 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 PDB 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 PDB 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 PDB and you want the layout to be as stable as possible. | ||
Error setBlockMapAddr(uint32_t Addr); | ||
|
||
/// Add a stream to the MSF file with the given size, occupying the given | ||
/// list of blocks. This is useful when reading a PDB 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<msf::Layout> 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 BlockSize; | ||
uint32_t MininumBlocks; | ||
uint32_t BlockMapAddr; | ||
BitVector FreeBlocks; | ||
std::vector<uint32_t> DirectoryBlocks; | ||
std::vector<std::pair<uint32_t, BlockList>> StreamData; | ||
}; | ||
} | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
//===- 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_PDB_RAW_MSFCOMMON_H | ||
#define LLVM_DEBUGINFO_PDB_RAW_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 pdb { | ||
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; | ||
// This field's purpose is not yet known. | ||
support::ulittle32_t Unknown0; | ||
// This contains the number of blocks resident in the file system. In | ||
// practice, NumBlocks * BlockSize is equivalent to the size of the PDB | ||
// 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 Layout { | ||
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; | ||
} | ||
|
||
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); | ||
} | ||
} | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.