forked from OSchip/llvm-project
[pdb] Add unit tests for PDB MappedBlockStream and zero copy
Differential Revision: http://reviews.llvm.org/D20837 Reviewed By: ruiu llvm-svn: 271346
This commit is contained in:
parent
f9acacaa92
commit
90b8b8db2e
|
@ -19,16 +19,12 @@
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
namespace pdb {
|
namespace pdb {
|
||||||
|
|
||||||
struct IPDBFile {
|
class IPDBFile {
|
||||||
public:
|
public:
|
||||||
virtual ~IPDBFile() {}
|
virtual ~IPDBFile() {}
|
||||||
|
|
||||||
virtual uint32_t getBlockSize() const = 0;
|
virtual uint32_t getBlockSize() const = 0;
|
||||||
virtual uint32_t getBlockCount() const = 0;
|
virtual uint32_t getBlockCount() const = 0;
|
||||||
virtual uint32_t getNumDirectoryBytes() const = 0;
|
|
||||||
virtual uint32_t getBlockMapIndex() const = 0;
|
|
||||||
virtual uint32_t getNumDirectoryBlocks() const = 0;
|
|
||||||
virtual uint64_t getBlockMapOffset() const = 0;
|
|
||||||
|
|
||||||
virtual uint32_t getNumStreams() const = 0;
|
virtual uint32_t getNumStreams() const = 0;
|
||||||
virtual uint32_t getStreamByteSize(uint32_t StreamIndex) const = 0;
|
virtual uint32_t getStreamByteSize(uint32_t StreamIndex) const = 0;
|
||||||
|
@ -36,8 +32,6 @@ public:
|
||||||
|
|
||||||
virtual StringRef getBlockData(uint32_t BlockIndex,
|
virtual StringRef getBlockData(uint32_t BlockIndex,
|
||||||
uint32_t NumBytes) const = 0;
|
uint32_t NumBytes) const = 0;
|
||||||
|
|
||||||
virtual ArrayRef<support::ulittle32_t> getDirectoryBlockArray() = 0;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
namespace pdb {
|
namespace pdb {
|
||||||
|
class PDBFile;
|
||||||
class InfoStream {
|
class InfoStream {
|
||||||
public:
|
public:
|
||||||
InfoStream(PDBFile &File);
|
InfoStream(PDBFile &File);
|
||||||
|
|
|
@ -21,17 +21,19 @@
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
namespace pdb {
|
namespace pdb {
|
||||||
|
|
||||||
class PDBFile;
|
class IPDBFile;
|
||||||
|
|
||||||
class MappedBlockStream : public codeview::StreamInterface {
|
class MappedBlockStream : public codeview::StreamInterface {
|
||||||
public:
|
public:
|
||||||
MappedBlockStream(uint32_t StreamIdx, const PDBFile &File);
|
MappedBlockStream(uint32_t StreamIdx, const IPDBFile &File);
|
||||||
|
|
||||||
Error readBytes(uint32_t Offset, uint32_t Size,
|
Error readBytes(uint32_t Offset, uint32_t Size,
|
||||||
ArrayRef<uint8_t> &Buffer) const override;
|
ArrayRef<uint8_t> &Buffer) const override;
|
||||||
|
|
||||||
uint32_t getLength() const override { return StreamLength; }
|
uint32_t getLength() const override { return StreamLength; }
|
||||||
|
|
||||||
|
uint32_t getNumBytesCopied() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Error readBytes(uint32_t Offset, MutableArrayRef<uint8_t> Buffer) const;
|
Error readBytes(uint32_t Offset, MutableArrayRef<uint8_t> Buffer) const;
|
||||||
bool tryReadContiguously(uint32_t Offset, uint32_t Size,
|
bool tryReadContiguously(uint32_t Offset, uint32_t Size,
|
||||||
|
@ -41,7 +43,7 @@ private:
|
||||||
std::vector<uint32_t> BlockList;
|
std::vector<uint32_t> BlockList;
|
||||||
mutable llvm::BumpPtrAllocator Pool;
|
mutable llvm::BumpPtrAllocator Pool;
|
||||||
mutable DenseMap<uint32_t, uint8_t *> CacheMap;
|
mutable DenseMap<uint32_t, uint8_t *> CacheMap;
|
||||||
const PDBFile &Pdb;
|
const IPDBFile &Pdb;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace pdb
|
} // end namespace pdb
|
||||||
|
|
|
@ -39,10 +39,10 @@ public:
|
||||||
|
|
||||||
uint32_t getBlockSize() const override;
|
uint32_t getBlockSize() const override;
|
||||||
uint32_t getBlockCount() const override;
|
uint32_t getBlockCount() const override;
|
||||||
uint32_t getNumDirectoryBytes() const override;
|
uint32_t getNumDirectoryBytes() const;
|
||||||
uint32_t getBlockMapIndex() const override;
|
uint32_t getBlockMapIndex() const;
|
||||||
uint32_t getNumDirectoryBlocks() const override;
|
uint32_t getNumDirectoryBlocks() const;
|
||||||
uint64_t getBlockMapOffset() const override;
|
uint64_t getBlockMapOffset() const;
|
||||||
|
|
||||||
uint32_t getNumStreams() const override;
|
uint32_t getNumStreams() const override;
|
||||||
uint32_t getStreamByteSize(uint32_t StreamIndex) const override;
|
uint32_t getStreamByteSize(uint32_t StreamIndex) const override;
|
||||||
|
@ -50,7 +50,7 @@ public:
|
||||||
|
|
||||||
StringRef getBlockData(uint32_t BlockIndex, uint32_t NumBytes) const override;
|
StringRef getBlockData(uint32_t BlockIndex, uint32_t NumBytes) const override;
|
||||||
|
|
||||||
ArrayRef<support::ulittle32_t> getDirectoryBlockArray() override;
|
ArrayRef<support::ulittle32_t> getDirectoryBlockArray();
|
||||||
|
|
||||||
Error parseFileHeaders();
|
Error parseFileHeaders();
|
||||||
Error parseStreamData();
|
Error parseStreamData();
|
||||||
|
|
|
@ -278,6 +278,8 @@ public:
|
||||||
return TotalMemory;
|
return TotalMemory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t getBytesAllocated() const { return BytesAllocated; }
|
||||||
|
|
||||||
void PrintStats() const {
|
void PrintStats() const {
|
||||||
detail::printBumpPtrAllocatorStats(Slabs.size(), BytesAllocated,
|
detail::printBumpPtrAllocatorStats(Slabs.size(), BytesAllocated,
|
||||||
getTotalMemory());
|
getTotalMemory());
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "llvm/ADT/BitVector.h"
|
#include "llvm/ADT/BitVector.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/DebugInfo/CodeView/StreamReader.h"
|
#include "llvm/DebugInfo/CodeView/StreamReader.h"
|
||||||
|
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
|
||||||
#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
|
#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
|
||||||
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
|
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace llvm::pdb;
|
using namespace llvm::pdb;
|
||||||
|
|
||||||
MappedBlockStream::MappedBlockStream(uint32_t StreamIdx, const PDBFile &File) : Pdb(File) {
|
MappedBlockStream::MappedBlockStream(uint32_t StreamIdx, const IPDBFile &File)
|
||||||
|
: Pdb(File) {
|
||||||
if (StreamIdx >= Pdb.getNumStreams()) {
|
if (StreamIdx >= Pdb.getNumStreams()) {
|
||||||
StreamLength = 0;
|
StreamLength = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -119,3 +120,7 @@ Error MappedBlockStream::readBytes(uint32_t Offset,
|
||||||
return Error::success();
|
return Error::success();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t MappedBlockStream::getNumBytesCopied() const {
|
||||||
|
return static_cast<uint32_t>(Pool.getBytesAllocated());
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "llvm/DebugInfo/CodeView/StreamReader.h"
|
#include "llvm/DebugInfo/CodeView/StreamReader.h"
|
||||||
#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
|
#include "llvm/DebugInfo/PDB/Raw/ModInfo.h"
|
||||||
|
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
|
||||||
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
|
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "llvm/DebugInfo/CodeView/StreamReader.h"
|
#include "llvm/DebugInfo/CodeView/StreamReader.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
|
#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
|
||||||
|
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
|
||||||
#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
|
#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
|
||||||
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
|
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "llvm/DebugInfo/CodeView/StreamReader.h"
|
#include "llvm/DebugInfo/CodeView/StreamReader.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
|
#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
|
||||||
|
#include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
|
||||||
#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
|
#include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
|
||||||
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
|
#include "llvm/DebugInfo/PDB/Raw/RawError.h"
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS
|
||||||
)
|
)
|
||||||
|
|
||||||
set(DebugInfoPDBSources
|
set(DebugInfoPDBSources
|
||||||
|
MappedBlockStreamTest.cpp
|
||||||
PDBApiTest.cpp
|
PDBApiTest.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,161 @@
|
||||||
|
//===- llvm/unittest/DebugInfo/PDB/MappedBlockStreamTest.cpp --------------===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "llvm/DebugInfo/CodeView/StreamReader.h"
|
||||||
|
#include "llvm/DebugInfo/CodeView/StreamRef.h"
|
||||||
|
#include "llvm/DebugInfo/PDB/Raw/IPDBFile.h"
|
||||||
|
#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
using namespace llvm::codeview;
|
||||||
|
using namespace llvm::pdb;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
#define EXPECT_NO_ERROR(Err) \
|
||||||
|
{ \
|
||||||
|
auto E = std::move(Err); \
|
||||||
|
EXPECT_FALSE(static_cast<bool>(E)); \
|
||||||
|
if (E) \
|
||||||
|
consumeError(std::move(E)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXPECT_ERROR(Err) \
|
||||||
|
{ \
|
||||||
|
auto E = std::move(Err); \
|
||||||
|
EXPECT_TRUE(static_cast<bool>(E)); \
|
||||||
|
if (E) \
|
||||||
|
consumeError(std::move(E)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
class DiscontiguousFile : public IPDBFile {
|
||||||
|
public:
|
||||||
|
DiscontiguousFile()
|
||||||
|
: Blocks{0, 1, 2, 5, 4, 3, 6, 7, 8, 9},
|
||||||
|
Data{'A', 'B', 'C', 'F', 'E', 'D', 'G', 'H', 'I', 'J'} {}
|
||||||
|
|
||||||
|
virtual uint32_t getBlockSize() const override { return 1; }
|
||||||
|
virtual uint32_t getBlockCount() const override { return 10; }
|
||||||
|
virtual uint32_t getNumStreams() const override { return 1; }
|
||||||
|
virtual uint32_t getStreamByteSize(uint32_t StreamIndex) const override {
|
||||||
|
return getBlockCount() * getBlockSize();
|
||||||
|
}
|
||||||
|
virtual ArrayRef<uint32_t>
|
||||||
|
getStreamBlockList(uint32_t StreamIndex) const override {
|
||||||
|
if (StreamIndex != 0)
|
||||||
|
return ArrayRef<uint32_t>();
|
||||||
|
return Blocks;
|
||||||
|
}
|
||||||
|
virtual StringRef getBlockData(uint32_t BlockIndex,
|
||||||
|
uint32_t NumBytes) const override {
|
||||||
|
return StringRef(&Data[BlockIndex], NumBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<uint32_t> Blocks;
|
||||||
|
std::vector<char> Data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tests that a read which is entirely contained within a single block works
|
||||||
|
// and does not allocate.
|
||||||
|
TEST(MappedBlockStreamTest, ZeroCopyReadNoBreak) {
|
||||||
|
DiscontiguousFile F;
|
||||||
|
MappedBlockStream S(0, F);
|
||||||
|
StreamReader R(S);
|
||||||
|
StringRef Str;
|
||||||
|
EXPECT_NO_ERROR(R.readFixedString(Str, 1));
|
||||||
|
EXPECT_EQ(Str, StringRef("A"));
|
||||||
|
EXPECT_EQ(0, S.getNumBytesCopied());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that a read which outputs into a full destination buffer works and
|
||||||
|
// does not fail due to the length of the output buffer.
|
||||||
|
TEST(MappedBlockStreamTest, ReadOntoNonEmptyBuffer) {
|
||||||
|
DiscontiguousFile F;
|
||||||
|
MappedBlockStream S(0, F);
|
||||||
|
StreamReader R(S);
|
||||||
|
StringRef Str = "ZYXWVUTSRQPONMLKJIHGFEDCBA";
|
||||||
|
EXPECT_NO_ERROR(R.readFixedString(Str, 1));
|
||||||
|
EXPECT_EQ(Str, StringRef("A"));
|
||||||
|
EXPECT_EQ(0, S.getNumBytesCopied());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that a read which crosses a block boundary, but where the subsequent
|
||||||
|
// blocks are still contiguous in memory to the previous block works and does
|
||||||
|
// not allocate memory.
|
||||||
|
TEST(MappedBlockStreamTest, ZeroCopyReadContiguousBreak) {
|
||||||
|
DiscontiguousFile F;
|
||||||
|
MappedBlockStream S(0, F);
|
||||||
|
StreamReader R(S);
|
||||||
|
StringRef Str;
|
||||||
|
EXPECT_NO_ERROR(R.readFixedString(Str, 2));
|
||||||
|
EXPECT_EQ(Str, StringRef("AB"));
|
||||||
|
EXPECT_EQ(0, S.getNumBytesCopied());
|
||||||
|
|
||||||
|
R.setOffset(6);
|
||||||
|
EXPECT_NO_ERROR(R.readFixedString(Str, 4));
|
||||||
|
EXPECT_EQ(Str, StringRef("GHIJ"));
|
||||||
|
EXPECT_EQ(0, S.getNumBytesCopied());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that a read which crosses a block boundary and cannot be referenced
|
||||||
|
// contiguously works and allocates only the precise amount of bytes
|
||||||
|
// requested.
|
||||||
|
TEST(MappedBlockStreamTest, CopyReadNonContiguousBreak) {
|
||||||
|
DiscontiguousFile F;
|
||||||
|
MappedBlockStream S(0, F);
|
||||||
|
StreamReader R(S);
|
||||||
|
StringRef Str;
|
||||||
|
EXPECT_NO_ERROR(R.readFixedString(Str, 10));
|
||||||
|
EXPECT_EQ(Str, StringRef("ABCDEFGHIJ"));
|
||||||
|
EXPECT_EQ(10, S.getNumBytesCopied());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that an out of bounds read which doesn't cross a block boundary
|
||||||
|
// fails and allocates no memory.
|
||||||
|
TEST(MappedBlockStreamTest, InvalidReadSizeNoBreak) {
|
||||||
|
DiscontiguousFile F;
|
||||||
|
MappedBlockStream S(0, F);
|
||||||
|
StreamReader R(S);
|
||||||
|
StringRef Str;
|
||||||
|
|
||||||
|
R.setOffset(10);
|
||||||
|
EXPECT_ERROR(R.readFixedString(Str, 1));
|
||||||
|
EXPECT_EQ(0, S.getNumBytesCopied());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that an out of bounds read which crosses a contiguous block boundary
|
||||||
|
// fails and allocates no memory.
|
||||||
|
TEST(MappedBlockStreamTest, InvalidReadSizeContiguousBreak) {
|
||||||
|
DiscontiguousFile F;
|
||||||
|
MappedBlockStream S(0, F);
|
||||||
|
StreamReader R(S);
|
||||||
|
StringRef Str;
|
||||||
|
|
||||||
|
R.setOffset(6);
|
||||||
|
EXPECT_ERROR(R.readFixedString(Str, 5));
|
||||||
|
EXPECT_EQ(0, S.getNumBytesCopied());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that an out of bounds read which crosses a discontiguous block
|
||||||
|
// boundary fails and allocates no memory.
|
||||||
|
TEST(MappedBlockStreamTest, InvalidReadSizeNonContiguousBreak) {
|
||||||
|
DiscontiguousFile F;
|
||||||
|
MappedBlockStream S(0, F);
|
||||||
|
StreamReader R(S);
|
||||||
|
StringRef Str;
|
||||||
|
|
||||||
|
EXPECT_ERROR(R.readFixedString(Str, 11));
|
||||||
|
EXPECT_EQ(0, S.getNumBytesCopied());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end anonymous namespace
|
Loading…
Reference in New Issue