Imported Upstream version 5.18.0.167

Former-commit-id: 289509151e0fee68a1b591a20c9f109c3c789d3a
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-10-20 08:25:10 +00:00
parent e19d552987
commit b084638f15
28489 changed files with 184 additions and 3866856 deletions

View File

@ -1,4 +0,0 @@
add_subdirectory(CodeView)
add_subdirectory(DWARF)
add_subdirectory(MSF)
add_subdirectory(PDB)

View File

@ -1,15 +0,0 @@
set(LLVM_LINK_COMPONENTS
DebugInfoCodeView
)
set(DebugInfoCodeViewSources
RandomAccessVisitorTest.cpp
TypeHashingTest.cpp
TypeIndexDiscoveryTest.cpp
)
add_llvm_unittest(DebugInfoCodeViewTests
${DebugInfoCodeViewSources}
)
target_link_libraries(DebugInfoCodeViewTests PRIVATE LLVMTestingSupport)

View File

@ -1,402 +0,0 @@
//===- llvm/unittest/DebugInfo/CodeView/RandomAccessVisitorTest.cpp -------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/BinaryItemStream.h"
#include "llvm/Support/Error.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace llvm::codeview;
using namespace llvm::pdb;
namespace llvm {
namespace codeview {
inline bool operator==(const ArrayRecord &R1, const ArrayRecord &R2) {
if (R1.ElementType != R2.ElementType)
return false;
if (R1.IndexType != R2.IndexType)
return false;
if (R1.Name != R2.Name)
return false;
if (R1.Size != R2.Size)
return false;
return true;
}
inline bool operator!=(const ArrayRecord &R1, const ArrayRecord &R2) {
return !(R1 == R2);
}
inline bool operator==(const CVType &R1, const CVType &R2) {
if (R1.Type != R2.Type)
return false;
if (R1.RecordData != R2.RecordData)
return false;
return true;
}
inline bool operator!=(const CVType &R1, const CVType &R2) {
return !(R1 == R2);
}
}
}
namespace llvm {
template <> struct BinaryItemTraits<CVType> {
static size_t length(const CVType &Item) { return Item.length(); }
static ArrayRef<uint8_t> bytes(const CVType &Item) { return Item.data(); }
};
}
namespace {
class MockCallbacks : public TypeVisitorCallbacks {
public:
virtual Error visitTypeBegin(CVType &CVR, TypeIndex Index) {
Indices.push_back(Index);
return Error::success();
}
virtual Error visitKnownRecord(CVType &CVR, ArrayRecord &AR) {
VisitedRecords.push_back(AR);
RawRecords.push_back(CVR);
return Error::success();
}
uint32_t count() const {
assert(Indices.size() == RawRecords.size());
assert(Indices.size() == VisitedRecords.size());
return Indices.size();
}
std::vector<TypeIndex> Indices;
std::vector<CVType> RawRecords;
std::vector<ArrayRecord> VisitedRecords;
};
class RandomAccessVisitorTest : public testing::Test {
public:
RandomAccessVisitorTest() {}
static void SetUpTestCase() {
GlobalState = llvm::make_unique<GlobalTestState>();
AppendingTypeTableBuilder Builder(GlobalState->Allocator);
uint32_t Offset = 0;
for (int I = 0; I < 11; ++I) {
ArrayRecord AR(TypeRecordKind::Array);
AR.ElementType = TypeIndex::Int32();
AR.IndexType = TypeIndex::UInt32();
AR.Size = I;
std::string Name;
raw_string_ostream Stream(Name);
Stream << "Array [" << I << "]";
AR.Name = GlobalState->Strings.save(Stream.str());
GlobalState->Records.push_back(AR);
GlobalState->Indices.push_back(Builder.writeLeafType(AR));
CVType Type(TypeLeafKind::LF_ARRAY, Builder.records().back());
GlobalState->TypeVector.push_back(Type);
GlobalState->AllOffsets.push_back(
{GlobalState->Indices.back(), ulittle32_t(Offset)});
Offset += Type.length();
}
GlobalState->ItemStream.setItems(GlobalState->TypeVector);
GlobalState->TypeArray = VarStreamArray<CVType>(GlobalState->ItemStream);
}
static void TearDownTestCase() { GlobalState.reset(); }
void SetUp() override {
TestState = llvm::make_unique<PerTestState>();
}
void TearDown() override { TestState.reset(); }
protected:
bool ValidateDatabaseRecord(LazyRandomTypeCollection &Types, uint32_t Index) {
TypeIndex TI = TypeIndex::fromArrayIndex(Index);
if (!Types.contains(TI))
return false;
if (GlobalState->TypeVector[Index] != Types.getType(TI))
return false;
return true;
}
bool ValidateVisitedRecord(uint32_t VisitationOrder,
uint32_t GlobalArrayIndex) {
TypeIndex TI = TypeIndex::fromArrayIndex(GlobalArrayIndex);
if (TI != TestState->Callbacks.Indices[VisitationOrder])
return false;
if (GlobalState->TypeVector[TI.toArrayIndex()] !=
TestState->Callbacks.RawRecords[VisitationOrder])
return false;
if (GlobalState->Records[TI.toArrayIndex()] !=
TestState->Callbacks.VisitedRecords[VisitationOrder])
return false;
return true;
}
struct GlobalTestState {
GlobalTestState() : Strings(Allocator), ItemStream(llvm::support::little) {}
BumpPtrAllocator Allocator;
StringSaver Strings;
std::vector<ArrayRecord> Records;
std::vector<TypeIndex> Indices;
std::vector<TypeIndexOffset> AllOffsets;
std::vector<CVType> TypeVector;
BinaryItemStream<CVType> ItemStream;
VarStreamArray<CVType> TypeArray;
MutableBinaryByteStream Stream;
};
struct PerTestState {
FixedStreamArray<TypeIndexOffset> Offsets;
MockCallbacks Callbacks;
};
FixedStreamArray<TypeIndexOffset>
createPartialOffsets(MutableBinaryByteStream &Storage,
std::initializer_list<uint32_t> Indices) {
uint32_t Count = Indices.size();
uint32_t Size = Count * sizeof(TypeIndexOffset);
uint8_t *Buffer = GlobalState->Allocator.Allocate<uint8_t>(Size);
MutableArrayRef<uint8_t> Bytes(Buffer, Size);
Storage = MutableBinaryByteStream(Bytes, support::little);
BinaryStreamWriter Writer(Storage);
for (const auto I : Indices)
consumeError(Writer.writeObject(GlobalState->AllOffsets[I]));
BinaryStreamReader Reader(Storage);
FixedStreamArray<TypeIndexOffset> Result;
consumeError(Reader.readArray(Result, Count));
return Result;
}
static std::unique_ptr<GlobalTestState> GlobalState;
std::unique_ptr<PerTestState> TestState;
};
std::unique_ptr<RandomAccessVisitorTest::GlobalTestState>
RandomAccessVisitorTest::GlobalState;
}
TEST_F(RandomAccessVisitorTest, MultipleVisits) {
TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8});
LazyRandomTypeCollection Types(GlobalState->TypeArray,
GlobalState->TypeVector.size(),
TestState->Offsets);
std::vector<uint32_t> IndicesToVisit = {5, 5, 5};
for (uint32_t I : IndicesToVisit) {
TypeIndex TI = TypeIndex::fromArrayIndex(I);
CVType T = Types.getType(TI);
EXPECT_THAT_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks),
Succeeded());
}
// [0,8) should be present
EXPECT_EQ(8u, Types.size());
for (uint32_t I = 0; I < 8; ++I)
EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
// 5, 5, 5
EXPECT_EQ(3u, TestState->Callbacks.count());
for (auto I : enumerate(IndicesToVisit))
EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value()));
}
TEST_F(RandomAccessVisitorTest, DescendingWithinChunk) {
// Visit multiple items from the same "chunk" in reverse order. In this
// example, it's 7 then 4 then 2. At the end, all records from 0 to 7 should
// be known by the database, but only 2, 4, and 7 should have been visited.
TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8});
std::vector<uint32_t> IndicesToVisit = {7, 4, 2};
LazyRandomTypeCollection Types(GlobalState->TypeArray,
GlobalState->TypeVector.size(),
TestState->Offsets);
for (uint32_t I : IndicesToVisit) {
TypeIndex TI = TypeIndex::fromArrayIndex(I);
CVType T = Types.getType(TI);
EXPECT_THAT_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks),
Succeeded());
}
// [0, 7]
EXPECT_EQ(8u, Types.size());
for (uint32_t I = 0; I < 8; ++I)
EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
// 2, 4, 7
EXPECT_EQ(3u, TestState->Callbacks.count());
for (auto I : enumerate(IndicesToVisit))
EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value()));
}
TEST_F(RandomAccessVisitorTest, AscendingWithinChunk) {
// * Visit multiple items from the same chunk in ascending order, ensuring
// that intermediate items are not visited. In the below example, it's
// 5 -> 6 -> 7 which come from the [4,8) chunk.
TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8});
std::vector<uint32_t> IndicesToVisit = {2, 4, 7};
LazyRandomTypeCollection Types(GlobalState->TypeArray,
GlobalState->TypeVector.size(),
TestState->Offsets);
for (uint32_t I : IndicesToVisit) {
TypeIndex TI = TypeIndex::fromArrayIndex(I);
CVType T = Types.getType(TI);
EXPECT_THAT_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks),
Succeeded());
}
// [0, 7]
EXPECT_EQ(8u, Types.size());
for (uint32_t I = 0; I < 8; ++I)
EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
// 2, 4, 7
EXPECT_EQ(3u, TestState->Callbacks.count());
for (auto &I : enumerate(IndicesToVisit))
EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value()));
}
TEST_F(RandomAccessVisitorTest, StopPrematurelyInChunk) {
// * Don't visit the last item in one chunk, ensuring that visitation stops
// at the record you specify, and the chunk is only partially visited.
// In the below example, this is tested by visiting 0 and 1 but not 2,
// all from the [0,3) chunk.
TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8});
std::vector<uint32_t> IndicesToVisit = {0, 1, 2};
LazyRandomTypeCollection Types(GlobalState->TypeArray,
GlobalState->TypeVector.size(),
TestState->Offsets);
for (uint32_t I : IndicesToVisit) {
TypeIndex TI = TypeIndex::fromArrayIndex(I);
CVType T = Types.getType(TI);
EXPECT_THAT_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks),
Succeeded());
}
// [0, 8) should be visited.
EXPECT_EQ(8u, Types.size());
for (uint32_t I = 0; I < 8; ++I)
EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
// [0, 2]
EXPECT_EQ(3u, TestState->Callbacks.count());
for (auto I : enumerate(IndicesToVisit))
EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value()));
}
TEST_F(RandomAccessVisitorTest, InnerChunk) {
// Test that when a request comes from a chunk in the middle of the partial
// offsets array, that items from surrounding chunks are not visited or
// added to the database.
TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 4, 9});
std::vector<uint32_t> IndicesToVisit = {5, 7};
LazyRandomTypeCollection Types(GlobalState->TypeArray,
GlobalState->TypeVector.size(),
TestState->Offsets);
for (uint32_t I : IndicesToVisit) {
TypeIndex TI = TypeIndex::fromArrayIndex(I);
CVType T = Types.getType(TI);
EXPECT_THAT_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks),
Succeeded());
}
// [4, 9)
EXPECT_EQ(5u, Types.size());
for (uint32_t I = 4; I < 9; ++I)
EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
// 5, 7
EXPECT_EQ(2u, TestState->Callbacks.count());
for (auto &I : enumerate(IndicesToVisit))
EXPECT_TRUE(ValidateVisitedRecord(I.index(), I.value()));
}
TEST_F(RandomAccessVisitorTest, CrossChunkName) {
AppendingTypeTableBuilder Builder(GlobalState->Allocator);
// TypeIndex 0
ClassRecord Class(TypeRecordKind::Class);
Class.Name = "FooClass";
Class.Options = ClassOptions::None;
Class.MemberCount = 0;
Class.Size = 4U;
Class.DerivationList = TypeIndex::fromArrayIndex(0);
Class.FieldList = TypeIndex::fromArrayIndex(0);
Class.VTableShape = TypeIndex::fromArrayIndex(0);
TypeIndex IndexZero = Builder.writeLeafType(Class);
// TypeIndex 1 refers to type index 0.
ModifierRecord Modifier(TypeRecordKind::Modifier);
Modifier.ModifiedType = TypeIndex::fromArrayIndex(0);
Modifier.Modifiers = ModifierOptions::Const;
TypeIndex IndexOne = Builder.writeLeafType(Modifier);
// set up a type stream that refers to the above two serialized records.
std::vector<CVType> TypeArray;
TypeArray.push_back(
CVType(static_cast<TypeLeafKind>(Class.Kind), Builder.records()[0]));
TypeArray.push_back(
CVType(static_cast<TypeLeafKind>(Modifier.Kind), Builder.records()[1]));
BinaryItemStream<CVType> ItemStream(llvm::support::little);
ItemStream.setItems(TypeArray);
VarStreamArray<CVType> TypeStream(ItemStream);
// Figure out the byte offset of the second item.
auto ItemOneIter = TypeStream.begin();
++ItemOneIter;
// Set up a partial offsets buffer that contains the first and second items
// in separate chunks.
std::vector<TypeIndexOffset> TIO;
TIO.push_back({IndexZero, ulittle32_t(0u)});
TIO.push_back({IndexOne, ulittle32_t(ItemOneIter.offset())});
ArrayRef<uint8_t> Buffer(reinterpret_cast<const uint8_t *>(TIO.data()),
TIO.size() * sizeof(TypeIndexOffset));
BinaryStreamReader Reader(Buffer, llvm::support::little);
FixedStreamArray<TypeIndexOffset> PartialOffsets;
ASSERT_THAT_ERROR(Reader.readArray(PartialOffsets, 2), Succeeded());
LazyRandomTypeCollection Types(TypeStream, 2, PartialOffsets);
StringRef Name = Types.getTypeName(IndexOne);
EXPECT_EQ("const FooClass", Name);
}

View File

@ -1,156 +0,0 @@
//===- llvm/unittest/DebugInfo/CodeView/TypeHashingTest.cpp ---------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/CodeView/TypeHashing.h"
#include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace llvm::codeview;
static TypeIndex createPointerRecord(AppendingTypeTableBuilder &Builder,
TypeIndex TI) {
PointerRecord PR(TypeRecordKind::Pointer);
PR.setAttrs(PointerKind::Near32, PointerMode::Pointer, PointerOptions::None,
4);
PR.ReferentType = TI;
return Builder.writeLeafType(PR);
}
static TypeIndex createArgListRecord(AppendingTypeTableBuilder &Builder,
TypeIndex Q, TypeIndex R) {
ArgListRecord AR(TypeRecordKind::ArgList);
AR.ArgIndices.push_back(Q);
AR.ArgIndices.push_back(R);
return Builder.writeLeafType(AR);
}
static TypeIndex createProcedureRecord(AppendingTypeTableBuilder &Builder,
uint32_t ParamCount, TypeIndex Return,
TypeIndex ArgList) {
ProcedureRecord PR(TypeRecordKind::Procedure);
PR.ArgumentList = ArgList;
PR.CallConv = CallingConvention::NearC;
PR.Options = FunctionOptions::None;
PR.ParameterCount = ParamCount;
PR.ReturnType = Return;
return Builder.writeLeafType(PR);
}
static ArrayRef<uint8_t> hash_of(ArrayRef<GloballyHashedType> Hashes,
TypeIndex TI) {
return Hashes[TI.toArrayIndex()].Hash;
}
static void verifyHashUniqueness(ArrayRef<GloballyHashedType> Hashes) {
assert(!Hashes.empty());
for (size_t I = 0; I < Hashes.size() - 1; ++I) {
for (size_t J = I + 1; J < Hashes.size(); ++J) {
EXPECT_NE(Hashes[I].Hash, Hashes[J].Hash);
}
}
}
TEST(TypeHashingTest, ContentHash) {
SimpleTypeSerializer Serializer;
TypeIndex CharStar(SimpleTypeKind::SignedCharacter,
SimpleTypeMode::NearPointer32);
BumpPtrAllocator Alloc;
AppendingTypeTableBuilder Ordering1(Alloc);
AppendingTypeTableBuilder Ordering2(Alloc);
TypeIndex CharP(SimpleTypeKind::SignedCharacter, SimpleTypeMode::NearPointer);
TypeIndex IntP(SimpleTypeKind::Int32, SimpleTypeMode::NearPointer);
TypeIndex DoubleP(SimpleTypeKind::Float64, SimpleTypeMode::NearPointer);
// We're going to the same type sequence with two different orderings, and
// then confirm all records are hashed the same.
TypeIndex CharPP[2];
TypeIndex IntPP[2];
TypeIndex IntPPP[2];
TypeIndex DoublePP[2];
TypeIndex Args[2];
TypeIndex Proc[2];
// Ordering 1
// ----------------------------------------
// LF_POINTER 0x1000 {char**}
// Referent = char*
// LF_POINTER 0x1001 {int**}
// Referent = int*
// LF_POINTER 0x1002 {int***}
// Referent = 0x1001
// LF_ARGLIST 0x1003 {(char**, int***)}
// Arg[0] = 0x1000
// Arg[1] = 0x1002
// LF_PROCEDURE 0x1004 {int** func(char**, int***)}
// ArgList = 0x1003
// ReturnType = 0x1001
std::vector<GloballyHashedType> Ordering1Hashes;
CharPP[0] = createPointerRecord(Ordering1, CharP);
IntPP[0] = createPointerRecord(Ordering1, IntP);
IntPPP[0] = createPointerRecord(Ordering1, IntPP[0]);
Args[0] = createArgListRecord(Ordering1, CharPP[0], IntPPP[0]);
Proc[0] = createProcedureRecord(Ordering1, 2, IntPP[0], Args[0]);
ASSERT_EQ(0x1000U, CharPP[0].getIndex());
ASSERT_EQ(0x1001U, IntPP[0].getIndex());
ASSERT_EQ(0x1002U, IntPPP[0].getIndex());
ASSERT_EQ(0x1003U, Args[0].getIndex());
ASSERT_EQ(0x1004U, Proc[0].getIndex());
auto Hashes1 = GloballyHashedType::hashTypes(Ordering1.records());
// Ordering 2
// ----------------------------------------
// LF_POINTER 0x1000 {int**}
// Referent = int*
// LF_POINTER 0x1001 {int***}
// Referent = 0x1000
// LF_POINTER 0x1002 {char**}
// Referent = char*
// LF_POINTER 0x1003 {double**}
// Referent = double*
// LF_ARGLIST 0x1004 {(char**, int***)}
// Arg[0] = 0x1002
// Arg[1] = 0x1001
// LF_PROCEDURE 0x1005 {int** func(char**, int***)}
// ArgList = 0x1004
// ReturnType = 0x1000
IntPP[1] = createPointerRecord(Ordering2, IntP);
IntPPP[1] = createPointerRecord(Ordering2, IntPP[1]);
CharPP[1] = createPointerRecord(Ordering2, CharP);
DoublePP[1] = createPointerRecord(Ordering2, DoubleP);
Args[1] = createArgListRecord(Ordering2, CharPP[1], IntPPP[1]);
Proc[1] = createProcedureRecord(Ordering2, 2, IntPP[1], Args[1]);
auto Hashes2 = GloballyHashedType::hashTypes(Ordering2.records());
ASSERT_EQ(0x1000U, IntPP[1].getIndex());
ASSERT_EQ(0x1001U, IntPPP[1].getIndex());
ASSERT_EQ(0x1002U, CharPP[1].getIndex());
ASSERT_EQ(0x1003U, DoublePP[1].getIndex());
ASSERT_EQ(0x1004U, Args[1].getIndex());
ASSERT_EQ(0x1005U, Proc[1].getIndex());
// Sanity check to make sure all same-ordering hashes are different
// from each other.
verifyHashUniqueness(Hashes1);
verifyHashUniqueness(Hashes2);
EXPECT_EQ(hash_of(Hashes1, IntPP[0]), hash_of(Hashes2, IntPP[1]));
EXPECT_EQ(hash_of(Hashes1, IntPPP[0]), hash_of(Hashes2, IntPPP[1]));
EXPECT_EQ(hash_of(Hashes1, CharPP[0]), hash_of(Hashes2, CharPP[1]));
EXPECT_EQ(hash_of(Hashes1, Args[0]), hash_of(Hashes2, Args[1]));
EXPECT_EQ(hash_of(Hashes1, Proc[0]), hash_of(Hashes2, Proc[1]));
}

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +0,0 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
AsmPrinter
DebugInfoDWARF
MC
Object
ObjectYAML
Support
)
set(DebugInfoSources
DwarfGenerator.cpp
DWARFDebugInfoTest.cpp
DWARFFormValueTest.cpp
)
add_llvm_unittest(DebugInfoDWARFTests
${DebugInfoSources}
)
target_link_libraries(DebugInfoDWARFTests PRIVATE LLVMTestingSupport)

View File

@ -1 +0,0 @@
cb7bf82d86f603bf5f6b0e88a0b0cf586ba4a1c6

View File

@ -1,177 +0,0 @@
//===- llvm/unittest/DebugInfo/DWARFFormValueTest.cpp ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/LEB128.h"
#include "gtest/gtest.h"
#include <climits>
using namespace llvm;
using namespace dwarf;
namespace {
TEST(DWARFFormValue, FixedFormSizes) {
Optional<uint8_t> RefSize;
Optional<uint8_t> AddrSize;
// Test 32 bit DWARF version 2 with 4 byte addresses.
DWARFFormParams Params_2_4_32 = {2, 4, DWARF32};
RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, Params_2_4_32);
AddrSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, Params_2_4_32);
EXPECT_TRUE(RefSize.hasValue());
EXPECT_TRUE(AddrSize.hasValue());
EXPECT_EQ(*RefSize, *AddrSize);
// Test 32 bit DWARF version 2 with 8 byte addresses.
DWARFFormParams Params_2_8_32 = {2, 8, DWARF32};
RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, Params_2_8_32);
AddrSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, Params_2_8_32);
EXPECT_TRUE(RefSize.hasValue());
EXPECT_TRUE(AddrSize.hasValue());
EXPECT_EQ(*RefSize, *AddrSize);
// DW_FORM_ref_addr is 4 bytes in DWARF 32 in DWARF version 3 and beyond.
DWARFFormParams Params_3_4_32 = {3, 4, DWARF32};
RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, Params_3_4_32);
EXPECT_TRUE(RefSize.hasValue());
EXPECT_EQ(*RefSize, 4);
DWARFFormParams Params_4_4_32 = {4, 4, DWARF32};
RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, Params_4_4_32);
EXPECT_TRUE(RefSize.hasValue());
EXPECT_EQ(*RefSize, 4);
DWARFFormParams Params_5_4_32 = {5, 4, DWARF32};
RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, Params_5_4_32);
EXPECT_TRUE(RefSize.hasValue());
EXPECT_EQ(*RefSize, 4);
// DW_FORM_ref_addr is 8 bytes in DWARF 64 in DWARF version 3 and beyond.
DWARFFormParams Params_3_8_64 = {3, 8, DWARF64};
RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, Params_3_8_64);
EXPECT_TRUE(RefSize.hasValue());
EXPECT_EQ(*RefSize, 8);
DWARFFormParams Params_4_8_64 = {4, 8, DWARF64};
RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, Params_4_8_64);
EXPECT_TRUE(RefSize.hasValue());
EXPECT_EQ(*RefSize, 8);
DWARFFormParams Params_5_8_64 = {5, 8, DWARF64};
RefSize = DWARFFormValue::getFixedByteSize(DW_FORM_ref_addr, Params_5_8_64);
EXPECT_TRUE(RefSize.hasValue());
EXPECT_EQ(*RefSize, 8);
}
bool isFormClass(dwarf::Form Form, DWARFFormValue::FormClass FC) {
return DWARFFormValue(Form).isFormClass(FC);
}
TEST(DWARFFormValue, FormClass) {
EXPECT_TRUE(isFormClass(DW_FORM_addr, DWARFFormValue::FC_Address));
EXPECT_FALSE(isFormClass(DW_FORM_data8, DWARFFormValue::FC_Address));
EXPECT_TRUE(isFormClass(DW_FORM_data8, DWARFFormValue::FC_Constant));
EXPECT_TRUE(isFormClass(DW_FORM_data8, DWARFFormValue::FC_SectionOffset));
EXPECT_TRUE(
isFormClass(DW_FORM_sec_offset, DWARFFormValue::FC_SectionOffset));
EXPECT_TRUE(isFormClass(DW_FORM_GNU_str_index, DWARFFormValue::FC_String));
EXPECT_TRUE(isFormClass(DW_FORM_GNU_addr_index, DWARFFormValue::FC_Address));
EXPECT_FALSE(isFormClass(DW_FORM_ref_addr, DWARFFormValue::FC_Address));
EXPECT_TRUE(isFormClass(DW_FORM_ref_addr, DWARFFormValue::FC_Reference));
EXPECT_TRUE(isFormClass(DW_FORM_ref_sig8, DWARFFormValue::FC_Reference));
}
template<typename RawTypeT>
DWARFFormValue createDataXFormValue(dwarf::Form Form, RawTypeT Value) {
char Raw[sizeof(RawTypeT)];
memcpy(Raw, &Value, sizeof(RawTypeT));
uint32_t Offset = 0;
DWARFFormValue Result(Form);
DWARFDataExtractor Data(StringRef(Raw, sizeof(RawTypeT)),
sys::IsLittleEndianHost, sizeof(void *));
Result.extractValue(Data, &Offset, {0, 0, dwarf::DwarfFormat::DWARF32});
return Result;
}
DWARFFormValue createULEBFormValue(uint64_t Value) {
SmallString<10> RawData;
raw_svector_ostream OS(RawData);
encodeULEB128(Value, OS);
uint32_t Offset = 0;
DWARFFormValue Result(DW_FORM_udata);
DWARFDataExtractor Data(OS.str(), sys::IsLittleEndianHost, sizeof(void *));
Result.extractValue(Data, &Offset, {0, 0, dwarf::DwarfFormat::DWARF32});
return Result;
}
DWARFFormValue createSLEBFormValue(int64_t Value) {
SmallString<10> RawData;
raw_svector_ostream OS(RawData);
encodeSLEB128(Value, OS);
uint32_t Offset = 0;
DWARFFormValue Result(DW_FORM_sdata);
DWARFDataExtractor Data(OS.str(), sys::IsLittleEndianHost, sizeof(void *));
Result.extractValue(Data, &Offset, {0, 0, dwarf::DwarfFormat::DWARF32});
return Result;
}
TEST(DWARFFormValue, SignedConstantForms) {
// Check that we correctly sign extend fixed size forms.
auto Sign1 = createDataXFormValue<uint8_t>(DW_FORM_data1, -123);
auto Sign2 = createDataXFormValue<uint16_t>(DW_FORM_data2, -12345);
auto Sign4 = createDataXFormValue<uint32_t>(DW_FORM_data4, -123456789);
auto Sign8 = createDataXFormValue<uint64_t>(DW_FORM_data8, -1);
EXPECT_EQ(Sign1.getAsSignedConstant().getValue(), -123);
EXPECT_EQ(Sign2.getAsSignedConstant().getValue(), -12345);
EXPECT_EQ(Sign4.getAsSignedConstant().getValue(), -123456789);
EXPECT_EQ(Sign8.getAsSignedConstant().getValue(), -1);
// Check that we can handle big positive values, but that we return
// an error just over the limit.
auto UMax = createULEBFormValue(LLONG_MAX);
auto TooBig = createULEBFormValue(uint64_t(LLONG_MAX) + 1);
EXPECT_EQ(UMax.getAsSignedConstant().getValue(), LLONG_MAX);
EXPECT_EQ(TooBig.getAsSignedConstant().hasValue(), false);
// Sanity check some other forms.
auto Data1 = createDataXFormValue<uint8_t>(DW_FORM_data1, 120);
auto Data2 = createDataXFormValue<uint16_t>(DW_FORM_data2, 32000);
auto Data4 = createDataXFormValue<uint32_t>(DW_FORM_data4, 2000000000);
auto Data8 = createDataXFormValue<uint64_t>(DW_FORM_data8, 0x1234567812345678LL);
auto LEBMin = createSLEBFormValue(LLONG_MIN);
auto LEBMax = createSLEBFormValue(LLONG_MAX);
auto LEB1 = createSLEBFormValue(-42);
auto LEB2 = createSLEBFormValue(42);
EXPECT_EQ(Data1.getAsSignedConstant().getValue(), 120);
EXPECT_EQ(Data2.getAsSignedConstant().getValue(), 32000);
EXPECT_EQ(Data4.getAsSignedConstant().getValue(), 2000000000);
EXPECT_EQ(Data8.getAsSignedConstant().getValue(), 0x1234567812345678LL);
EXPECT_EQ(LEBMin.getAsSignedConstant().getValue(), LLONG_MIN);
EXPECT_EQ(LEBMax.getAsSignedConstant().getValue(), LLONG_MAX);
EXPECT_EQ(LEB1.getAsSignedConstant().getValue(), -42);
EXPECT_EQ(LEB2.getAsSignedConstant().getValue(), 42);
// Data16 is a little tricky.
char Cksum[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
DWARFFormValue Data16(DW_FORM_data16);
DWARFDataExtractor DE16(StringRef(Cksum, 16), sys::IsLittleEndianHost,
sizeof(void *));
uint32_t Offset = 0;
Data16.extractValue(DE16, &Offset, {0, 0, dwarf::DwarfFormat::DWARF32});
SmallString<32> Str;
raw_svector_ostream Res(Str);
Data16.dump(Res, DIDumpOptions());
EXPECT_EQ(memcmp(Str.data(), "000102030405060708090a0b0c0d0e0f", 32), 0);
}
} // end anonymous namespace

View File

@ -1,269 +0,0 @@
//===--- unittests/DebugInfo/DWARF/DwarfGenerator.cpp -----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "DwarfGenerator.h"
#include "../lib/CodeGen/AsmPrinter/DwarfStringPool.h"
#include "llvm/ADT/Triple.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/DIE.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDwarf.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCTargetOptionsCommandFlags.def"
#include "llvm/PassAnalysisSupport.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
using namespace llvm;
using namespace dwarf;
namespace {} // end anonymous namespace
//===----------------------------------------------------------------------===//
/// dwarfgen::DIE implementation.
//===----------------------------------------------------------------------===//
unsigned dwarfgen::DIE::computeSizeAndOffsets(unsigned Offset) {
auto &DG = CU->getGenerator();
return Die->computeOffsetsAndAbbrevs(DG.getAsmPrinter(), DG.getAbbrevSet(),
Offset);
}
void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, uint64_t U) {
auto &DG = CU->getGenerator();
Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
DIEInteger(U));
}
void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form,
StringRef String) {
auto &DG = CU->getGenerator();
if (Form == DW_FORM_string) {
Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
new (DG.getAllocator())
DIEInlineString(String, DG.getAllocator()));
} else {
Die->addValue(
DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
DIEString(DG.getStringPool().getEntry(*DG.getAsmPrinter(), String)));
}
}
void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form,
dwarfgen::DIE &RefDie) {
auto &DG = CU->getGenerator();
Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
DIEEntry(*RefDie.Die));
}
void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form, const void *P,
size_t S) {
auto &DG = CU->getGenerator();
DIEBlock *Block = new (DG.getAllocator()) DIEBlock;
for (size_t I = 0; I < S; ++I)
Block->addValue(
DG.getAllocator(), (dwarf::Attribute)0, dwarf::DW_FORM_data1,
DIEInteger(
(const_cast<uint8_t *>(static_cast<const uint8_t *>(P)))[I]));
Block->ComputeSize(DG.getAsmPrinter());
Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
Block);
}
void dwarfgen::DIE::addAttribute(uint16_t A, dwarf::Form Form) {
auto &DG = CU->getGenerator();
assert(Form == DW_FORM_flag_present);
Die->addValue(DG.getAllocator(), static_cast<dwarf::Attribute>(A), Form,
DIEInteger(1));
}
dwarfgen::DIE dwarfgen::DIE::addChild(dwarf::Tag Tag) {
auto &DG = CU->getGenerator();
return dwarfgen::DIE(CU,
&Die->addChild(llvm::DIE::get(DG.getAllocator(), Tag)));
}
dwarfgen::DIE dwarfgen::CompileUnit::getUnitDIE() {
return dwarfgen::DIE(this, &DU.getUnitDie());
}
//===----------------------------------------------------------------------===//
/// dwarfgen::Generator implementation.
//===----------------------------------------------------------------------===//
dwarfgen::Generator::Generator()
: MAB(nullptr), MCE(nullptr), MS(nullptr), StringPool(nullptr),
Abbreviations(Allocator) {}
dwarfgen::Generator::~Generator() = default;
llvm::Expected<std::unique_ptr<dwarfgen::Generator>>
dwarfgen::Generator::create(Triple TheTriple, uint16_t DwarfVersion) {
std::unique_ptr<dwarfgen::Generator> GenUP(new dwarfgen::Generator());
llvm::Error error = GenUP->init(TheTriple, DwarfVersion);
if (error)
return Expected<std::unique_ptr<dwarfgen::Generator>>(std::move(error));
return Expected<std::unique_ptr<dwarfgen::Generator>>(std::move(GenUP));
}
llvm::Error dwarfgen::Generator::init(Triple TheTriple, uint16_t V) {
Version = V;
std::string ErrorStr;
std::string TripleName;
// Get the target.
const Target *TheTarget =
TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
if (!TheTarget)
return make_error<StringError>(ErrorStr, inconvertibleErrorCode());
TripleName = TheTriple.getTriple();
// Create all the MC Objects.
MRI.reset(TheTarget->createMCRegInfo(TripleName));
if (!MRI)
return make_error<StringError>(Twine("no register info for target ") +
TripleName,
inconvertibleErrorCode());
MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName));
if (!MAI)
return make_error<StringError>("no asm info for target " + TripleName,
inconvertibleErrorCode());
MOFI.reset(new MCObjectFileInfo);
MC.reset(new MCContext(MAI.get(), MRI.get(), MOFI.get()));
MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, *MC);
MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
if (!MSTI)
return make_error<StringError>("no subtarget info for target " + TripleName,
inconvertibleErrorCode());
MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();
MAB = TheTarget->createMCAsmBackend(*MSTI, *MRI, MCOptions);
if (!MAB)
return make_error<StringError>("no asm backend for target " + TripleName,
inconvertibleErrorCode());
MII.reset(TheTarget->createMCInstrInfo());
if (!MII)
return make_error<StringError>("no instr info info for target " +
TripleName,
inconvertibleErrorCode());
MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC);
if (!MCE)
return make_error<StringError>("no code emitter for target " + TripleName,
inconvertibleErrorCode());
Stream = make_unique<raw_svector_ostream>(FileBytes);
MS = TheTarget->createMCObjectStreamer(
TheTriple, *MC, std::unique_ptr<MCAsmBackend>(MAB), *Stream,
std::unique_ptr<MCCodeEmitter>(MCE), *MSTI, MCOptions.MCRelaxAll,
MCOptions.MCIncrementalLinkerCompatible,
/*DWARFMustBeAtTheEnd*/ false);
if (!MS)
return make_error<StringError>("no object streamer for target " +
TripleName,
inconvertibleErrorCode());
// Finally create the AsmPrinter we'll use to emit the DIEs.
TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions(),
None));
if (!TM)
return make_error<StringError>("no target machine for target " + TripleName,
inconvertibleErrorCode());
Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS)));
if (!Asm)
return make_error<StringError>("no asm printer for target " + TripleName,
inconvertibleErrorCode());
// Set the DWARF version correctly on all classes that we use.
MC->setDwarfVersion(Version);
Asm->setDwarfVersion(Version);
StringPool = llvm::make_unique<DwarfStringPool>(Allocator, *Asm, StringRef());
return Error::success();
}
StringRef dwarfgen::Generator::generate() {
// Offset from the first CU in the debug info section is 0 initially.
unsigned SecOffset = 0;
// Iterate over each compile unit and set the size and offsets for each
// DIE within each compile unit. All offsets are CU relative.
for (auto &CU : CompileUnits) {
// Set the absolute .debug_info offset for this compile unit.
CU->setOffset(SecOffset);
// The DIEs contain compile unit relative offsets.
unsigned CUOffset = 11;
CUOffset = CU->getUnitDIE().computeSizeAndOffsets(CUOffset);
// Update our absolute .debug_info offset.
SecOffset += CUOffset;
CU->setLength(CUOffset - 4);
}
Abbreviations.Emit(Asm.get(), MOFI->getDwarfAbbrevSection());
StringPool->emit(*Asm, MOFI->getDwarfStrSection());
MS->SwitchSection(MOFI->getDwarfInfoSection());
for (auto &CU : CompileUnits) {
uint16_t Version = CU->getVersion();
auto Length = CU->getLength();
MC->setDwarfVersion(Version);
assert(Length != -1U);
Asm->EmitInt32(Length);
Asm->EmitInt16(Version);
if (Version <= 4) {
Asm->EmitInt32(0);
Asm->EmitInt8(CU->getAddressSize());
} else {
Asm->EmitInt8(dwarf::DW_UT_compile);
Asm->EmitInt8(CU->getAddressSize());
Asm->EmitInt32(0);
}
Asm->emitDwarfDIE(*CU->getUnitDIE().Die);
}
MS->Finish();
if (FileBytes.empty())
return StringRef();
return StringRef(FileBytes.data(), FileBytes.size());
}
bool dwarfgen::Generator::saveFile(StringRef Path) {
if (FileBytes.empty())
return false;
std::error_code EC;
raw_fd_ostream Strm(Path, EC, sys::fs::F_None);
if (EC)
return false;
Strm.write(FileBytes.data(), FileBytes.size());
Strm.close();
return true;
}
dwarfgen::CompileUnit &dwarfgen::Generator::addCompileUnit() {
CompileUnits.push_back(std::unique_ptr<CompileUnit>(
new CompileUnit(*this, Version, Asm->getPointerSize())));
return *CompileUnits.back();
}

View File

@ -1,232 +0,0 @@
//===--- unittests/DebugInfo/DWARF/DwarfGenerator.h -------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// A file that can generate DWARF debug info for unit tests.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_UNITTESTS_DEBUG_INFO_DWARF_DWARFGENERATOR_H
#define LLVM_UNITTESTS_DEBUG_INFO_DWARF_DWARFGENERATOR_H
#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/DIE.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
#include "llvm/Support/Error.h"
#include <memory>
#include <string>
#include <tuple>
#include <vector>
namespace llvm {
class AsmPrinter;
class DIE;
class DIEAbbrev;
class DwarfStringPool;
class MCAsmBackend;
class MCAsmInfo;
class MCCodeEmitter;
class MCContext;
struct MCDwarfLineTableParams;
class MCInstrInfo;
class MCObjectFileInfo;
class MCRegisterInfo;
class MCStreamer;
class MCSubtargetInfo;
class raw_fd_ostream;
class TargetMachine;
class Triple;
namespace dwarfgen {
class Generator;
class CompileUnit;
/// A DWARF debug information entry class used to generate DWARF DIEs.
///
/// This class is used to quickly generate DWARF debug information by creating
/// child DIEs or adding attributes to the current DIE. Instances of this class
/// are created from the compile unit (dwarfgen::CompileUnit::getUnitDIE()) or
/// by calling dwarfgen::DIE::addChild(...) and using the returned DIE object.
class DIE {
dwarfgen::CompileUnit *CU;
llvm::DIE *Die;
protected:
friend class Generator;
friend class CompileUnit;
DIE(CompileUnit *U = nullptr, llvm::DIE *D = nullptr) : CU(U), Die(D) {}
/// Called with a compile/type unit relative offset prior to generating the
/// DWARF debug info.
///
/// \param CUOffset the compile/type unit relative offset where the
/// abbreviation code for this DIE will be encoded.
unsigned computeSizeAndOffsets(unsigned CUOffset);
public:
/// Add an attribute value that has no value.
///
/// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
/// represents a user defined DWARF attribute.
/// \param Form the dwarf::Form to use when encoding the attribute. This is
/// only used with the DW_FORM_flag_present form encoding.
void addAttribute(uint16_t Attr, dwarf::Form Form);
/// Add an attribute value to be encoded as a DIEInteger
///
/// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
/// represents a user defined DWARF attribute.
/// \param Form the dwarf::Form to use when encoding the attribute.
/// \param U the unsigned integer to encode.
void addAttribute(uint16_t Attr, dwarf::Form Form, uint64_t U);
/// Add an attribute value to be encoded as a DIEString or DIEInlinedString.
///
/// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
/// represents a user defined DWARF attribute.
/// \param Form the dwarf::Form to use when encoding the attribute. The form
/// must be one of DW_FORM_strp or DW_FORM_string.
/// \param String the string to encode.
void addAttribute(uint16_t Attr, dwarf::Form Form, StringRef String);
/// Add an attribute value to be encoded as a DIEEntry.
///
/// DIEEntry attributes refer to other llvm::DIE objects that have been
/// created.
///
/// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
/// represents a user defined DWARF attribute.
/// \param Form the dwarf::Form to use when encoding the attribute. The form
/// must be one of DW_FORM_strp or DW_FORM_string.
/// \param RefDie the DIE that this attriute refers to.
void addAttribute(uint16_t Attr, dwarf::Form Form, dwarfgen::DIE &RefDie);
/// Add an attribute value to be encoded as a DIEBlock.
///
/// DIEBlock attributes refers to binary data that is stored as the
/// attribute's value.
///
/// \param Attr a dwarf::Attribute enumeration value or any uint16_t that
/// represents a user defined DWARF attribute.
/// \param Form the dwarf::Form to use when encoding the attribute. The form
/// must be one of DW_FORM_strp or DW_FORM_string.
/// \param P a pointer to the data to store as the attribute value.
/// \param S the size in bytes of the data pointed to by P .
void addAttribute(uint16_t Attr, dwarf::Form Form, const void *P, size_t S);
/// Add a new child to this DIE object.
///
/// \param Tag the dwarf::Tag to assing to the llvm::DIE object.
/// \returns the newly created DIE object that is now a child owned by this
/// object.
dwarfgen::DIE addChild(dwarf::Tag Tag);
};
/// A DWARF compile unit used to generate DWARF compile/type units.
///
/// Instances of these classes are created by instances of the Generator
/// class. All information required to generate a DWARF compile unit is
/// contained inside this class.
class CompileUnit {
Generator &DG;
BasicDIEUnit DU;
public:
CompileUnit(Generator &D, uint16_t V, uint8_t A)
: DG(D), DU(V, A, dwarf::DW_TAG_compile_unit) {}
DIE getUnitDIE();
Generator &getGenerator() { return DG; }
uint64_t getOffset() const { return DU.getDebugSectionOffset(); }
uint64_t getLength() const { return DU.getLength(); }
uint16_t getVersion() const { return DU.getDwarfVersion(); }
uint16_t getAddressSize() const { return DU.getAddressSize(); }
void setOffset(uint64_t Offset) { DU.setDebugSectionOffset(Offset); }
void setLength(uint64_t Length) { DU.setLength(Length); }
};
/// A DWARF generator.
///
/// Generate DWARF for unit tests by creating any instance of this class and
/// calling Generator::addCompileUnit(), and then getting the dwarfgen::DIE from
/// the returned compile unit and adding attributes and children to each DIE.
class Generator {
std::unique_ptr<MCRegisterInfo> MRI;
std::unique_ptr<MCAsmInfo> MAI;
std::unique_ptr<MCObjectFileInfo> MOFI;
std::unique_ptr<MCContext> MC;
MCAsmBackend *MAB; // Owned by MCStreamer
std::unique_ptr<MCInstrInfo> MII;
std::unique_ptr<MCSubtargetInfo> MSTI;
MCCodeEmitter *MCE; // Owned by MCStreamer
MCStreamer *MS; // Owned by AsmPrinter
std::unique_ptr<TargetMachine> TM;
std::unique_ptr<AsmPrinter> Asm;
BumpPtrAllocator Allocator;
std::unique_ptr<DwarfStringPool> StringPool; // Entries owned by Allocator.
std::vector<std::unique_ptr<CompileUnit>> CompileUnits;
DIEAbbrevSet Abbreviations;
SmallString<4096> FileBytes;
/// The stream we use to generate the DWARF into as an ELF file.
std::unique_ptr<raw_svector_ostream> Stream;
/// The DWARF version to generate.
uint16_t Version;
/// Private constructor, call Generator::Create(...) to get a DWARF generator
/// expected.
Generator();
/// Create the streamer and setup the output buffer.
llvm::Error init(Triple TheTriple, uint16_t DwarfVersion);
public:
/// Create a DWARF generator or get an appropriate error.
///
/// \param TheTriple the triple to use when creating any required support
/// classes needed to emit the DWARF.
/// \param DwarfVersion the version of DWARF to emit.
///
/// \returns a llvm::Expected that either contains a unique_ptr to a Generator
/// or a llvm::Error.
static llvm::Expected<std::unique_ptr<Generator>>
create(Triple TheTriple, uint16_t DwarfVersion);
~Generator();
/// Generate all DWARF sections and return a memory buffer that
/// contains an ELF file that contains the DWARF.
StringRef generate();
/// Add a compile unit to be generated.
///
/// \returns a dwarfgen::CompileUnit that can be used to retrieve the compile
/// unit dwarfgen::DIE that can be used to add attributes and add child DIE
/// objedts to.
dwarfgen::CompileUnit &addCompileUnit();
BumpPtrAllocator &getAllocator() { return Allocator; }
AsmPrinter *getAsmPrinter() const { return Asm.get(); }
MCContext *getMCContext() const { return MC.get(); }
DIEAbbrevSet &getAbbrevSet() { return Abbreviations; }
DwarfStringPool &getStringPool() { return *StringPool; }
/// Save the generated DWARF file to disk.
///
/// \param Path the path to save the ELF file to.
bool saveFile(StringRef Path);
};
} // end namespace dwarfgen
} // end namespace llvm
#endif // LLVM_UNITTESTS_DEBUG_INFO_DWARF_DWARFGENERATOR_H

View File

@ -1,15 +0,0 @@
set(LLVM_LINK_COMPONENTS
DebugInfoMSF
)
set(DebugInfoMSFSources
MappedBlockStreamTest.cpp
MSFBuilderTest.cpp
MSFCommonTest.cpp
)
add_llvm_unittest(DebugInfoMSFTests
${DebugInfoMSFSources}
)
target_link_libraries(DebugInfoMSFTests PRIVATE LLVMTestingSupport)

View File

@ -1,397 +0,0 @@
//===- MSFBuilderTest.cpp Tests manipulation of MSF stream metadata ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/MSF/MSFBuilder.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
#include "llvm/Testing/Support/Error.h"
#include "gmock/gmock-matchers.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace llvm::msf;
using namespace testing;
namespace {
class MSFBuilderTest : public testing::Test {
protected:
void initializeSimpleSuperBlock(msf::SuperBlock &SB) {
initializeSuperBlock(SB);
SB.NumBlocks = 1000;
SB.NumDirectoryBytes = 8192;
}
void initializeSuperBlock(msf::SuperBlock &SB) {
::memset(&SB, 0, sizeof(SB));
::memcpy(SB.MagicBytes, msf::Magic, sizeof(msf::Magic));
SB.FreeBlockMapBlock = 1;
SB.BlockMapAddr = 1;
SB.BlockSize = 4096;
SB.NumDirectoryBytes = 0;
SB.NumBlocks = 2; // one for the Super Block, one for the directory
}
BumpPtrAllocator Allocator;
};
} // namespace
TEST_F(MSFBuilderTest, ValidateSuperBlockAccept) {
// Test that a known good super block passes validation.
SuperBlock SB;
initializeSuperBlock(SB);
EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Succeeded());
}
TEST_F(MSFBuilderTest, ValidateSuperBlockReject) {
// Test that various known problems cause a super block to be rejected.
SuperBlock SB;
initializeSimpleSuperBlock(SB);
// Mismatched magic
SB.MagicBytes[0] = 8;
EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());
initializeSimpleSuperBlock(SB);
// Block 0 is reserved for super block, can't be occupied by the block map
SB.BlockMapAddr = 0;
EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());
initializeSimpleSuperBlock(SB);
// Block sizes have to be powers of 2.
SB.BlockSize = 3120;
EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());
initializeSimpleSuperBlock(SB);
// The directory itself has a maximum size.
SB.NumDirectoryBytes = SB.BlockSize * SB.BlockSize / 4;
EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Succeeded());
SB.NumDirectoryBytes = SB.NumDirectoryBytes + 4;
EXPECT_THAT_ERROR(msf::validateSuperBlock(SB), Failed());
}
TEST_F(MSFBuilderTest, TestUsedBlocksMarkedAsUsed) {
// Test that when assigning a stream to a known list of blocks, the blocks
// are correctly marked as used after adding, but no other incorrect blocks
// are accidentally marked as used.
std::vector<uint32_t> Blocks = {4, 5, 6, 7, 8, 9, 10, 11, 12};
// Allocate some extra blocks at the end so we can verify that they're free
// after the initialization.
uint32_t NumBlocks = msf::getMinimumBlockCount() + Blocks.size() + 10;
auto ExpectedMsf = MSFBuilder::create(Allocator, 4096, NumBlocks);
ASSERT_THAT_EXPECTED(ExpectedMsf, Succeeded());
auto &Msf = *ExpectedMsf;
EXPECT_THAT_EXPECTED(Msf.addStream(Blocks.size() * 4096, Blocks),
Succeeded());
for (auto B : Blocks) {
EXPECT_FALSE(Msf.isBlockFree(B));
}
uint32_t FreeBlockStart = Blocks.back() + 1;
for (uint32_t I = FreeBlockStart; I < NumBlocks; ++I) {
EXPECT_TRUE(Msf.isBlockFree(I));
}
}
TEST_F(MSFBuilderTest, TestAddStreamNoDirectoryBlockIncrease) {
// Test that adding a new stream correctly updates the directory. This only
// tests the case where the directory *DOES NOT* grow large enough that it
// crosses a Block boundary.
auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
auto &Msf = *ExpectedMsf;
auto ExpectedL1 = Msf.build();
EXPECT_THAT_EXPECTED(ExpectedL1, Succeeded());
MSFLayout &L1 = *ExpectedL1;
auto OldDirBlocks = L1.DirectoryBlocks;
EXPECT_EQ(1U, OldDirBlocks.size());
auto ExpectedMsf2 = MSFBuilder::create(Allocator, 4096);
EXPECT_THAT_EXPECTED(ExpectedMsf2, Succeeded());
auto &Msf2 = *ExpectedMsf2;
EXPECT_THAT_EXPECTED(Msf2.addStream(4000), Succeeded());
EXPECT_EQ(1U, Msf2.getNumStreams());
EXPECT_EQ(4000U, Msf2.getStreamSize(0));
auto Blocks = Msf2.getStreamBlocks(0);
EXPECT_EQ(1U, Blocks.size());
auto ExpectedL2 = Msf2.build();
EXPECT_THAT_EXPECTED(ExpectedL2, Succeeded());
MSFLayout &L2 = *ExpectedL2;
auto NewDirBlocks = L2.DirectoryBlocks;
EXPECT_EQ(1U, NewDirBlocks.size());
}
TEST_F(MSFBuilderTest, TestAddStreamWithDirectoryBlockIncrease) {
// Test that adding a new stream correctly updates the directory. This only
// tests the case where the directory *DOES* grow large enough that it
// crosses a Block boundary. This is because the newly added stream occupies
// so many Blocks that need to be indexed in the directory that the directory
// crosses a Block boundary.
auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
auto &Msf = *ExpectedMsf;
EXPECT_THAT_EXPECTED(Msf.addStream(4096 * 4096 / sizeof(uint32_t)),
Succeeded());
auto ExpectedL1 = Msf.build();
EXPECT_THAT_EXPECTED(ExpectedL1, Succeeded());
MSFLayout &L1 = *ExpectedL1;
auto DirBlocks = L1.DirectoryBlocks;
EXPECT_EQ(2U, DirBlocks.size());
}
TEST_F(MSFBuilderTest, TestGrowStreamNoBlockIncrease) {
// Test growing an existing stream by a value that does not affect the number
// of blocks it occupies.
auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
auto &Msf = *ExpectedMsf;
EXPECT_THAT_EXPECTED(Msf.addStream(1024), Succeeded());
EXPECT_EQ(1024U, Msf.getStreamSize(0));
auto OldStreamBlocks = Msf.getStreamBlocks(0);
EXPECT_EQ(1U, OldStreamBlocks.size());
EXPECT_THAT_ERROR(Msf.setStreamSize(0, 2048), Succeeded());
EXPECT_EQ(2048U, Msf.getStreamSize(0));
auto NewStreamBlocks = Msf.getStreamBlocks(0);
EXPECT_EQ(1U, NewStreamBlocks.size());
EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
}
TEST_F(MSFBuilderTest, TestGrowStreamWithBlockIncrease) {
// Test that growing an existing stream to a value large enough that it causes
// the need to allocate new Blocks to the stream correctly updates the
// stream's
// block list.
auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
auto &Msf = *ExpectedMsf;
EXPECT_THAT_EXPECTED(Msf.addStream(2048), Succeeded());
EXPECT_EQ(2048U, Msf.getStreamSize(0));
std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
EXPECT_EQ(1U, OldStreamBlocks.size());
EXPECT_THAT_ERROR(Msf.setStreamSize(0, 6144), Succeeded());
EXPECT_EQ(6144U, Msf.getStreamSize(0));
std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
EXPECT_EQ(2U, NewStreamBlocks.size());
EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);
EXPECT_NE(NewStreamBlocks[0], NewStreamBlocks[1]);
}
TEST_F(MSFBuilderTest, TestShrinkStreamNoBlockDecrease) {
// Test that shrinking an existing stream by a value that does not affect the
// number of Blocks it occupies makes no changes to stream's block list.
auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
auto &Msf = *ExpectedMsf;
EXPECT_THAT_EXPECTED(Msf.addStream(2048), Succeeded());
EXPECT_EQ(2048U, Msf.getStreamSize(0));
std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
EXPECT_EQ(1U, OldStreamBlocks.size());
EXPECT_THAT_ERROR(Msf.setStreamSize(0, 1024), Succeeded());
EXPECT_EQ(1024U, Msf.getStreamSize(0));
std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
EXPECT_EQ(1U, NewStreamBlocks.size());
EXPECT_EQ(OldStreamBlocks, NewStreamBlocks);
}
TEST_F(MSFBuilderTest, TestShrinkStreamWithBlockDecrease) {
// Test that shrinking an existing stream to a value large enough that it
// causes the need to deallocate new Blocks to the stream correctly updates
// the stream's block list.
auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
auto &Msf = *ExpectedMsf;
EXPECT_THAT_EXPECTED(Msf.addStream(6144), Succeeded());
EXPECT_EQ(6144U, Msf.getStreamSize(0));
std::vector<uint32_t> OldStreamBlocks = Msf.getStreamBlocks(0);
EXPECT_EQ(2U, OldStreamBlocks.size());
EXPECT_THAT_ERROR(Msf.setStreamSize(0, 2048), Succeeded());
EXPECT_EQ(2048U, Msf.getStreamSize(0));
std::vector<uint32_t> NewStreamBlocks = Msf.getStreamBlocks(0);
EXPECT_EQ(1U, NewStreamBlocks.size());
EXPECT_EQ(OldStreamBlocks[0], NewStreamBlocks[0]);
}
TEST_F(MSFBuilderTest, TestRejectReusedStreamBlock) {
// Test that attempting to add a stream and assigning a block that is already
// in use by another stream fails.
auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
auto &Msf = *ExpectedMsf;
EXPECT_THAT_EXPECTED(Msf.addStream(6144), Succeeded());
std::vector<uint32_t> Blocks = {2, 3};
EXPECT_THAT_EXPECTED(Msf.addStream(6144, Blocks), Failed());
}
TEST_F(MSFBuilderTest, TestBlockCountsWhenAddingStreams) {
// Test that when adding multiple streams, the number of used and free Blocks
// allocated to the MSF file are as expected.
auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
auto &Msf = *ExpectedMsf;
// one for the super block, one for the directory block map
uint32_t NumUsedBlocks = Msf.getNumUsedBlocks();
EXPECT_EQ(msf::getMinimumBlockCount(), NumUsedBlocks);
EXPECT_EQ(0U, Msf.getNumFreeBlocks());
const uint32_t StreamSizes[] = {4000, 6193, 189723};
for (int I = 0; I < 3; ++I) {
EXPECT_THAT_EXPECTED(Msf.addStream(StreamSizes[I]), Succeeded());
NumUsedBlocks += bytesToBlocks(StreamSizes[I], 4096);
EXPECT_EQ(NumUsedBlocks, Msf.getNumUsedBlocks());
EXPECT_EQ(0U, Msf.getNumFreeBlocks());
}
}
TEST_F(MSFBuilderTest, BuildMsfLayout) {
// Test that we can generate an MSFLayout structure from a valid layout
// specification.
auto ExpectedMsf = MSFBuilder::create(Allocator, 4096);
EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
auto &Msf = *ExpectedMsf;
const uint32_t StreamSizes[] = {4000, 6193, 189723};
uint32_t ExpectedNumBlocks = msf::getMinimumBlockCount();
for (int I = 0; I < 3; ++I) {
EXPECT_THAT_EXPECTED(Msf.addStream(StreamSizes[I]), Succeeded());
ExpectedNumBlocks += bytesToBlocks(StreamSizes[I], 4096);
}
++ExpectedNumBlocks; // The directory itself should use 1 block
auto ExpectedLayout = Msf.build();
EXPECT_THAT_EXPECTED(ExpectedLayout, Succeeded());
MSFLayout &L = *ExpectedLayout;
EXPECT_EQ(4096U, L.SB->BlockSize);
EXPECT_EQ(ExpectedNumBlocks, L.SB->NumBlocks);
EXPECT_EQ(1U, L.DirectoryBlocks.size());
EXPECT_EQ(3U, L.StreamMap.size());
EXPECT_EQ(3U, L.StreamSizes.size());
for (int I = 0; I < 3; ++I) {
EXPECT_EQ(StreamSizes[I], L.StreamSizes[I]);
uint32_t ExpectedNumBlocks = bytesToBlocks(StreamSizes[I], 4096);
EXPECT_EQ(ExpectedNumBlocks, L.StreamMap[I].size());
}
}
TEST_F(MSFBuilderTest, UseDirectoryBlockHint) {
Expected<MSFBuilder> ExpectedMsf = MSFBuilder::create(
Allocator, 4096, msf::getMinimumBlockCount() + 1, false);
EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
auto &Msf = *ExpectedMsf;
uint32_t B = msf::getFirstUnreservedBlock();
EXPECT_THAT_ERROR(Msf.setDirectoryBlocksHint({B + 1}), Succeeded());
EXPECT_THAT_EXPECTED(Msf.addStream(2048, {B + 2}), Succeeded());
auto ExpectedLayout = Msf.build();
EXPECT_THAT_EXPECTED(ExpectedLayout, Succeeded());
MSFLayout &L = *ExpectedLayout;
EXPECT_EQ(msf::getMinimumBlockCount() + 2, L.SB->NumBlocks);
EXPECT_EQ(1U, L.DirectoryBlocks.size());
EXPECT_EQ(1U, L.StreamMap[0].size());
EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
EXPECT_EQ(B + 2, L.StreamMap[0].front());
}
TEST_F(MSFBuilderTest, DirectoryBlockHintInsufficient) {
Expected<MSFBuilder> ExpectedMsf =
MSFBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);
EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
auto &Msf = *ExpectedMsf;
uint32_t B = msf::getFirstUnreservedBlock();
EXPECT_THAT_ERROR(Msf.setDirectoryBlocksHint({B + 1}), Succeeded());
uint32_t Size = 4096 * 4096 / 4;
EXPECT_THAT_EXPECTED(Msf.addStream(Size), Succeeded());
auto ExpectedLayout = Msf.build();
EXPECT_THAT_EXPECTED(ExpectedLayout, Succeeded());
MSFLayout &L = *ExpectedLayout;
EXPECT_EQ(2U, L.DirectoryBlocks.size());
EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
}
TEST_F(MSFBuilderTest, DirectoryBlockHintOverestimated) {
Expected<MSFBuilder> ExpectedMsf =
MSFBuilder::create(Allocator, 4096, msf::getMinimumBlockCount() + 2);
EXPECT_THAT_EXPECTED(ExpectedMsf, Succeeded());
auto &Msf = *ExpectedMsf;
uint32_t B = msf::getFirstUnreservedBlock();
EXPECT_THAT_ERROR(Msf.setDirectoryBlocksHint({B + 1, B + 2}), Succeeded());
ASSERT_THAT_EXPECTED(Msf.addStream(2048), Succeeded());
auto ExpectedLayout = Msf.build();
ASSERT_THAT_EXPECTED(ExpectedLayout, Succeeded());
MSFLayout &L = *ExpectedLayout;
EXPECT_EQ(1U, L.DirectoryBlocks.size());
EXPECT_EQ(B + 1, L.DirectoryBlocks[0]);
}
TEST_F(MSFBuilderTest, StreamDoesntUseFpmBlocks) {
Expected<MSFBuilder> ExpectedMsf = MSFBuilder::create(Allocator, 4096);
ASSERT_THAT_EXPECTED(ExpectedMsf, Succeeded());
auto &Msf = *ExpectedMsf;
// A block is 4096 bytes, and every 4096 blocks we have 2 reserved FPM blocks.
// By creating add a stream that spans 4096*4096*3 bytes, we ensure that we
// cross over a couple of reserved FPM blocks, and that none of them are
// allocated to the stream.
constexpr uint32_t StreamSize = 4096 * 4096 * 3;
Expected<uint32_t> SN = Msf.addStream(StreamSize);
ASSERT_THAT_EXPECTED(SN, Succeeded());
auto ExpectedLayout = Msf.build();
ASSERT_THAT_EXPECTED(ExpectedLayout, Succeeded());
MSFLayout &L = *ExpectedLayout;
auto BlocksRef = L.StreamMap[*SN];
std::vector<uint32_t> Blocks(BlocksRef.begin(), BlocksRef.end());
EXPECT_EQ(StreamSize, L.StreamSizes[*SN]);
for (uint32_t I = 0; I <= 3; ++I) {
// Pages from the regular FPM are allocated, while pages from the alt fpm
// are free.
EXPECT_FALSE(L.FreePageMap.test(1 + I * 4096));
EXPECT_TRUE(L.FreePageMap.test(2 + I * 4096));
}
for (uint32_t I = 1; I <= 3; ++I) {
EXPECT_THAT(Blocks, Not(Contains(1 + I * 4096)));
EXPECT_THAT(Blocks, Not(Contains(2 + I * 4096)));
}
}

View File

@ -1,104 +0,0 @@
//===- MSFBuilderTest.cpp Tests manipulation of MSF stream metadata ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/MSF/MSFCommon.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace llvm::msf;
TEST(MSFCommonTest, BytesToBlocks) {
EXPECT_EQ(0ULL, bytesToBlocks(0, 4096));
EXPECT_EQ(1ULL, bytesToBlocks(12, 4096));
EXPECT_EQ(1ULL, bytesToBlocks(4096, 4096));
EXPECT_EQ(2ULL, bytesToBlocks(4097, 4096));
EXPECT_EQ(2ULL, bytesToBlocks(600, 512));
}
TEST(MSFCommonTest, FpmIntervals) {
SuperBlock SB;
SB.FreeBlockMapBlock = 1;
SB.BlockSize = 4096;
MSFLayout L;
L.SB = &SB;
SB.NumBlocks = 12;
EXPECT_EQ(1u, getNumFpmIntervals(L, false));
SB.NumBlocks = SB.BlockSize;
EXPECT_EQ(1u, getNumFpmIntervals(L, false));
SB.NumBlocks = SB.BlockSize + 1;
EXPECT_EQ(1u, getNumFpmIntervals(L, false));
SB.NumBlocks = SB.BlockSize * 8;
EXPECT_EQ(1u, getNumFpmIntervals(L, false));
SB.NumBlocks = SB.BlockSize * 8 + 1;
EXPECT_EQ(2u, getNumFpmIntervals(L, false));
SB.NumBlocks = 12;
EXPECT_EQ(1u, getNumFpmIntervals(L, true));
SB.NumBlocks = SB.BlockSize;
EXPECT_EQ(1u, getNumFpmIntervals(L, true));
SB.NumBlocks = SB.BlockSize + 1;
EXPECT_EQ(2u, getNumFpmIntervals(L, true));
SB.NumBlocks = SB.BlockSize * 8;
EXPECT_EQ(8u, getNumFpmIntervals(L, true));
SB.NumBlocks = SB.BlockSize * 8 + 1;
EXPECT_EQ(9u, getNumFpmIntervals(L, true));
}
TEST(MSFCommonTest, FpmStreamLayout) {
SuperBlock SB;
MSFLayout L;
L.SB = &SB;
SB.FreeBlockMapBlock = 1;
// Each FPM block has 4096 bytes for a maximum of 4096*8 allocation states.
SB.BlockSize = 4096;
// 1. When we're not including unused FPM data, the length of the FPM stream
// should be only long enough to contain 1 bit for each block.
// 1a. When the PDB has <= 4096*8 blocks, there should only be one FPM block.
SB.NumBlocks = 8000;
MSFStreamLayout SL = getFpmStreamLayout(L, false, false);
EXPECT_EQ(1000u, SL.Length);
EXPECT_EQ(1u, SL.Blocks.size());
EXPECT_EQ(SB.FreeBlockMapBlock, SL.Blocks.front());
SL = getFpmStreamLayout(L, false, true);
EXPECT_EQ(1000u, SL.Length);
EXPECT_EQ(1u, SL.Blocks.size());
EXPECT_EQ(3u - SB.FreeBlockMapBlock, SL.Blocks.front());
// 1b. When the PDB has > 4096*8 blocks, there should be multiple FPM blocks.
SB.NumBlocks = SB.BlockSize * 8 + 1;
SL = getFpmStreamLayout(L, false, false);
EXPECT_EQ(SB.BlockSize + 1, SL.Length);
EXPECT_EQ(2u, SL.Blocks.size());
EXPECT_EQ(SB.FreeBlockMapBlock, SL.Blocks[0]);
EXPECT_EQ(SB.FreeBlockMapBlock + SB.BlockSize, SL.Blocks[1]);
SL = getFpmStreamLayout(L, false, true);
EXPECT_EQ(SB.BlockSize + 1, SL.Length);
EXPECT_EQ(2u, SL.Blocks.size());
EXPECT_EQ(3u - SB.FreeBlockMapBlock, SL.Blocks[0]);
EXPECT_EQ(3u - SB.FreeBlockMapBlock + SB.BlockSize, SL.Blocks[1]);
// 2. When we are including unused FPM data, there should be one FPM block
// at every BlockSize interval in the file, even if entire FPM blocks are
// unused.
SB.NumBlocks = SB.BlockSize * 8 + 1;
SL = getFpmStreamLayout(L, true, false);
EXPECT_EQ(SB.BlockSize * 9, SL.Length);
EXPECT_EQ(9u, SL.Blocks.size());
for (int I = 0; I < 9; ++I)
EXPECT_EQ(I * SB.BlockSize + SB.FreeBlockMapBlock, SL.Blocks[I]);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +0,0 @@
set(LLVM_LINK_COMPONENTS
DebugInfoCodeView
DebugInfoMSF
DebugInfoPDB
)
set(DebugInfoPDBSources
HashTableTest.cpp
StringTableBuilderTest.cpp
PDBApiTest.cpp
)
add_llvm_unittest(DebugInfoPDBTests
${DebugInfoPDBSources}
)
target_link_libraries(DebugInfoPDBTests PRIVATE LLVMTestingSupport)

View File

@ -1,168 +0,0 @@
//===- llvm/unittest/DebugInfo/PDB/HashTableTest.cpp ----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/PDB/Native/HashTable.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
#include <vector>
using namespace llvm;
using namespace llvm::pdb;
using namespace llvm::support;
namespace {
class HashTableInternals : public HashTable {
public:
using HashTable::Buckets;
using HashTable::Present;
using HashTable::Deleted;
};
}
TEST(HashTableTest, TestSimple) {
HashTable Table;
EXPECT_EQ(0u, Table.size());
EXPECT_GT(Table.capacity(), 0u);
Table.set(3, 7);
EXPECT_EQ(1u, Table.size());
ASSERT_NE(Table.end(), Table.find(3));
EXPECT_EQ(7u, Table.get(3));
}
TEST(HashTableTest, TestCollision) {
HashTable Table;
EXPECT_EQ(0u, Table.size());
EXPECT_GT(Table.capacity(), 0u);
// We use knowledge of the hash table's implementation details to make sure
// to add another value that is the equivalent to the first value modulo the
// hash table's capacity.
uint32_t N1 = Table.capacity() + 1;
uint32_t N2 = 2 * N1;
Table.set(N1, 7);
Table.set(N2, 12);
EXPECT_EQ(2u, Table.size());
ASSERT_NE(Table.end(), Table.find(N1));
ASSERT_NE(Table.end(), Table.find(N2));
EXPECT_EQ(7u, Table.get(N1));
EXPECT_EQ(12u, Table.get(N2));
}
TEST(HashTableTest, TestRemove) {
HashTable Table;
EXPECT_EQ(0u, Table.size());
EXPECT_GT(Table.capacity(), 0u);
Table.set(1, 2);
Table.set(3, 4);
EXPECT_EQ(2u, Table.size());
ASSERT_NE(Table.end(), Table.find(1));
ASSERT_NE(Table.end(), Table.find(3));
EXPECT_EQ(2u, Table.get(1));
EXPECT_EQ(4u, Table.get(3));
Table.remove(1u);
EXPECT_EQ(1u, Table.size());
EXPECT_EQ(Table.end(), Table.find(1));
ASSERT_NE(Table.end(), Table.find(3));
EXPECT_EQ(4u, Table.get(3));
}
TEST(HashTableTest, TestCollisionAfterMultipleProbes) {
HashTable Table;
EXPECT_EQ(0u, Table.size());
EXPECT_GT(Table.capacity(), 0u);
// Probing looks for the first available slot. A slot may already be filled
// as a result of an item with a *different* hash value already being there.
// Test that when this happens, the probe still finds the value.
uint32_t N1 = Table.capacity() + 1;
uint32_t N2 = N1 + 1;
uint32_t N3 = 2 * N1;
Table.set(N1, 7);
Table.set(N2, 11);
Table.set(N3, 13);
EXPECT_EQ(3u, Table.size());
ASSERT_NE(Table.end(), Table.find(N1));
ASSERT_NE(Table.end(), Table.find(N2));
ASSERT_NE(Table.end(), Table.find(N3));
EXPECT_EQ(7u, Table.get(N1));
EXPECT_EQ(11u, Table.get(N2));
EXPECT_EQ(13u, Table.get(N3));
// Remove the one that had been filled in the middle, then insert another one
// with a collision. It should fill the newly emptied slot.
Table.remove(N2);
uint32_t N4 = N1 * 3;
Table.set(N4, 17);
EXPECT_EQ(3u, Table.size());
ASSERT_NE(Table.end(), Table.find(N1));
ASSERT_NE(Table.end(), Table.find(N3));
ASSERT_NE(Table.end(), Table.find(N4));
EXPECT_EQ(7u, Table.get(N1));
EXPECT_EQ(13u, Table.get(N3));
EXPECT_EQ(17u, Table.get(N4));
}
TEST(HashTableTest, Grow) {
// So that we are independent of the load factor, `capacity` items, which is
// guaranteed to trigger a grow. Then verify that the size is the same, the
// capacity is larger, and all the original items are still in the table.
HashTable Table;
uint32_t OldCapacity = Table.capacity();
for (uint32_t I = 0; I < OldCapacity; ++I) {
Table.set(OldCapacity + I * 2 + 1, I * 2 + 3);
}
EXPECT_EQ(OldCapacity, Table.size());
EXPECT_GT(Table.capacity(), OldCapacity);
for (uint32_t I = 0; I < OldCapacity; ++I) {
ASSERT_NE(Table.end(), Table.find(OldCapacity + I * 2 + 1));
EXPECT_EQ(I * 2 + 3, Table.get(OldCapacity + I * 2 + 1));
}
}
TEST(HashTableTest, Serialization) {
HashTableInternals Table;
uint32_t Cap = Table.capacity();
for (uint32_t I = 0; I < Cap; ++I) {
Table.set(Cap + I * 2 + 1, I * 2 + 3);
}
std::vector<uint8_t> Buffer(Table.calculateSerializedLength());
MutableBinaryByteStream Stream(Buffer, little);
BinaryStreamWriter Writer(Stream);
EXPECT_THAT_ERROR(Table.commit(Writer), Succeeded());
// We should have written precisely the number of bytes we calculated earlier.
EXPECT_EQ(Buffer.size(), Writer.getOffset());
HashTableInternals Table2;
BinaryStreamReader Reader(Stream);
EXPECT_THAT_ERROR(Table2.load(Reader), Succeeded());
// We should have read precisely the number of bytes we calculated earlier.
EXPECT_EQ(Buffer.size(), Reader.getOffset());
EXPECT_EQ(Table.size(), Table2.size());
EXPECT_EQ(Table.capacity(), Table2.capacity());
EXPECT_EQ(Table.Buckets, Table2.Buckets);
EXPECT_EQ(Table.Present, Table2.Present);
EXPECT_EQ(Table.Deleted, Table2.Deleted);
}

View File

@ -1,432 +0,0 @@
//===- llvm/unittest/DebugInfo/PDB/PDBApiTest.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/ADT/STLExtras.h"
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
#include "llvm/DebugInfo/PDB/IPDBSession.h"
#include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
#include "llvm/DebugInfo/PDB/IPDBTable.h"
#include "llvm/DebugInfo/PDB/PDBSymbol.h"
#include "llvm/DebugInfo/PDB/PDBSymbolAnnotation.h"
#include "llvm/DebugInfo/PDB/PDBSymbolBlock.h"
#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h"
#include "llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h"
#include "llvm/DebugInfo/PDB/PDBSymbolCustom.h"
#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h"
#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h"
#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h"
#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h"
#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h"
#include "llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h"
#include "llvm/DebugInfo/PDB/PDBTypes.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace llvm::pdb;
namespace {
#define MOCK_SYMBOL_ACCESSOR(Func) \
decltype(std::declval<IPDBRawSymbol>().Func()) Func() const override { \
typedef decltype(IPDBRawSymbol::Func()) ReturnType; \
return ReturnType(); \
}
class MockSession : public IPDBSession {
uint64_t getLoadAddress() const override { return 0; }
void setLoadAddress(uint64_t Address) override {}
std::unique_ptr<PDBSymbolExe> getGlobalScope() override { return nullptr; }
std::unique_ptr<PDBSymbol> getSymbolById(uint32_t SymbolId) const override {
return nullptr;
}
std::unique_ptr<IPDBSourceFile>
getSourceFileById(uint32_t SymbolId) const override {
return nullptr;
}
std::unique_ptr<PDBSymbol>
findSymbolByAddress(uint64_t Address, PDB_SymType Type) const override {
return nullptr;
}
std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbers(const PDBSymbolCompiland &Compiland,
const IPDBSourceFile &File) const override {
return nullptr;
}
std::unique_ptr<IPDBEnumLineNumbers>
findLineNumbersByAddress(uint64_t Address, uint32_t Length) const override {
return nullptr;
}
std::unique_ptr<IPDBEnumSourceFiles>
findSourceFiles(const PDBSymbolCompiland *Compiland, llvm::StringRef Pattern,
PDB_NameSearchFlags Flags) const override {
return nullptr;
}
std::unique_ptr<IPDBSourceFile>
findOneSourceFile(const PDBSymbolCompiland *Compiland,
llvm::StringRef Pattern,
PDB_NameSearchFlags Flags) const override {
return nullptr;
}
std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
findCompilandsForSourceFile(llvm::StringRef Pattern,
PDB_NameSearchFlags Flags) const override {
return nullptr;
}
std::unique_ptr<PDBSymbolCompiland>
findOneCompilandForSourceFile(llvm::StringRef Pattern,
PDB_NameSearchFlags Flags) const override {
return nullptr;
}
std::unique_ptr<IPDBEnumSourceFiles> getAllSourceFiles() const override {
return nullptr;
}
std::unique_ptr<IPDBEnumSourceFiles> getSourceFilesForCompiland(
const PDBSymbolCompiland &Compiland) const override {
return nullptr;
}
std::unique_ptr<IPDBEnumDataStreams> getDebugStreams() const override {
return nullptr;
}
std::unique_ptr<IPDBEnumTables> getEnumTables() const override {
return nullptr;
}
};
class MockRawSymbol : public IPDBRawSymbol {
public:
MockRawSymbol(PDB_SymType SymType)
: Type(SymType) {}
void dump(raw_ostream &OS, int Indent) const override {}
std::unique_ptr<IPDBEnumSymbols>
findChildren(PDB_SymType Type) const override {
return nullptr;
}
std::unique_ptr<IPDBEnumSymbols>
findChildren(PDB_SymType Type, StringRef Name,
PDB_NameSearchFlags Flags) const override {
return nullptr;
}
std::unique_ptr<IPDBEnumSymbols>
findChildrenByRVA(PDB_SymType Type, StringRef Name, PDB_NameSearchFlags Flags,
uint32_t RVA) const override {
return nullptr;
}
std::unique_ptr<IPDBEnumSymbols>
findInlineFramesByRVA(uint32_t RVA) const override {
return nullptr;
}
void getDataBytes(llvm::SmallVector<uint8_t, 32> &bytes) const override {}
void getFrontEndVersion(VersionInfo &Version) const override {}
void getBackEndVersion(VersionInfo &Version) const override {}
PDB_SymType getSymTag() const override { return Type; }
std::string getUndecoratedNameEx(PDB_UndnameFlags Flags) const override {
return {};
}
MOCK_SYMBOL_ACCESSOR(getAccess)
MOCK_SYMBOL_ACCESSOR(getAddressOffset)
MOCK_SYMBOL_ACCESSOR(getAddressSection)
MOCK_SYMBOL_ACCESSOR(getAge)
MOCK_SYMBOL_ACCESSOR(getArrayIndexTypeId)
MOCK_SYMBOL_ACCESSOR(getBaseDataOffset)
MOCK_SYMBOL_ACCESSOR(getBaseDataSlot)
MOCK_SYMBOL_ACCESSOR(getBaseSymbolId)
MOCK_SYMBOL_ACCESSOR(getBuiltinType)
MOCK_SYMBOL_ACCESSOR(getBitPosition)
MOCK_SYMBOL_ACCESSOR(getCallingConvention)
MOCK_SYMBOL_ACCESSOR(getClassParentId)
MOCK_SYMBOL_ACCESSOR(getCompilerName)
MOCK_SYMBOL_ACCESSOR(getCount)
MOCK_SYMBOL_ACCESSOR(getCountLiveRanges)
MOCK_SYMBOL_ACCESSOR(getLanguage)
MOCK_SYMBOL_ACCESSOR(getLexicalParentId)
MOCK_SYMBOL_ACCESSOR(getLibraryName)
MOCK_SYMBOL_ACCESSOR(getLiveRangeStartAddressOffset)
MOCK_SYMBOL_ACCESSOR(getLiveRangeStartAddressSection)
MOCK_SYMBOL_ACCESSOR(getLiveRangeStartRelativeVirtualAddress)
MOCK_SYMBOL_ACCESSOR(getLocalBasePointerRegisterId)
MOCK_SYMBOL_ACCESSOR(getLowerBoundId)
MOCK_SYMBOL_ACCESSOR(getMemorySpaceKind)
MOCK_SYMBOL_ACCESSOR(getName)
MOCK_SYMBOL_ACCESSOR(getNumberOfAcceleratorPointerTags)
MOCK_SYMBOL_ACCESSOR(getNumberOfColumns)
MOCK_SYMBOL_ACCESSOR(getNumberOfModifiers)
MOCK_SYMBOL_ACCESSOR(getNumberOfRegisterIndices)
MOCK_SYMBOL_ACCESSOR(getNumberOfRows)
MOCK_SYMBOL_ACCESSOR(getObjectFileName)
MOCK_SYMBOL_ACCESSOR(getOemId)
MOCK_SYMBOL_ACCESSOR(getOemSymbolId)
MOCK_SYMBOL_ACCESSOR(getOffsetInUdt)
MOCK_SYMBOL_ACCESSOR(getPlatform)
MOCK_SYMBOL_ACCESSOR(getRank)
MOCK_SYMBOL_ACCESSOR(getRegisterId)
MOCK_SYMBOL_ACCESSOR(getRegisterType)
MOCK_SYMBOL_ACCESSOR(getRelativeVirtualAddress)
MOCK_SYMBOL_ACCESSOR(getSamplerSlot)
MOCK_SYMBOL_ACCESSOR(getSignature)
MOCK_SYMBOL_ACCESSOR(getSizeInUdt)
MOCK_SYMBOL_ACCESSOR(getSlot)
MOCK_SYMBOL_ACCESSOR(getSourceFileName)
MOCK_SYMBOL_ACCESSOR(getStride)
MOCK_SYMBOL_ACCESSOR(getSubTypeId)
MOCK_SYMBOL_ACCESSOR(getSymbolsFileName)
MOCK_SYMBOL_ACCESSOR(getSymIndexId)
MOCK_SYMBOL_ACCESSOR(getTargetOffset)
MOCK_SYMBOL_ACCESSOR(getTargetRelativeVirtualAddress)
MOCK_SYMBOL_ACCESSOR(getTargetVirtualAddress)
MOCK_SYMBOL_ACCESSOR(getTargetSection)
MOCK_SYMBOL_ACCESSOR(getTextureSlot)
MOCK_SYMBOL_ACCESSOR(getTimeStamp)
MOCK_SYMBOL_ACCESSOR(getToken)
MOCK_SYMBOL_ACCESSOR(getTypeId)
MOCK_SYMBOL_ACCESSOR(getUavSlot)
MOCK_SYMBOL_ACCESSOR(getUndecoratedName)
MOCK_SYMBOL_ACCESSOR(getUnmodifiedTypeId)
MOCK_SYMBOL_ACCESSOR(getUpperBoundId)
MOCK_SYMBOL_ACCESSOR(getVirtualBaseDispIndex)
MOCK_SYMBOL_ACCESSOR(getVirtualBaseOffset)
MOCK_SYMBOL_ACCESSOR(getVirtualTableShapeId)
MOCK_SYMBOL_ACCESSOR(getDataKind)
MOCK_SYMBOL_ACCESSOR(getGuid)
MOCK_SYMBOL_ACCESSOR(getOffset)
MOCK_SYMBOL_ACCESSOR(getThisAdjust)
MOCK_SYMBOL_ACCESSOR(getVirtualBasePointerOffset)
MOCK_SYMBOL_ACCESSOR(getLocationType)
MOCK_SYMBOL_ACCESSOR(getMachineType)
MOCK_SYMBOL_ACCESSOR(getThunkOrdinal)
MOCK_SYMBOL_ACCESSOR(getLength)
MOCK_SYMBOL_ACCESSOR(getVirtualBaseTableType)
MOCK_SYMBOL_ACCESSOR(getLiveRangeLength)
MOCK_SYMBOL_ACCESSOR(getVirtualAddress)
MOCK_SYMBOL_ACCESSOR(getUdtKind)
MOCK_SYMBOL_ACCESSOR(hasConstructor)
MOCK_SYMBOL_ACCESSOR(hasCustomCallingConvention)
MOCK_SYMBOL_ACCESSOR(hasFarReturn)
MOCK_SYMBOL_ACCESSOR(isCode)
MOCK_SYMBOL_ACCESSOR(isCompilerGenerated)
MOCK_SYMBOL_ACCESSOR(isConstType)
MOCK_SYMBOL_ACCESSOR(isEditAndContinueEnabled)
MOCK_SYMBOL_ACCESSOR(isFunction)
MOCK_SYMBOL_ACCESSOR(getAddressTaken)
MOCK_SYMBOL_ACCESSOR(getNoStackOrdering)
MOCK_SYMBOL_ACCESSOR(hasAlloca)
MOCK_SYMBOL_ACCESSOR(hasAssignmentOperator)
MOCK_SYMBOL_ACCESSOR(hasCTypes)
MOCK_SYMBOL_ACCESSOR(hasCastOperator)
MOCK_SYMBOL_ACCESSOR(hasDebugInfo)
MOCK_SYMBOL_ACCESSOR(hasEH)
MOCK_SYMBOL_ACCESSOR(hasEHa)
MOCK_SYMBOL_ACCESSOR(hasFramePointer)
MOCK_SYMBOL_ACCESSOR(hasInlAsm)
MOCK_SYMBOL_ACCESSOR(hasInlineAttribute)
MOCK_SYMBOL_ACCESSOR(hasInterruptReturn)
MOCK_SYMBOL_ACCESSOR(hasLongJump)
MOCK_SYMBOL_ACCESSOR(hasManagedCode)
MOCK_SYMBOL_ACCESSOR(hasNestedTypes)
MOCK_SYMBOL_ACCESSOR(hasNoInlineAttribute)
MOCK_SYMBOL_ACCESSOR(hasNoReturnAttribute)
MOCK_SYMBOL_ACCESSOR(hasOptimizedCodeDebugInfo)
MOCK_SYMBOL_ACCESSOR(hasOverloadedOperator)
MOCK_SYMBOL_ACCESSOR(hasSEH)
MOCK_SYMBOL_ACCESSOR(hasSecurityChecks)
MOCK_SYMBOL_ACCESSOR(hasSetJump)
MOCK_SYMBOL_ACCESSOR(hasStrictGSCheck)
MOCK_SYMBOL_ACCESSOR(isAcceleratorGroupSharedLocal)
MOCK_SYMBOL_ACCESSOR(isAcceleratorPointerTagLiveRange)
MOCK_SYMBOL_ACCESSOR(isAcceleratorStubFunction)
MOCK_SYMBOL_ACCESSOR(isAggregated)
MOCK_SYMBOL_ACCESSOR(isIntroVirtualFunction)
MOCK_SYMBOL_ACCESSOR(isCVTCIL)
MOCK_SYMBOL_ACCESSOR(isConstructorVirtualBase)
MOCK_SYMBOL_ACCESSOR(isCxxReturnUdt)
MOCK_SYMBOL_ACCESSOR(isDataAligned)
MOCK_SYMBOL_ACCESSOR(isHLSLData)
MOCK_SYMBOL_ACCESSOR(isHotpatchable)
MOCK_SYMBOL_ACCESSOR(isIndirectVirtualBaseClass)
MOCK_SYMBOL_ACCESSOR(isInterfaceUdt)
MOCK_SYMBOL_ACCESSOR(isIntrinsic)
MOCK_SYMBOL_ACCESSOR(isLTCG)
MOCK_SYMBOL_ACCESSOR(isLocationControlFlowDependent)
MOCK_SYMBOL_ACCESSOR(isMSILNetmodule)
MOCK_SYMBOL_ACCESSOR(isMatrixRowMajor)
MOCK_SYMBOL_ACCESSOR(isManagedCode)
MOCK_SYMBOL_ACCESSOR(isMSILCode)
MOCK_SYMBOL_ACCESSOR(isMultipleInheritance)
MOCK_SYMBOL_ACCESSOR(isNaked)
MOCK_SYMBOL_ACCESSOR(isNested)
MOCK_SYMBOL_ACCESSOR(isOptimizedAway)
MOCK_SYMBOL_ACCESSOR(isPacked)
MOCK_SYMBOL_ACCESSOR(isPointerBasedOnSymbolValue)
MOCK_SYMBOL_ACCESSOR(isPointerToDataMember)
MOCK_SYMBOL_ACCESSOR(isPointerToMemberFunction)
MOCK_SYMBOL_ACCESSOR(isPureVirtual)
MOCK_SYMBOL_ACCESSOR(isRValueReference)
MOCK_SYMBOL_ACCESSOR(isRefUdt)
MOCK_SYMBOL_ACCESSOR(isReference)
MOCK_SYMBOL_ACCESSOR(isRestrictedType)
MOCK_SYMBOL_ACCESSOR(isReturnValue)
MOCK_SYMBOL_ACCESSOR(isSafeBuffers)
MOCK_SYMBOL_ACCESSOR(isScoped)
MOCK_SYMBOL_ACCESSOR(isSdl)
MOCK_SYMBOL_ACCESSOR(isSingleInheritance)
MOCK_SYMBOL_ACCESSOR(isSplitted)
MOCK_SYMBOL_ACCESSOR(isStatic)
MOCK_SYMBOL_ACCESSOR(hasPrivateSymbols)
MOCK_SYMBOL_ACCESSOR(isUnalignedType)
MOCK_SYMBOL_ACCESSOR(isUnreached)
MOCK_SYMBOL_ACCESSOR(isValueUdt)
MOCK_SYMBOL_ACCESSOR(isVirtual)
MOCK_SYMBOL_ACCESSOR(isVirtualBaseClass)
MOCK_SYMBOL_ACCESSOR(isVirtualInheritance)
MOCK_SYMBOL_ACCESSOR(isVolatileType)
MOCK_SYMBOL_ACCESSOR(getValue)
MOCK_SYMBOL_ACCESSOR(wasInlined)
MOCK_SYMBOL_ACCESSOR(getUnused)
private:
PDB_SymType Type;
};
class PDBApiTest : public testing::Test {
public:
std::unordered_map<PDB_SymType, std::unique_ptr<PDBSymbol>> SymbolMap;
void SetUp() override {
Session.reset(new MockSession());
InsertItemWithTag(PDB_SymType::None);
InsertItemWithTag(PDB_SymType::Exe);
InsertItemWithTag(PDB_SymType::Compiland);
InsertItemWithTag(PDB_SymType::CompilandDetails);
InsertItemWithTag(PDB_SymType::CompilandEnv);
InsertItemWithTag(PDB_SymType::Function);
InsertItemWithTag(PDB_SymType::Block);
InsertItemWithTag(PDB_SymType::Data);
InsertItemWithTag(PDB_SymType::Annotation);
InsertItemWithTag(PDB_SymType::Label);
InsertItemWithTag(PDB_SymType::PublicSymbol);
InsertItemWithTag(PDB_SymType::UDT);
InsertItemWithTag(PDB_SymType::Enum);
InsertItemWithTag(PDB_SymType::FunctionSig);
InsertItemWithTag(PDB_SymType::PointerType);
InsertItemWithTag(PDB_SymType::ArrayType);
InsertItemWithTag(PDB_SymType::BuiltinType);
InsertItemWithTag(PDB_SymType::Typedef);
InsertItemWithTag(PDB_SymType::BaseClass);
InsertItemWithTag(PDB_SymType::Friend);
InsertItemWithTag(PDB_SymType::FunctionArg);
InsertItemWithTag(PDB_SymType::FuncDebugStart);
InsertItemWithTag(PDB_SymType::FuncDebugEnd);
InsertItemWithTag(PDB_SymType::UsingNamespace);
InsertItemWithTag(PDB_SymType::VTableShape);
InsertItemWithTag(PDB_SymType::VTable);
InsertItemWithTag(PDB_SymType::Custom);
InsertItemWithTag(PDB_SymType::Thunk);
InsertItemWithTag(PDB_SymType::CustomType);
InsertItemWithTag(PDB_SymType::ManagedType);
InsertItemWithTag(PDB_SymType::Dimension);
InsertItemWithTag(PDB_SymType::Max);
}
template <class ExpectedType> void VerifyDyncast(PDB_SymType Tag) {
for (auto item = SymbolMap.begin(); item != SymbolMap.end(); ++item) {
EXPECT_EQ(item->first == Tag, llvm::isa<ExpectedType>(*item->second));
}
}
void VerifyUnknownDyncasts() {
for (auto item = SymbolMap.begin(); item != SymbolMap.end(); ++item) {
bool should_match = false;
if (item->first == PDB_SymType::None || item->first >= PDB_SymType::Max)
should_match = true;
EXPECT_EQ(should_match, llvm::isa<PDBSymbolUnknown>(*item->second));
}
}
private:
std::unique_ptr<IPDBSession> Session;
void InsertItemWithTag(PDB_SymType Tag) {
auto RawSymbol = llvm::make_unique<MockRawSymbol>(Tag);
auto Symbol = PDBSymbol::create(*Session, std::move(RawSymbol));
SymbolMap.insert(std::make_pair(Tag, std::move(Symbol)));
}
};
TEST_F(PDBApiTest, Dyncast) {
// Most of the types have a one-to-one mapping between Tag and concrete type.
VerifyDyncast<PDBSymbolExe>(PDB_SymType::Exe);
VerifyDyncast<PDBSymbolCompiland>(PDB_SymType::Compiland);
VerifyDyncast<PDBSymbolCompilandDetails>(PDB_SymType::CompilandDetails);
VerifyDyncast<PDBSymbolCompilandEnv>(PDB_SymType::CompilandEnv);
VerifyDyncast<PDBSymbolFunc>(PDB_SymType::Function);
VerifyDyncast<PDBSymbolBlock>(PDB_SymType::Block);
VerifyDyncast<PDBSymbolData>(PDB_SymType::Data);
VerifyDyncast<PDBSymbolAnnotation>(PDB_SymType::Annotation);
VerifyDyncast<PDBSymbolLabel>(PDB_SymType::Label);
VerifyDyncast<PDBSymbolPublicSymbol>(PDB_SymType::PublicSymbol);
VerifyDyncast<PDBSymbolTypeUDT>(PDB_SymType::UDT);
VerifyDyncast<PDBSymbolTypeEnum>(PDB_SymType::Enum);
VerifyDyncast<PDBSymbolTypeFunctionSig>(PDB_SymType::FunctionSig);
VerifyDyncast<PDBSymbolTypePointer>(PDB_SymType::PointerType);
VerifyDyncast<PDBSymbolTypeArray>(PDB_SymType::ArrayType);
VerifyDyncast<PDBSymbolTypeBuiltin>(PDB_SymType::BuiltinType);
VerifyDyncast<PDBSymbolTypeTypedef>(PDB_SymType::Typedef);
VerifyDyncast<PDBSymbolTypeBaseClass>(PDB_SymType::BaseClass);
VerifyDyncast<PDBSymbolTypeFriend>(PDB_SymType::Friend);
VerifyDyncast<PDBSymbolTypeFunctionArg>(PDB_SymType::FunctionArg);
VerifyDyncast<PDBSymbolFuncDebugStart>(PDB_SymType::FuncDebugStart);
VerifyDyncast<PDBSymbolFuncDebugEnd>(PDB_SymType::FuncDebugEnd);
VerifyDyncast<PDBSymbolUsingNamespace>(PDB_SymType::UsingNamespace);
VerifyDyncast<PDBSymbolTypeVTableShape>(PDB_SymType::VTableShape);
VerifyDyncast<PDBSymbolTypeVTable>(PDB_SymType::VTable);
VerifyDyncast<PDBSymbolCustom>(PDB_SymType::Custom);
VerifyDyncast<PDBSymbolThunk>(PDB_SymType::Thunk);
VerifyDyncast<PDBSymbolTypeCustom>(PDB_SymType::CustomType);
VerifyDyncast<PDBSymbolTypeManaged>(PDB_SymType::ManagedType);
VerifyDyncast<PDBSymbolTypeDimension>(PDB_SymType::Dimension);
VerifyUnknownDyncasts();
}
} // end anonymous namespace

View File

@ -1,55 +0,0 @@
//===- StringTableBuilderTest.cpp -----------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace llvm::pdb;
using namespace llvm::support;
namespace {
class StringTableBuilderTest : public ::testing::Test {};
}
TEST_F(StringTableBuilderTest, Simple) {
// Create /names table contents.
PDBStringTableBuilder Builder;
EXPECT_EQ(1U, Builder.insert("foo"));
EXPECT_EQ(5U, Builder.insert("bar"));
EXPECT_EQ(1U, Builder.insert("foo"));
EXPECT_EQ(9U, Builder.insert("baz"));
std::vector<uint8_t> Buffer(Builder.calculateSerializedSize());
MutableBinaryByteStream OutStream(Buffer, little);
BinaryStreamWriter Writer(OutStream);
EXPECT_THAT_ERROR(Builder.commit(Writer), Succeeded());
// Reads the contents back.
BinaryByteStream InStream(Buffer, little);
BinaryStreamReader Reader(InStream);
PDBStringTable Table;
EXPECT_THAT_ERROR(Table.reload(Reader), Succeeded());
EXPECT_EQ(3U, Table.getNameCount());
EXPECT_EQ(1U, Table.getHashVersion());
EXPECT_THAT_EXPECTED(Table.getStringForID(1), HasValue("foo"));
EXPECT_THAT_EXPECTED(Table.getStringForID(5), HasValue("bar"));
EXPECT_THAT_EXPECTED(Table.getStringForID(9), HasValue("baz"));
EXPECT_THAT_EXPECTED(Table.getIDForString("foo"), HasValue(1U));
EXPECT_THAT_EXPECTED(Table.getIDForString("bar"), HasValue(5U));
EXPECT_THAT_EXPECTED(Table.getIDForString("baz"), HasValue(9U));
}