summaryrefslogtreecommitdiff
path: root/unittests/DebugInfo
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-12-18 20:10:56 +0000
commit044eb2f6afba375a914ac9d8024f8f5142bb912e (patch)
tree1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /unittests/DebugInfo
parenteb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff)
Notes
Diffstat (limited to 'unittests/DebugInfo')
-rw-r--r--unittests/DebugInfo/CMakeLists.txt1
-rw-r--r--unittests/DebugInfo/CodeView/CMakeLists.txt3
-rw-r--r--unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp14
-rw-r--r--unittests/DebugInfo/CodeView/TypeHashingTest.cpp156
-rw-r--r--unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp50
-rw-r--r--unittests/DebugInfo/DWARF/CMakeLists.txt2
-rw-r--r--unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp992
-rw-r--r--unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp18
-rw-r--r--unittests/DebugInfo/DWARF/DwarfGenerator.cpp15
-rw-r--r--unittests/DebugInfo/MSF/CMakeLists.txt15
-rw-r--r--unittests/DebugInfo/MSF/MSFBuilderTest.cpp (renamed from unittests/DebugInfo/PDB/MSFBuilderTest.cpp)38
-rw-r--r--unittests/DebugInfo/MSF/MSFCommonTest.cpp104
-rw-r--r--unittests/DebugInfo/MSF/MappedBlockStreamTest.cpp (renamed from unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp)72
-rw-r--r--unittests/DebugInfo/PDB/CMakeLists.txt4
-rw-r--r--unittests/DebugInfo/PDB/PDBApiTest.cpp9
15 files changed, 1359 insertions, 134 deletions
diff --git a/unittests/DebugInfo/CMakeLists.txt b/unittests/DebugInfo/CMakeLists.txt
index e38fff58cae6..579fdb202cf4 100644
--- a/unittests/DebugInfo/CMakeLists.txt
+++ b/unittests/DebugInfo/CMakeLists.txt
@@ -1,3 +1,4 @@
add_subdirectory(CodeView)
add_subdirectory(DWARF)
+add_subdirectory(MSF)
add_subdirectory(PDB)
diff --git a/unittests/DebugInfo/CodeView/CMakeLists.txt b/unittests/DebugInfo/CodeView/CMakeLists.txt
index 6f504d8149b5..d06ccfaba72a 100644
--- a/unittests/DebugInfo/CodeView/CMakeLists.txt
+++ b/unittests/DebugInfo/CodeView/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
set(DebugInfoCodeViewSources
RandomAccessVisitorTest.cpp
+ TypeHashingTest.cpp
TypeIndexDiscoveryTest.cpp
)
@@ -11,4 +12,4 @@ add_llvm_unittest(DebugInfoCodeViewTests
${DebugInfoCodeViewSources}
)
-target_link_libraries(DebugInfoCodeViewTests LLVMTestingSupport) \ No newline at end of file
+target_link_libraries(DebugInfoCodeViewTests PRIVATE LLVMTestingSupport)
diff --git a/unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp b/unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp
index 04b7bb0ba936..c84eae32face 100644
--- a/unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp
+++ b/unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp
@@ -7,13 +7,11 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/SmallBitVector.h"
+#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/TypeSerializer.h"
-#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
#include "llvm/Support/Allocator.h"
@@ -95,7 +93,7 @@ public:
static void SetUpTestCase() {
GlobalState = llvm::make_unique<GlobalTestState>();
- TypeTableBuilder Builder(GlobalState->Allocator);
+ AppendingTypeTableBuilder Builder(GlobalState->Allocator);
uint32_t Offset = 0;
for (int I = 0; I < 11; ++I) {
@@ -108,7 +106,7 @@ public:
Stream << "Array [" << I << "]";
AR.Name = GlobalState->Strings.save(Stream.str());
GlobalState->Records.push_back(AR);
- GlobalState->Indices.push_back(Builder.writeKnownType(AR));
+ GlobalState->Indices.push_back(Builder.writeLeafType(AR));
CVType Type(TypeLeafKind::LF_ARRAY, Builder.records().back());
GlobalState->TypeVector.push_back(Type);
@@ -352,7 +350,7 @@ TEST_F(RandomAccessVisitorTest, InnerChunk) {
}
TEST_F(RandomAccessVisitorTest, CrossChunkName) {
- TypeTableBuilder Builder(GlobalState->Allocator);
+ AppendingTypeTableBuilder Builder(GlobalState->Allocator);
// TypeIndex 0
ClassRecord Class(TypeRecordKind::Class);
@@ -363,13 +361,13 @@ TEST_F(RandomAccessVisitorTest, CrossChunkName) {
Class.DerivationList = TypeIndex::fromArrayIndex(0);
Class.FieldList = TypeIndex::fromArrayIndex(0);
Class.VTableShape = TypeIndex::fromArrayIndex(0);
- TypeIndex IndexZero = Builder.writeKnownType(Class);
+ 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.writeKnownType(Modifier);
+ TypeIndex IndexOne = Builder.writeLeafType(Modifier);
// set up a type stream that refers to the above two serialized records.
std::vector<CVType> TypeArray;
diff --git a/unittests/DebugInfo/CodeView/TypeHashingTest.cpp b/unittests/DebugInfo/CodeView/TypeHashingTest.cpp
new file mode 100644
index 000000000000..5b9dadfb33ff
--- /dev/null
+++ b/unittests/DebugInfo/CodeView/TypeHashingTest.cpp
@@ -0,0 +1,156 @@
+//===- 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]));
+}
diff --git a/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp b/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp
index fa9e96123184..c51b9e723f04 100644
--- a/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp
+++ b/unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp
@@ -9,7 +9,8 @@
#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
-#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
+#include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h"
+#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
#include "llvm/Support/Allocator.h"
@@ -25,13 +26,13 @@ public:
void SetUp() override {
Refs.clear();
- TTB = make_unique<TypeTableBuilder>(Storage);
- FLRB = make_unique<FieldListRecordBuilder>(*TTB);
+ TTB = make_unique<AppendingTypeTableBuilder>(Storage);
+ CRB = make_unique<ContinuationRecordBuilder>();
Symbols.clear();
}
void TearDown() override {
- FLRB.reset();
+ CRB.reset();
TTB.reset();
}
@@ -55,10 +56,11 @@ protected:
}
template <typename... T> void writeFieldList(T &&... MemberRecords) {
- FLRB->begin();
+ CRB->begin(ContinuationRecordKind::FieldList);
writeFieldListImpl(std::forward<T>(MemberRecords)...);
- FLRB->end(true);
- ASSERT_EQ(1u, TTB->records().size());
+ auto Records = CRB->end(TTB->nextTypeIndex());
+ ASSERT_EQ(1u, Records.size());
+ TTB->insertRecordBytes(Records.front().RecordData);
discoverAllTypeIndices();
}
@@ -74,8 +76,7 @@ protected:
discoverTypeIndicesInSymbols();
}
-
- std::unique_ptr<TypeTableBuilder> TTB;
+ std::unique_ptr<AppendingTypeTableBuilder> TTB;
private:
uint32_t countRefs(uint32_t RecordIndex) const {
@@ -131,7 +132,7 @@ private:
void discoverTypeIndicesInSymbols() {
Refs.resize(Symbols.size());
for (uint32_t I = 0; I < Symbols.size(); ++I)
- discoverTypeIndices(Symbols[I], Refs[I]);
+ discoverTypeIndicesInSymbol(Symbols[I], Refs[I]);
}
// Helper function to write out a field list record with the given list
@@ -140,7 +141,7 @@ private:
template <typename RecType, typename... Rest>
void writeFieldListImpl(RecType &&Record, Rest &&... Records) {
- FLRB->writeMemberType(Record);
+ CRB->writeMemberType(Record);
writeFieldListImpl(std::forward<Rest>(Records)...);
}
@@ -149,7 +150,7 @@ private:
template <typename RecType, typename... Rest>
void writeTypeRecordsImpl(RecType &&Record, Rest &&... Records) {
- TTB->writeKnownType(Record);
+ TTB->writeLeafType(Record);
writeTypeRecordsImpl(std::forward<Rest>(Records)...);
}
@@ -164,7 +165,7 @@ private:
}
std::vector<SmallVector<TiReference, 4>> Refs;
- std::unique_ptr<FieldListRecordBuilder> FLRB;
+ std::unique_ptr<ContinuationRecordBuilder> CRB;
std::vector<CVSymbol> Symbols;
BumpPtrAllocator Storage;
};
@@ -536,9 +537,9 @@ TEST_F(TypeIndexIteratorTest, ManyMembers) {
TEST_F(TypeIndexIteratorTest, ProcSym) {
ProcSym GS(SymbolRecordKind::GlobalProcSym);
- GS.FunctionType = TypeIndex(0x40);
+ GS.FunctionType = TypeIndex::Float32();
ProcSym LS(SymbolRecordKind::ProcSym);
- LS.FunctionType = TypeIndex(0x41);
+ LS.FunctionType = TypeIndex::Float64();
writeSymbolRecords(GS, LS);
checkTypeReferences(0, GS.FunctionType);
checkTypeReferences(1, LS.FunctionType);
@@ -546,11 +547,20 @@ TEST_F(TypeIndexIteratorTest, ProcSym) {
TEST_F(TypeIndexIteratorTest, DataSym) {
DataSym DS(SymbolRecordKind::GlobalData);
- DS.Type = TypeIndex(0x40);
+ DS.Type = TypeIndex::Float32();
writeSymbolRecords(DS);
checkTypeReferences(0, DS.Type);
}
+TEST_F(TypeIndexIteratorTest, RegisterSym) {
+ RegisterSym Reg(SymbolRecordKind::RegisterSym);
+ Reg.Index = TypeIndex::UInt32();
+ Reg.Register = RegisterId::EAX;
+ Reg.Name = "Target";
+ writeSymbolRecords(Reg);
+ checkTypeReferences(0, Reg.Index);
+}
+
TEST_F(TypeIndexIteratorTest, CallerSym) {
CallerSym Callees(SymbolRecordKind::CalleeSym);
Callees.Indices.push_back(TypeIndex(1));
@@ -560,7 +570,13 @@ TEST_F(TypeIndexIteratorTest, CallerSym) {
Callers.Indices.push_back(TypeIndex(4));
Callers.Indices.push_back(TypeIndex(5));
Callers.Indices.push_back(TypeIndex(6));
- writeSymbolRecords(Callees, Callers);
+ CallerSym Inlinees(SymbolRecordKind::InlineesSym);
+ Inlinees.Indices.push_back(TypeIndex(7));
+ Inlinees.Indices.push_back(TypeIndex(8));
+ Inlinees.Indices.push_back(TypeIndex(9));
+ writeSymbolRecords(Callees, Callers, Inlinees);
checkTypeReferences(0, TypeIndex(1), TypeIndex(2), TypeIndex(3));
checkTypeReferences(1, TypeIndex(4), TypeIndex(5), TypeIndex(6));
+ checkTypeReferences(2, TypeIndex(7), TypeIndex(8), TypeIndex(9));
}
+
diff --git a/unittests/DebugInfo/DWARF/CMakeLists.txt b/unittests/DebugInfo/DWARF/CMakeLists.txt
index 1966472a9467..f490097a21a7 100644
--- a/unittests/DebugInfo/DWARF/CMakeLists.txt
+++ b/unittests/DebugInfo/DWARF/CMakeLists.txt
@@ -18,4 +18,4 @@ add_llvm_unittest(DebugInfoDWARFTests
${DebugInfoSources}
)
-target_link_libraries(DebugInfoDWARFTests LLVMTestingSupport)
+target_link_libraries(DebugInfoDWARFTests PRIVATE LLVMTestingSupport)
diff --git a/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp b/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
index 6ffb710d2549..cb7bf82d86f6 100644
--- a/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
+++ b/unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp
@@ -14,27 +14,24 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/BinaryFormat/Dwarf.h"
-#include "llvm/Config/llvm-config.h"
#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/Config/llvm-config.h"
#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDie.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/ObjectYAML/DWARFEmitter.h"
-#include "llvm/ObjectYAML/DWARFYAML.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
-#include <climits>
-#include <cstdint>
-#include <cstring>
#include <string>
using namespace llvm;
@@ -85,6 +82,8 @@ void TestAllForms() {
const uint32_t Data4 = 0x6789abcdU;
const uint64_t Data8 = 0x0011223344556677ULL;
const uint64_t Data8_2 = 0xAABBCCDDEEFF0011ULL;
+ const uint8_t Data16[16] = {1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16};
const int64_t SData = INT64_MIN;
const int64_t ICSData = INT64_MAX; // DW_FORM_implicit_const SData
const uint64_t UData[] = {UINT64_MAX - 1, UINT64_MAX - 2, UINT64_MAX - 3,
@@ -123,6 +122,11 @@ void TestAllForms() {
const auto Attr_DW_FORM_block4 = static_cast<dwarf::Attribute>(Attr++);
CUDie.addAttribute(Attr_DW_FORM_block4, DW_FORM_block4, BlockData, BlockSize);
+ // We handle data16 as a block form.
+ const auto Attr_DW_FORM_data16 = static_cast<dwarf::Attribute>(Attr++);
+ if (Version >= 5)
+ CUDie.addAttribute(Attr_DW_FORM_data16, DW_FORM_data16, Data16, 16);
+
//----------------------------------------------------------------------
// Test data forms
//----------------------------------------------------------------------
@@ -228,10 +232,10 @@ void TestAllForms() {
MemoryBufferRef FileBuffer(FileBytes, "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
- DWARFContextInMemory DwarfContext(*Obj.get());
- uint32_t NumCUs = DwarfContext.getNumCompileUnits();
+ std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
+ uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
- DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+ DWARFCompileUnit *U = DwarfContext->getCompileUnitAtIndex(0);
auto DieDG = U->getUnitDIE(false);
EXPECT_TRUE(DieDG.isValid());
@@ -279,6 +283,17 @@ void TestAllForms() {
EXPECT_EQ(ExtractedBlockData.size(), BlockSize);
EXPECT_TRUE(memcmp(ExtractedBlockData.data(), BlockData, BlockSize) == 0);
+ // Data16 is handled like a block.
+ if (Version >= 5) {
+ FormValue = DieDG.find(Attr_DW_FORM_data16);
+ EXPECT_TRUE((bool)FormValue);
+ BlockDataOpt = FormValue->getAsBlock();
+ EXPECT_TRUE(BlockDataOpt.hasValue());
+ ExtractedBlockData = BlockDataOpt.getValue();
+ EXPECT_EQ(ExtractedBlockData.size(), 16u);
+ EXPECT_TRUE(memcmp(ExtractedBlockData.data(), Data16, 16) == 0);
+ }
+
//----------------------------------------------------------------------
// Test data forms
//----------------------------------------------------------------------
@@ -458,12 +473,12 @@ template <uint16_t Version, class AddrType> void TestChildren() {
MemoryBufferRef FileBuffer(FileBytes, "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
- DWARFContextInMemory DwarfContext(*Obj.get());
+ std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
- uint32_t NumCUs = DwarfContext.getNumCompileUnits();
+ uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
- DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+ DWARFCompileUnit *U = DwarfContext->getCompileUnitAtIndex(0);
// Get the compile unit DIE is valid.
auto DieDG = U->getUnitDIE(false);
@@ -629,13 +644,13 @@ template <uint16_t Version, class AddrType> void TestReferences() {
MemoryBufferRef FileBuffer(FileBytes, "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
- DWARFContextInMemory DwarfContext(*Obj.get());
+ std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
- uint32_t NumCUs = DwarfContext.getNumCompileUnits();
+ uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 2u);
- DWARFCompileUnit *U1 = DwarfContext.getCompileUnitAtIndex(0);
- DWARFCompileUnit *U2 = DwarfContext.getCompileUnitAtIndex(1);
+ DWARFCompileUnit *U1 = DwarfContext->getCompileUnitAtIndex(0);
+ DWARFCompileUnit *U2 = DwarfContext->getCompileUnitAtIndex(1);
// Get the compile unit DIE is valid.
auto Unit1DieDG = U1->getUnitDIE(false);
@@ -837,12 +852,12 @@ template <uint16_t Version, class AddrType> void TestAddresses() {
MemoryBufferRef FileBuffer(FileBytes, "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
- DWARFContextInMemory DwarfContext(*Obj.get());
+ std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
- uint32_t NumCUs = DwarfContext.getNumCompileUnits();
+ uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
- DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+ DWARFCompileUnit *U = DwarfContext->getCompileUnitAtIndex(0);
// Get the compile unit DIE is valid.
auto DieDG = U->getUnitDIE(false);
@@ -1012,12 +1027,12 @@ TEST(DWARFDebugInfo, TestRelations) {
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
- DWARFContextInMemory DwarfContext(*Obj.get());
+ std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
- uint32_t NumCUs = DwarfContext.getNumCompileUnits();
+ uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
- DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+ DWARFCompileUnit *U = DwarfContext->getCompileUnitAtIndex(0);
// Get the compile unit DIE is valid.
auto CUDie = U->getUnitDIE(false);
@@ -1127,12 +1142,12 @@ TEST(DWARFDebugInfo, TestChildIterators) {
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
- DWARFContextInMemory DwarfContext(*Obj.get());
+ std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
- uint32_t NumCUs = DwarfContext.getNumCompileUnits();
+ uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
- DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+ DWARFCompileUnit *U = DwarfContext->getCompileUnitAtIndex(0);
// Get the compile unit DIE is valid.
auto CUDie = U->getUnitDIE(false);
@@ -1188,12 +1203,13 @@ TEST(DWARFDebugInfo, TestEmptyChildren) {
auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
ASSERT_TRUE((bool)ErrOrSections);
- DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
// Verify the number of compile units is correct.
- uint32_t NumCUs = DwarfContext.getNumCompileUnits();
+ uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
- DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+ DWARFCompileUnit *U = DwarfContext->getCompileUnitAtIndex(0);
// Get the compile unit DIE is valid.
auto CUDie = U->getUnitDIE(false);
@@ -1235,12 +1251,12 @@ TEST(DWARFDebugInfo, TestAttributeIterators) {
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
- DWARFContextInMemory DwarfContext(*Obj.get());
+ std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
- uint32_t NumCUs = DwarfContext.getNumCompileUnits();
+ uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
- DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+ DWARFCompileUnit *U = DwarfContext->getCompileUnitAtIndex(0);
// Get the compile unit DIE is valid.
auto CUDie = U->getUnitDIE(false);
@@ -1285,12 +1301,16 @@ TEST(DWARFDebugInfo, TestFindRecurse) {
auto CUDie = CU.getUnitDIE();
auto FuncSpecDie = CUDie.addChild(DW_TAG_subprogram);
auto FuncAbsDie = CUDie.addChild(DW_TAG_subprogram);
+ // Put the linkage name in a second abstract origin DIE to ensure we
+ // recurse through more than just one DIE when looking for attributes.
+ auto FuncAbsDie2 = CUDie.addChild(DW_TAG_subprogram);
auto FuncDie = CUDie.addChild(DW_TAG_subprogram);
auto VarAbsDie = CUDie.addChild(DW_TAG_variable);
auto VarDie = CUDie.addChild(DW_TAG_variable);
FuncSpecDie.addAttribute(DW_AT_name, DW_FORM_strp, SpecDieName);
- FuncAbsDie.addAttribute(DW_AT_linkage_name, DW_FORM_strp, SpecLinkageName);
+ FuncAbsDie2.addAttribute(DW_AT_linkage_name, DW_FORM_strp, SpecLinkageName);
FuncAbsDie.addAttribute(DW_AT_specification, DW_FORM_ref4, FuncSpecDie);
+ FuncAbsDie.addAttribute(DW_AT_abstract_origin, DW_FORM_ref4, FuncAbsDie2);
FuncDie.addAttribute(DW_AT_abstract_origin, DW_FORM_ref4, FuncAbsDie);
VarAbsDie.addAttribute(DW_AT_name, DW_FORM_strp, AbsDieName);
VarDie.addAttribute(DW_AT_abstract_origin, DW_FORM_ref4, VarAbsDie);
@@ -1299,12 +1319,12 @@ TEST(DWARFDebugInfo, TestFindRecurse) {
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
- DWARFContextInMemory DwarfContext(*Obj.get());
+ std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
- uint32_t NumCUs = DwarfContext.getNumCompileUnits();
+ uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
- DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+ DWARFCompileUnit *U = DwarfContext->getCompileUnitAtIndex(0);
// Get the compile unit DIE is valid.
auto CUDie = U->getUnitDIE(false);
@@ -1312,7 +1332,8 @@ TEST(DWARFDebugInfo, TestFindRecurse) {
auto FuncSpecDie = CUDie.getFirstChild();
auto FuncAbsDie = FuncSpecDie.getSibling();
- auto FuncDie = FuncAbsDie.getSibling();
+ auto FuncAbsDie2 = FuncAbsDie.getSibling();
+ auto FuncDie = FuncAbsDie2.getSibling();
auto VarAbsDie = FuncDie.getSibling();
auto VarDie = VarAbsDie.getSibling();
@@ -1505,12 +1526,12 @@ TEST(DWARFDebugInfo, TestFindAttrs) {
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
- DWARFContextInMemory DwarfContext(*Obj.get());
+ std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
// Verify the number of compile units is correct.
- uint32_t NumCUs = DwarfContext.getNumCompileUnits();
+ uint32_t NumCUs = DwarfContext->getNumCompileUnits();
EXPECT_EQ(NumCUs, 1u);
- DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+ DWARFCompileUnit *U = DwarfContext->getCompileUnitAtIndex(0);
// Get the compile unit DIE is valid.
auto CUDie = U->getUnitDIE(false);
@@ -1568,8 +1589,8 @@ TEST(DWARFDebugInfo, TestImplicitConstAbbrevs) {
MemoryBufferRef FileBuffer(DG->generate(), "dwarf");
auto Obj = object::ObjectFile::createObjectFile(FileBuffer);
EXPECT_TRUE((bool)Obj);
- DWARFContextInMemory DwarfContext(*Obj.get());
- DWARFCompileUnit *U = DwarfContext.getCompileUnitAtIndex(0);
+ std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(**Obj);
+ DWARFCompileUnit *U = DwarfContext->getCompileUnitAtIndex(0);
EXPECT_TRUE((bool)U);
const auto *Abbrevs = U->getAbbreviations();
@@ -1657,16 +1678,29 @@ TEST(DWARFDebugInfo, TestImplicitConstAbbrevs) {
EXPECT_EQ(DIEs.find(Val2)->second, AbbrevPtrVal2);
}
+void VerifyWarning(DWARFContext &DwarfContext, StringRef Error) {
+ SmallString<1024> Str;
+ raw_svector_ostream Strm(Str);
+ EXPECT_TRUE(DwarfContext.verify(Strm));
+ EXPECT_TRUE(Str.str().contains(Error));
+}
+
void VerifyError(DWARFContext &DwarfContext, StringRef Error) {
SmallString<1024> Str;
raw_svector_ostream Strm(Str);
- EXPECT_FALSE(DwarfContext.verify(Strm, DIDT_All));
+ EXPECT_FALSE(DwarfContext.verify(Strm));
EXPECT_TRUE(Str.str().contains(Error));
}
+void VerifySuccess(DWARFContext &DwarfContext) {
+ SmallString<1024> Str;
+ raw_svector_ostream Strm(Str);
+ EXPECT_TRUE(DwarfContext.verify(Strm));
+}
+
TEST(DWARFDebugInfo, TestDwarfVerifyInvalidCURef) {
// Create a single compile unit with a single function that has a DW_AT_type
- // that is CU relative. The CU offset is not valid becuase it is larger than
+ // that is CU relative. The CU offset is not valid because it is larger than
// the compile unit itself.
const char *yamldata = R"(
@@ -1708,10 +1742,11 @@ TEST(DWARFDebugInfo, TestDwarfVerifyInvalidCURef) {
)";
auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
ASSERT_TRUE((bool)ErrOrSections);
- DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
- VerifyError(DwarfContext, "error: DW_FORM_ref4 CU offset 0x00001234 is "
- "invalid (must be less than CU size of "
- "0x0000001a):");
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifyError(*DwarfContext, "error: DW_FORM_ref4 CU offset 0x00001234 is "
+ "invalid (must be less than CU size of "
+ "0x0000001a):");
}
TEST(DWARFDebugInfo, TestDwarfVerifyInvalidRefAddr) {
@@ -1756,8 +1791,9 @@ TEST(DWARFDebugInfo, TestDwarfVerifyInvalidRefAddr) {
)";
auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
ASSERT_TRUE((bool)ErrOrSections);
- DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
- VerifyError(DwarfContext,
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifyError(*DwarfContext,
"error: DW_FORM_ref_addr offset beyond .debug_info bounds:");
}
@@ -1792,8 +1828,9 @@ TEST(DWARFDebugInfo, TestDwarfVerifyInvalidRanges) {
)";
auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
ASSERT_TRUE((bool)ErrOrSections);
- DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
- VerifyError(DwarfContext,
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifyError(*DwarfContext,
"error: DW_AT_ranges offset is beyond .debug_ranges bounds:");
}
@@ -1828,9 +1865,10 @@ TEST(DWARFDebugInfo, TestDwarfVerifyInvalidStmtList) {
)";
auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
ASSERT_TRUE((bool)ErrOrSections);
- DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
VerifyError(
- DwarfContext,
+ *DwarfContext,
"error: DW_AT_stmt_list offset is beyond .debug_line bounds: 0x00001000");
}
@@ -1860,8 +1898,9 @@ TEST(DWARFDebugInfo, TestDwarfVerifyInvalidStrp) {
)";
auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
ASSERT_TRUE((bool)ErrOrSections);
- DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
- VerifyError(DwarfContext,
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifyError(*DwarfContext,
"error: DW_FORM_strp offset beyond .debug_str bounds:");
}
@@ -1907,9 +1946,10 @@ TEST(DWARFDebugInfo, TestDwarfVerifyInvalidRefAddrBetween) {
)";
auto ErrOrSections = DWARFYAML::EmitDebugSections(StringRef(yamldata));
ASSERT_TRUE((bool)ErrOrSections);
- DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
VerifyError(
- DwarfContext,
+ *DwarfContext,
"error: invalid DIE reference 0x00000011. Offset is in between DIEs:");
}
@@ -1977,9 +2017,10 @@ TEST(DWARFDebugInfo, TestDwarfVerifyInvalidLineSequence) {
)";
auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata);
ASSERT_TRUE((bool)ErrOrSections);
- DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
- VerifyError(DwarfContext, "error: .debug_line[0x00000000] row[1] decreases "
- "in address from previous row:");
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifyError(*DwarfContext, "error: .debug_line[0x00000000] row[1] decreases "
+ "in address from previous row:");
}
TEST(DWARFDebugInfo, TestDwarfVerifyInvalidLineFileIndex) {
@@ -2048,9 +2089,160 @@ TEST(DWARFDebugInfo, TestDwarfVerifyInvalidLineFileIndex) {
)";
auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata);
ASSERT_TRUE((bool)ErrOrSections);
- DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
- VerifyError(DwarfContext, "error: .debug_line[0x00000000][1] has invalid "
- "file index 5 (valid values are [1,1]):");
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifyError(*DwarfContext, "error: .debug_line[0x00000000][1] has invalid "
+ "file index 5 (valid values are [1,1]):");
+}
+
+TEST(DWARFDebugInfo, TestDwarfVerifyInvalidLineTablePorlogueDirIndex) {
+ // Create a single compile unit whose line table has a prologue with an
+ // invalid dir index.
+ StringRef yamldata = R"(
+ debug_str:
+ - ''
+ - /tmp/main.c
+ debug_abbrev:
+ - Code: 0x00000001
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Attribute: DW_AT_stmt_list
+ Form: DW_FORM_sec_offset
+ debug_info:
+ - Length:
+ TotalLength: 16
+ Version: 4
+ AbbrOffset: 0
+ AddrSize: 8
+ Entries:
+ - AbbrCode: 0x00000001
+ Values:
+ - Value: 0x0000000000000001
+ - Value: 0x0000000000000000
+ debug_line:
+ - Length:
+ TotalLength: 61
+ Version: 2
+ PrologueLength: 34
+ MinInstLength: 1
+ DefaultIsStmt: 1
+ LineBase: 251
+ LineRange: 14
+ OpcodeBase: 13
+ StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
+ IncludeDirs:
+ - /tmp
+ Files:
+ - Name: main.c
+ DirIdx: 2
+ ModTime: 0
+ Length: 0
+ Opcodes:
+ - Opcode: DW_LNS_extended_op
+ ExtLen: 9
+ SubOpcode: DW_LNE_set_address
+ Data: 4096
+ - Opcode: DW_LNS_advance_line
+ SData: 9
+ Data: 4096
+ - Opcode: DW_LNS_copy
+ Data: 4096
+ - Opcode: DW_LNS_advance_pc
+ Data: 16
+ - Opcode: DW_LNS_set_file
+ Data: 1
+ - Opcode: DW_LNS_extended_op
+ ExtLen: 1
+ SubOpcode: DW_LNE_end_sequence
+ Data: 1
+ )";
+ auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata);
+ ASSERT_TRUE((bool)ErrOrSections);
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifyError(*DwarfContext,
+ "error: .debug_line[0x00000000].prologue."
+ "file_names[1].dir_idx contains an invalid index: 2");
+}
+
+TEST(DWARFDebugInfo, TestDwarfVerifyDuplicateFileWarning) {
+ // Create a single compile unit whose line table has a prologue with an
+ // invalid dir index.
+ StringRef yamldata = R"(
+ debug_str:
+ - ''
+ - /tmp/main.c
+ debug_abbrev:
+ - Code: 0x00000001
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Attribute: DW_AT_stmt_list
+ Form: DW_FORM_sec_offset
+ debug_info:
+ - Length:
+ TotalLength: 16
+ Version: 4
+ AbbrOffset: 0
+ AddrSize: 8
+ Entries:
+ - AbbrCode: 0x00000001
+ Values:
+ - Value: 0x0000000000000001
+ - Value: 0x0000000000000000
+ debug_line:
+ - Length:
+ TotalLength: 71
+ Version: 2
+ PrologueLength: 44
+ MinInstLength: 1
+ DefaultIsStmt: 1
+ LineBase: 251
+ LineRange: 14
+ OpcodeBase: 13
+ StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ]
+ IncludeDirs:
+ - /tmp
+ Files:
+ - Name: main.c
+ DirIdx: 1
+ ModTime: 0
+ Length: 0
+ - Name: main.c
+ DirIdx: 1
+ ModTime: 0
+ Length: 0
+ Opcodes:
+ - Opcode: DW_LNS_extended_op
+ ExtLen: 9
+ SubOpcode: DW_LNE_set_address
+ Data: 4096
+ - Opcode: DW_LNS_advance_line
+ SData: 9
+ Data: 4096
+ - Opcode: DW_LNS_copy
+ Data: 4096
+ - Opcode: DW_LNS_advance_pc
+ Data: 16
+ - Opcode: DW_LNS_set_file
+ Data: 1
+ - Opcode: DW_LNS_extended_op
+ ExtLen: 1
+ SubOpcode: DW_LNE_end_sequence
+ Data: 2
+ )";
+ auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata);
+ ASSERT_TRUE((bool)ErrOrSections);
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifyWarning(*DwarfContext,
+ "warning: .debug_line[0x00000000].prologue.file_names[2] is "
+ "a duplicate of file_names[1]");
}
TEST(DWARFDebugInfo, TestDwarfVerifyCUDontShareLineTable) {
@@ -2128,10 +2320,12 @@ TEST(DWARFDebugInfo, TestDwarfVerifyCUDontShareLineTable) {
)";
auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata);
ASSERT_TRUE((bool)ErrOrSections);
- DWARFContextInMemory DwarfContext(*ErrOrSections, 8);
- VerifyError(DwarfContext, "error: two compile unit DIEs, 0x0000000b and "
- "0x0000001f, have the same DW_AT_stmt_list section "
- "offset:");
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifyError(*DwarfContext,
+ "error: two compile unit DIEs, 0x0000000b and "
+ "0x0000001f, have the same DW_AT_stmt_list section "
+ "offset:");
}
TEST(DWARFDebugInfo, TestErrorReportingPolicy) {
@@ -2158,24 +2352,664 @@ TEST(DWARFDebugInfo, TestErrorReportingPolicy) {
EXPECT_TRUE((bool)Obj);
// Case 1: error handler handles all errors. That allows
- // DWARFContextInMemory
- // to parse whole file and find both two errors we know about.
+ // DWARFContext to parse whole file and find both two errors we know about.
int Errors = 0;
- DWARFContextInMemory Ctx1(*Obj.get(), nullptr, [&](Error E) {
- ++Errors;
- consumeError(std::move(E));
- return ErrorPolicy::Continue;
- });
+ std::unique_ptr<DWARFContext> Ctx1 =
+ DWARFContext::create(**Obj, nullptr, [&](Error E) {
+ ++Errors;
+ consumeError(std::move(E));
+ return ErrorPolicy::Continue;
+ });
EXPECT_TRUE(Errors == 2);
// Case 2: error handler stops parsing of object after first error.
Errors = 0;
- DWARFContextInMemory Ctx2(*Obj.get(), nullptr, [&](Error E) {
- ++Errors;
- consumeError(std::move(E));
- return ErrorPolicy::Halt;
- });
+ std::unique_ptr<DWARFContext> Ctx2 =
+ DWARFContext::create(**Obj, nullptr, [&](Error E) {
+ ++Errors;
+ consumeError(std::move(E));
+ return ErrorPolicy::Halt;
+ });
EXPECT_TRUE(Errors == 1);
}
+TEST(DWARFDebugInfo, TestDwarfVerifyCURangesIncomplete) {
+ // Create a single compile unit with a single function. The compile
+ // unit has a DW_AT_ranges attribute that doesn't fully contain the
+ // address range of the function. The verification should fail due to
+ // the CU ranges not containing all of the address ranges of all of the
+ // functions.
+ StringRef yamldata = R"(
+ debug_str:
+ - ''
+ - /tmp/main.c
+ debug_abbrev:
+ - Code: 0x00000001
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Code: 0x00000002
+ Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_addr
+ debug_info:
+ - Length:
+ TotalLength: 46
+ Version: 4
+ AbbrOffset: 0
+ AddrSize: 8
+ Entries:
+ - AbbrCode: 0x00000001
+ Values:
+ - Value: 0x0000000000001000
+ - Value: 0x0000000000001500
+ - Value: 0x0000000000000001
+ - AbbrCode: 0x00000002
+ Values:
+ - Value: 0x0000000000001000
+ - Value: 0x0000000000002000
+ - AbbrCode: 0x00000000
+ Values:
+ )";
+ auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata);
+ ASSERT_TRUE((bool)ErrOrSections);
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifyError(*DwarfContext, "error: DIE address ranges are not "
+ "contained in its parent's ranges:");
+}
+
+TEST(DWARFDebugInfo, TestDwarfVerifyLexicalBlockRanges) {
+ // Create a single compile unit with a single function that has a lexical
+ // block whose address range is not contained in the function address range.
+ StringRef yamldata = R"(
+ debug_str:
+ - ''
+ - /tmp/main.c
+ - main
+ debug_abbrev:
+ - Code: 0x00000001
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Code: 0x00000002
+ Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_addr
+ - Code: 0x00000003
+ Tag: DW_TAG_lexical_block
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_addr
+ debug_info:
+ - Length:
+ TotalLength: 52
+ Version: 4
+ AbbrOffset: 0
+ AddrSize: 8
+ Entries:
+ - AbbrCode: 0x00000001
+ Values:
+ - Value: 0x0000000000000001
+ - AbbrCode: 0x00000002
+ Values:
+ - Value: 0x000000000000000D
+ - Value: 0x0000000000001000
+ - Value: 0x0000000000002000
+ - AbbrCode: 0x00000003
+ Values:
+ - Value: 0x0000000000001000
+ - Value: 0x0000000000002001
+ - AbbrCode: 0x00000000
+ Values:
+ - AbbrCode: 0x00000000
+ Values:
+ )";
+ auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata);
+ ASSERT_TRUE((bool)ErrOrSections);
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifyError(*DwarfContext, "error: DIE address ranges are not "
+ "contained in its parent's ranges:");
+}
+
+TEST(DWARFDebugInfo, TestDwarfVerifyOverlappingFunctionRanges) {
+ // Create a single compile unit with a two functions that have overlapping
+ // address ranges.
+ StringRef yamldata = R"(
+ debug_str:
+ - ''
+ - /tmp/main.c
+ - main
+ - foo
+ debug_abbrev:
+ - Code: 0x00000001
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Code: 0x00000002
+ Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_addr
+ debug_info:
+ - Length:
+ TotalLength: 55
+ Version: 4
+ AbbrOffset: 0
+ AddrSize: 8
+ Entries:
+ - AbbrCode: 0x00000001
+ Values:
+ - Value: 0x0000000000000001
+ - AbbrCode: 0x00000002
+ Values:
+ - Value: 0x000000000000000D
+ - Value: 0x0000000000001000
+ - Value: 0x0000000000002000
+ - AbbrCode: 0x00000002
+ Values:
+ - Value: 0x0000000000000012
+ - Value: 0x0000000000001FFF
+ - Value: 0x0000000000002000
+ - AbbrCode: 0x00000000
+ Values:
+ )";
+ auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata);
+ ASSERT_TRUE((bool)ErrOrSections);
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifyError(*DwarfContext, "error: DIEs have overlapping address ranges:");
+}
+
+TEST(DWARFDebugInfo, TestDwarfVerifyOverlappingLexicalBlockRanges) {
+ // Create a single compile unit with a one function that has two lexical
+ // blocks with overlapping address ranges.
+ StringRef yamldata = R"(
+ debug_str:
+ - ''
+ - /tmp/main.c
+ - main
+ debug_abbrev:
+ - Code: 0x00000001
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Code: 0x00000002
+ Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_addr
+ - Code: 0x00000003
+ Tag: DW_TAG_lexical_block
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_addr
+ debug_info:
+ - Length:
+ TotalLength: 85
+ Version: 4
+ AbbrOffset: 0
+ AddrSize: 8
+ Entries:
+ - AbbrCode: 0x00000001
+ Values:
+ - Value: 0x0000000000001000
+ - Value: 0x0000000000002000
+ - Value: 0x0000000000000001
+ - AbbrCode: 0x00000002
+ Values:
+ - Value: 0x000000000000000D
+ - Value: 0x0000000000001000
+ - Value: 0x0000000000002000
+ - AbbrCode: 0x00000003
+ Values:
+ - Value: 0x0000000000001100
+ - Value: 0x0000000000001300
+ - AbbrCode: 0x00000003
+ Values:
+ - Value: 0x00000000000012FF
+ - Value: 0x0000000000001300
+ - AbbrCode: 0x00000000
+ Values:
+ - AbbrCode: 0x00000000
+ Values:
+ )";
+ auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata);
+ ASSERT_TRUE((bool)ErrOrSections);
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifyError(*DwarfContext, "error: DIEs have overlapping address ranges:");
+}
+
+TEST(DWARFDebugInfo, TestDwarfVerifyInvalidDIERange) {
+ // Create a single compile unit with a single function that has an invalid
+ // address range where the high PC is smaller than the low PC.
+ StringRef yamldata = R"(
+ debug_str:
+ - ''
+ - /tmp/main.c
+ - main
+ debug_abbrev:
+ - Code: 0x00000001
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Code: 0x00000002
+ Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_addr
+ debug_info:
+ - Length:
+ TotalLength: 34
+ Version: 4
+ AbbrOffset: 0
+ AddrSize: 8
+ Entries:
+ - AbbrCode: 0x00000001
+ Values:
+ - Value: 0x0000000000000001
+ - AbbrCode: 0x00000002
+ Values:
+ - Value: 0x000000000000000D
+ - Value: 0x0000000000001000
+ - Value: 0x0000000000000900
+ - AbbrCode: 0x00000000
+ Values:
+ )";
+ auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata);
+ ASSERT_TRUE((bool)ErrOrSections);
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifyError(*DwarfContext, "error: Invalid address range");
+}
+
+TEST(DWARFDebugInfo, TestDwarfVerifyElidedDoesntFail) {
+ // Create a single compile unit with two functions: one that has a valid range
+ // and one whose low and high PC are the same. When the low and high PC are
+ // the same, this indicates the function was dead code stripped. We want to
+ // ensure that verification succeeds.
+ StringRef yamldata = R"(
+ debug_str:
+ - ''
+ - /tmp/main.c
+ - main
+ - elided
+ debug_abbrev:
+ - Code: 0x00000001
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Code: 0x00000002
+ Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_no
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_addr
+ debug_info:
+ - Length:
+ TotalLength: 71
+ Version: 4
+ AbbrOffset: 0
+ AddrSize: 8
+ Entries:
+ - AbbrCode: 0x00000001
+ Values:
+ - Value: 0x0000000000001000
+ - Value: 0x0000000000002000
+ - Value: 0x0000000000000001
+ - AbbrCode: 0x00000002
+ Values:
+ - Value: 0x000000000000000D
+ - Value: 0x0000000000001000
+ - Value: 0x0000000000002000
+ - AbbrCode: 0x00000002
+ Values:
+ - Value: 0x0000000000000012
+ - Value: 0x0000000000002000
+ - Value: 0x0000000000002000
+ - AbbrCode: 0x00000000
+ Values:
+ )";
+ auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata);
+ ASSERT_TRUE((bool)ErrOrSections);
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifySuccess(*DwarfContext);
+}
+
+TEST(DWARFDebugInfo, TestDwarfVerifyNestedFunctions) {
+ // Create a single compile unit with a nested function which is not contained
+ // in its parent. Although LLVM doesn't generate this, it is valid accoridng
+ // to the DWARF standard.
+ StringRef yamldata = R"(
+ debug_str:
+ - ''
+ - /tmp/main.c
+ - main
+ - nested
+ debug_abbrev:
+ - Code: 0x00000001
+ Tag: DW_TAG_compile_unit
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Code: 0x00000002
+ Tag: DW_TAG_subprogram
+ Children: DW_CHILDREN_yes
+ Attributes:
+ - Attribute: DW_AT_name
+ Form: DW_FORM_strp
+ - Attribute: DW_AT_low_pc
+ Form: DW_FORM_addr
+ - Attribute: DW_AT_high_pc
+ Form: DW_FORM_addr
+ debug_info:
+ - Length:
+ TotalLength: 73
+ Version: 4
+ AbbrOffset: 0
+ AddrSize: 8
+ Entries:
+ - AbbrCode: 0x00000001
+ Values:
+ - Value: 0x0000000000001000
+ - Value: 0x0000000000002000
+ - Value: 0x0000000000000001
+ - AbbrCode: 0x00000002
+ Values:
+ - Value: 0x000000000000000D
+ - Value: 0x0000000000001000
+ - Value: 0x0000000000001500
+ - AbbrCode: 0x00000002
+ Values:
+ - Value: 0x0000000000000012
+ - Value: 0x0000000000001500
+ - Value: 0x0000000000002000
+ - AbbrCode: 0x00000000
+ Values:
+ - AbbrCode: 0x00000000
+ Values:
+ - AbbrCode: 0x00000000
+ Values:
+ )";
+ auto ErrOrSections = DWARFYAML::EmitDebugSections(yamldata);
+ ASSERT_TRUE((bool)ErrOrSections);
+ std::unique_ptr<DWARFContext> DwarfContext =
+ DWARFContext::create(*ErrOrSections, 8);
+ VerifySuccess(*DwarfContext);
+}
+
+TEST(DWARFDebugInfo, TestDwarfRangesContains) {
+ DWARFAddressRange R(0x10, 0x20);
+
+ //----------------------------------------------------------------------
+ // Test ranges that start before R...
+ //----------------------------------------------------------------------
+ // Other range ends before start of R
+ ASSERT_FALSE(R.contains({0x0f, 0x10}));
+ // Other range end address is start of a R
+ ASSERT_FALSE(R.contains({0x0f, 0x11}));
+ // Other range end address is at and of R
+ ASSERT_FALSE(R.contains({0x0f, 0x20}));
+ // Other range end address is past end of R
+ ASSERT_FALSE(R.contains({0x0f, 0x40}));
+
+ //----------------------------------------------------------------------
+ // Test ranges that start at R's start address
+ //----------------------------------------------------------------------
+ // Ensure empty ranges matches
+ ASSERT_TRUE(R.contains({0x10, 0x10}));
+ // 1 byte of Range
+ ASSERT_TRUE(R.contains({0x10, 0x11}));
+ // same as Range
+ ASSERT_TRUE(R.contains({0x10, 0x20}));
+ // 1 byte past Range
+ ASSERT_FALSE(R.contains({0x10, 0x21}));
+
+ //----------------------------------------------------------------------
+ // Test ranges that start inside Range
+ //----------------------------------------------------------------------
+ // empty in range
+ ASSERT_TRUE(R.contains({0x11, 0x11}));
+ // all in Range
+ ASSERT_TRUE(R.contains({0x11, 0x1f}));
+ // ends at end of Range
+ ASSERT_TRUE(R.contains({0x11, 0x20}));
+ // ends past Range
+ ASSERT_FALSE(R.contains({0x11, 0x21}));
+
+ //----------------------------------------------------------------------
+ // Test ranges that start at last bytes of Range
+ //----------------------------------------------------------------------
+ // ends at end of Range
+ ASSERT_TRUE(R.contains({0x1f, 0x20}));
+ // ends past Range
+ ASSERT_FALSE(R.contains({0x1f, 0x21}));
+
+ //----------------------------------------------------------------------
+ // Test ranges that start after Range
+ //----------------------------------------------------------------------
+ // empty considered in Range
+ ASSERT_TRUE(R.contains({0x20, 0x20}));
+ // valid past Range
+ ASSERT_FALSE(R.contains({0x20, 0x21}));
+}
+
+TEST(DWARFDebugInfo, TestDWARFDieRangeInfoContains) {
+ DWARFVerifier::DieRangeInfo Ranges({{0x10, 0x20}, {0x30, 0x40}});
+
+ ASSERT_FALSE(Ranges.contains({{{0x0f, 0x10}}}));
+ ASSERT_FALSE(Ranges.contains({{{0x20, 0x30}}}));
+ ASSERT_FALSE(Ranges.contains({{{0x40, 0x41}}}));
+ ASSERT_TRUE(Ranges.contains({{{0x10, 0x20}}}));
+ ASSERT_TRUE(Ranges.contains({{{0x11, 0x12}}}));
+ ASSERT_TRUE(Ranges.contains({{{0x1f, 0x20}}}));
+ ASSERT_TRUE(Ranges.contains({{{0x30, 0x40}}}));
+ ASSERT_TRUE(Ranges.contains({{{0x31, 0x32}}}));
+ ASSERT_TRUE(Ranges.contains({{{0x3f, 0x40}}}));
+ ASSERT_TRUE(Ranges.contains({{{0x10, 0x20}, {0x30, 0x40}}}));
+ ASSERT_TRUE(Ranges.contains({{{0x11, 0x12}, {0x31, 0x32}}}));
+ ASSERT_TRUE(Ranges.contains(
+ {{{0x11, 0x12}, {0x12, 0x13}, {0x31, 0x32}, {0x32, 0x33}}}));
+ ASSERT_FALSE(Ranges.contains({{{0x11, 0x12},
+ {0x12, 0x13},
+ {0x20, 0x21},
+ {0x31, 0x32},
+ {0x32, 0x33}}}));
+ ASSERT_FALSE(Ranges.contains(
+ {{{0x11, 0x12}, {0x12, 0x13}, {0x31, 0x32}, {0x32, 0x41}}}));
+}
+
+namespace {
+
+void AssertRangesIntersect(const DWARFAddressRange &LHS,
+ const DWARFAddressRange &RHS) {
+ ASSERT_TRUE(LHS.intersects(RHS));
+ ASSERT_TRUE(RHS.intersects(LHS));
+}
+void AssertRangesDontIntersect(const DWARFAddressRange &LHS,
+ const DWARFAddressRange &RHS) {
+ ASSERT_FALSE(LHS.intersects(RHS));
+ ASSERT_FALSE(RHS.intersects(LHS));
+}
+
+void AssertRangesIntersect(const DWARFVerifier::DieRangeInfo &LHS,
+ const DWARFAddressRangesVector &Ranges) {
+ DWARFVerifier::DieRangeInfo RHS(Ranges);
+ ASSERT_TRUE(LHS.intersects(RHS));
+ ASSERT_TRUE(RHS.intersects(LHS));
+}
+
+void AssertRangesDontIntersect(const DWARFVerifier::DieRangeInfo &LHS,
+ const DWARFAddressRangesVector &Ranges) {
+ DWARFVerifier::DieRangeInfo RHS(Ranges);
+ ASSERT_FALSE(LHS.intersects(RHS));
+ ASSERT_FALSE(RHS.intersects(LHS));
+}
+
+} // namespace
+TEST(DWARFDebugInfo, TestDwarfRangesIntersect) {
+ DWARFAddressRange R(0x10, 0x20);
+
+ //----------------------------------------------------------------------
+ // Test ranges that start before R...
+ //----------------------------------------------------------------------
+ // Other range ends before start of R
+ AssertRangesDontIntersect(R, {0x00, 0x10});
+ // Other range end address is start of a R
+ AssertRangesIntersect(R, {0x00, 0x11});
+ // Other range end address is in R
+ AssertRangesIntersect(R, {0x00, 0x15});
+ // Other range end address is at and of R
+ AssertRangesIntersect(R, {0x00, 0x20});
+ // Other range end address is past end of R
+ AssertRangesIntersect(R, {0x00, 0x40});
+
+ //----------------------------------------------------------------------
+ // Test ranges that start at R's start address
+ //----------------------------------------------------------------------
+ // Ensure empty ranges doesn't match
+ AssertRangesDontIntersect(R, {0x10, 0x10});
+ // 1 byte of Range
+ AssertRangesIntersect(R, {0x10, 0x11});
+ // same as Range
+ AssertRangesIntersect(R, {0x10, 0x20});
+ // 1 byte past Range
+ AssertRangesIntersect(R, {0x10, 0x21});
+
+ //----------------------------------------------------------------------
+ // Test ranges that start inside Range
+ //----------------------------------------------------------------------
+ // empty in range
+ AssertRangesDontIntersect(R, {0x11, 0x11});
+ // all in Range
+ AssertRangesIntersect(R, {0x11, 0x1f});
+ // ends at end of Range
+ AssertRangesIntersect(R, {0x11, 0x20});
+ // ends past Range
+ AssertRangesIntersect(R, {0x11, 0x21});
+
+ //----------------------------------------------------------------------
+ // Test ranges that start at last bytes of Range
+ //----------------------------------------------------------------------
+ // ends at end of Range
+ AssertRangesIntersect(R, {0x1f, 0x20});
+ // ends past Range
+ AssertRangesIntersect(R, {0x1f, 0x21});
+
+ //----------------------------------------------------------------------
+ // Test ranges that start after Range
+ //----------------------------------------------------------------------
+ // empty just past in Range
+ AssertRangesDontIntersect(R, {0x20, 0x20});
+ // valid past Range
+ AssertRangesDontIntersect(R, {0x20, 0x21});
+}
+
+TEST(DWARFDebugInfo, TestDWARFDieRangeInfoIntersects) {
+
+ DWARFVerifier::DieRangeInfo Ranges({{0x10, 0x20}, {0x30, 0x40}});
+
+ // Test empty range
+ AssertRangesDontIntersect(Ranges, {});
+ // Test range that appears before all ranges in Ranges
+ AssertRangesDontIntersect(Ranges, {{0x00, 0x10}});
+ // Test range that appears between ranges in Ranges
+ AssertRangesDontIntersect(Ranges, {{0x20, 0x30}});
+ // Test range that appears after ranges in Ranges
+ AssertRangesDontIntersect(Ranges, {{0x40, 0x50}});
+
+ // Test range that start before first range
+ AssertRangesIntersect(Ranges, {{0x00, 0x11}});
+ // Test range that start at first range
+ AssertRangesIntersect(Ranges, {{0x10, 0x11}});
+ // Test range that start in first range
+ AssertRangesIntersect(Ranges, {{0x11, 0x12}});
+ // Test range that start at end of first range
+ AssertRangesIntersect(Ranges, {{0x1f, 0x20}});
+ // Test range that starts at end of first range
+ AssertRangesDontIntersect(Ranges, {{0x20, 0x21}});
+ // Test range that starts at end of first range
+ AssertRangesIntersect(Ranges, {{0x20, 0x31}});
+
+ // Test range that start before second range and ends before second
+ AssertRangesDontIntersect(Ranges, {{0x2f, 0x30}});
+ // Test range that start before second range and ends in second
+ AssertRangesIntersect(Ranges, {{0x2f, 0x31}});
+ // Test range that start at second range
+ AssertRangesIntersect(Ranges, {{0x30, 0x31}});
+ // Test range that start in second range
+ AssertRangesIntersect(Ranges, {{0x31, 0x32}});
+ // Test range that start at end of second range
+ AssertRangesIntersect(Ranges, {{0x3f, 0x40}});
+ // Test range that starts at end of second range
+ AssertRangesDontIntersect(Ranges, {{0x40, 0x41}});
+}
+
} // end anonymous namespace
diff --git a/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp b/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp
index f283ac0961cc..c552623a7866 100644
--- a/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp
+++ b/unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp
@@ -99,7 +99,7 @@ DWARFFormValue createDataXFormValue(dwarf::Form Form, RawTypeT Value) {
DWARFFormValue Result(Form);
DWARFDataExtractor Data(StringRef(Raw, sizeof(RawTypeT)),
sys::IsLittleEndianHost, sizeof(void *));
- Result.extractValue(Data, &Offset, nullptr);
+ Result.extractValue(Data, &Offset, {0, 0, dwarf::DwarfFormat::DWARF32});
return Result;
}
@@ -110,7 +110,7 @@ DWARFFormValue createULEBFormValue(uint64_t Value) {
uint32_t Offset = 0;
DWARFFormValue Result(DW_FORM_udata);
DWARFDataExtractor Data(OS.str(), sys::IsLittleEndianHost, sizeof(void *));
- Result.extractValue(Data, &Offset, nullptr);
+ Result.extractValue(Data, &Offset, {0, 0, dwarf::DwarfFormat::DWARF32});
return Result;
}
@@ -121,7 +121,7 @@ DWARFFormValue createSLEBFormValue(int64_t Value) {
uint32_t Offset = 0;
DWARFFormValue Result(DW_FORM_sdata);
DWARFDataExtractor Data(OS.str(), sys::IsLittleEndianHost, sizeof(void *));
- Result.extractValue(Data, &Offset, nullptr);
+ Result.extractValue(Data, &Offset, {0, 0, dwarf::DwarfFormat::DWARF32});
return Result;
}
@@ -160,6 +160,18 @@ TEST(DWARFFormValue, SignedConstantForms) {
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
diff --git a/unittests/DebugInfo/DWARF/DwarfGenerator.cpp b/unittests/DebugInfo/DWARF/DwarfGenerator.cpp
index c32cfa1de9ae..3aa52a0d5b8f 100644
--- a/unittests/DebugInfo/DWARF/DwarfGenerator.cpp
+++ b/unittests/DebugInfo/DWARF/DwarfGenerator.cpp
@@ -13,10 +13,8 @@
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/DIE.h"
-#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
-#include "llvm/IR/LegacyPassManagers.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCCodeEmitter.h"
@@ -27,9 +25,8 @@
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCTargetOptionsCommandFlags.h"
+#include "llvm/MC/MCTargetOptionsCommandFlags.def"
#include "llvm/PassAnalysisSupport.h"
-#include "llvm/Support/LEB128.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
@@ -153,10 +150,10 @@ llvm::Error dwarfgen::Generator::init(Triple TheTriple, uint16_t V) {
MOFI.reset(new MCObjectFileInfo);
MC.reset(new MCContext(MAI.get(), MRI.get(), MOFI.get()));
- MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, CodeModel::Default, *MC);
+ MOFI->InitMCObjectFileInfo(TheTriple, /*PIC*/ false, *MC);
- MCTargetOptions Options;
- MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, "", Options);
+ MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();
+ MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, "", MCOptions);
if (!MAB)
return make_error<StringError>("no asm backend for target " + TripleName,
inconvertibleErrorCode());
@@ -179,9 +176,9 @@ llvm::Error dwarfgen::Generator::init(Triple TheTriple, uint16_t V) {
Stream = make_unique<raw_svector_ostream>(FileBytes);
- MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();
MS = TheTarget->createMCObjectStreamer(
- TheTriple, *MC, *MAB, *Stream, MCE, *MSTI, MCOptions.MCRelaxAll,
+ TheTriple, *MC, std::unique_ptr<MCAsmBackend>(MAB), *Stream,
+ std::unique_ptr<MCCodeEmitter>(MCE), *MSTI, MCOptions.MCRelaxAll,
MCOptions.MCIncrementalLinkerCompatible,
/*DWARFMustBeAtTheEnd*/ false);
if (!MS)
diff --git a/unittests/DebugInfo/MSF/CMakeLists.txt b/unittests/DebugInfo/MSF/CMakeLists.txt
new file mode 100644
index 000000000000..20f3b2ab3dcd
--- /dev/null
+++ b/unittests/DebugInfo/MSF/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(LLVM_LINK_COMPONENTS
+ DebugInfoMSF
+ )
+
+set(DebugInfoMSFSources
+ MappedBlockStreamTest.cpp
+ MSFBuilderTest.cpp
+ MSFCommonTest.cpp
+ )
+
+add_llvm_unittest(DebugInfoMSFTests
+ ${DebugInfoMSFSources}
+ )
+
+target_link_libraries(DebugInfoMSFTests PRIVATE LLVMTestingSupport)
diff --git a/unittests/DebugInfo/PDB/MSFBuilderTest.cpp b/unittests/DebugInfo/MSF/MSFBuilderTest.cpp
index 23a15d14f756..a91ac8d443fe 100644
--- a/unittests/DebugInfo/PDB/MSFBuilderTest.cpp
+++ b/unittests/DebugInfo/MSF/MSFBuilderTest.cpp
@@ -11,10 +11,13 @@
#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 {
@@ -38,7 +41,7 @@ protected:
BumpPtrAllocator Allocator;
};
-}
+} // namespace
TEST_F(MSFBuilderTest, ValidateSuperBlockAccept) {
// Test that a known good super block passes validation.
@@ -359,3 +362,36 @@ TEST_F(MSFBuilderTest, DirectoryBlockHintOverestimated) {
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)));
+ }
+}
diff --git a/unittests/DebugInfo/MSF/MSFCommonTest.cpp b/unittests/DebugInfo/MSF/MSFCommonTest.cpp
new file mode 100644
index 000000000000..144f5b113fb5
--- /dev/null
+++ b/unittests/DebugInfo/MSF/MSFCommonTest.cpp
@@ -0,0 +1,104 @@
+//===- 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]);
+}
diff --git a/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp b/unittests/DebugInfo/MSF/MappedBlockStreamTest.cpp
index a9a1ee4d65b9..639536e94be9 100644
--- a/unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp
+++ b/unittests/DebugInfo/MSF/MappedBlockStreamTest.cpp
@@ -1,4 +1,4 @@
-//===- llvm/unittest/DebugInfo/PDB/MappedBlockStreamTest.cpp --------------===//
+//===- llvm/unittest/DebugInfo/MSF/MappedBlockStreamTest.cpp --------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -8,18 +8,15 @@
//===----------------------------------------------------------------------===//
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
-#include "llvm/DebugInfo/MSF/IMSFFile.h"
-#include "llvm/DebugInfo/MSF/MSFError.h"
-#include "llvm/DebugInfo/MSF/MSFStreamLayout.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/BinaryStreamRef.h"
#include "llvm/Support/BinaryStreamWriter.h"
#include "llvm/Testing/Support/Error.h"
+#include "gmock/gmock.h"
#include "gtest/gtest.h"
-#include <unordered_map>
using namespace llvm;
using namespace llvm::msf;
@@ -42,7 +39,7 @@ public:
Error readBytes(uint32_t Offset, uint32_t Size,
ArrayRef<uint8_t> &Buffer) override {
- if (auto EC = checkOffset(Offset, Size))
+ if (auto EC = checkOffsetForRead(Offset, Size))
return EC;
Buffer = Data.slice(Offset, Size);
return Error::success();
@@ -50,7 +47,7 @@ public:
Error readLongestContiguousChunk(uint32_t Offset,
ArrayRef<uint8_t> &Buffer) override {
- if (auto EC = checkOffset(Offset, 1))
+ if (auto EC = checkOffsetForRead(Offset, 1))
return EC;
Buffer = Data.drop_front(Offset);
return Error::success();
@@ -59,7 +56,7 @@ public:
uint32_t getLength() override { return Data.size(); }
Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> SrcData) override {
- if (auto EC = checkOffset(Offset, SrcData.size()))
+ if (auto EC = checkOffsetForWrite(Offset, SrcData.size()))
return EC;
::memcpy(&Data[Offset], SrcData.data(), SrcData.size());
return Error::success();
@@ -83,7 +80,6 @@ TEST(MappedBlockStreamTest, NumBlocks) {
F.Allocator);
EXPECT_EQ(F.block_size(), S->getBlockSize());
EXPECT_EQ(F.layout().Blocks.size(), S->getNumBlocks());
-
}
// Tests that a read which is entirely contained within a single block works
@@ -255,8 +251,6 @@ TEST(MappedBlockStreamTest, WriteBeyondEndOfStream) {
DiscontiguousStream F(BlocksAry, Data);
auto S = WritableMappedBlockStream::createStream(F.block_size(), F.layout(),
F, F.Allocator);
- ArrayRef<uint8_t> Buffer;
-
EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>(LargeBuffer)), Failed());
EXPECT_THAT_ERROR(S->writeBytes(0, ArrayRef<uint8_t>(SmallBuffer)),
Succeeded());
@@ -335,7 +329,7 @@ TEST(MappedBlockStreamTest, TestWriteThenRead) {
uint8_t byteArray1[] = {'0', '0'};
ArrayRef<uint8_t> byteArrayRef0(byteArray0);
ArrayRef<uint8_t> byteArrayRef1(byteArray1);
- ArrayRef<uint8_t> byteArray[] = { byteArrayRef0, byteArrayRef1 };
+ ArrayRef<uint8_t> byteArray[] = {byteArrayRef0, byteArrayRef1};
uint32_t intArr0[] = {890723408, 29082234};
uint32_t intArr1[] = {890723408, 29082234};
ArrayRef<uint32_t> intArray[] = {intArr0, intArr1};
@@ -496,5 +490,59 @@ TEST(MappedBlockStreamTest, DataLivesAfterStreamDestruction) {
EXPECT_EQ(Str[0], Str[1]);
}
+} // namespace
+
+MATCHER_P3(BlockIsFilledWith, Layout, BlockIndex, Byte, "succeeded") {
+ uint64_t Offset = msf::blockToOffset(BlockIndex, Layout.SB->BlockSize);
+ ArrayRef<uint8_t> BufferRef = makeArrayRef(arg);
+ BufferRef = BufferRef.slice(Offset, Layout.SB->BlockSize);
+ return llvm::all_of(BufferRef, [this](uint8_t B) { return B == Byte; });
+}
+
+namespace {
+TEST(MappedBlockStreamTest, CreateFpmStream) {
+ BumpPtrAllocator Allocator;
+ SuperBlock SB;
+ MSFLayout L;
+ L.SB = &SB;
+
+ SB.FreeBlockMapBlock = 1;
+ SB.BlockSize = 4096;
+
+ constexpr uint32_t NumFileBlocks = 4096 * 4;
+
+ std::vector<uint8_t> MsfBuffer(NumFileBlocks * SB.BlockSize);
+ MutableBinaryByteStream MsfStream(MsfBuffer, llvm::support::little);
+
+ SB.NumBlocks = NumFileBlocks;
+ auto FpmStream =
+ WritableMappedBlockStream::createFpmStream(L, MsfStream, Allocator);
+ // 4096 * 4 / 8 = 2048 bytes of FPM data is needed to describe 4096 * 4
+ // blocks. This translates to 1 FPM block.
+ EXPECT_EQ(2048u, FpmStream->getLength());
+ EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks.size());
+ EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks[0]);
+ // All blocks from FPM1 should be 1 initialized, and all blocks from FPM2
+ // should be 0 initialized (since we requested the main FPM, not the alt FPM)
+ for (int I = 0; I < 4; ++I) {
+ EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 1 + I * SB.BlockSize, 0xFF));
+ EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 2 + I * SB.BlockSize, 0));
+ }
+
+ ::memset(MsfBuffer.data(), 0, MsfBuffer.size());
+ FpmStream =
+ WritableMappedBlockStream::createFpmStream(L, MsfStream, Allocator, true);
+ // 4096 * 4 / 8 = 2048 bytes of FPM data is needed to describe 4096 * 4
+ // blocks. This translates to 1 FPM block.
+ EXPECT_EQ(2048u, FpmStream->getLength());
+ EXPECT_EQ(1u, FpmStream->getStreamLayout().Blocks.size());
+ EXPECT_EQ(2u, FpmStream->getStreamLayout().Blocks[0]);
+ // All blocks from FPM2 should be 1 initialized, and all blocks from FPM1
+ // should be 0 initialized (since we requested the alt FPM, not the main FPM)
+ for (int I = 0; I < 4; ++I) {
+ EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 1 + I * SB.BlockSize, 0));
+ EXPECT_THAT(MsfBuffer, BlockIsFilledWith(L, 2 + I * SB.BlockSize, 0xFF));
+ }
+}
} // end anonymous namespace
diff --git a/unittests/DebugInfo/PDB/CMakeLists.txt b/unittests/DebugInfo/PDB/CMakeLists.txt
index 583b065f464c..b19ee2cf43a5 100644
--- a/unittests/DebugInfo/PDB/CMakeLists.txt
+++ b/unittests/DebugInfo/PDB/CMakeLists.txt
@@ -6,9 +6,7 @@ set(LLVM_LINK_COMPONENTS
set(DebugInfoPDBSources
HashTableTest.cpp
- MappedBlockStreamTest.cpp
StringTableBuilderTest.cpp
- MSFBuilderTest.cpp
PDBApiTest.cpp
)
@@ -16,4 +14,4 @@ add_llvm_unittest(DebugInfoPDBTests
${DebugInfoPDBSources}
)
-target_link_libraries(DebugInfoPDBTests LLVMTestingSupport)
+target_link_libraries(DebugInfoPDBTests PRIVATE LLVMTestingSupport)
diff --git a/unittests/DebugInfo/PDB/PDBApiTest.cpp b/unittests/DebugInfo/PDB/PDBApiTest.cpp
index 257a8879e439..e998acf009ec 100644
--- a/unittests/DebugInfo/PDB/PDBApiTest.cpp
+++ b/unittests/DebugInfo/PDB/PDBApiTest.cpp
@@ -14,6 +14,7 @@
#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"
@@ -118,6 +119,10 @@ class MockSession : public IPDBSession {
std::unique_ptr<IPDBEnumDataStreams> getDebugStreams() const override {
return nullptr;
}
+
+ std::unique_ptr<IPDBEnumTables> getEnumTables() const override {
+ return nullptr;
+ }
};
class MockRawSymbol : public IPDBRawSymbol {
@@ -152,6 +157,10 @@ public:
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)