diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 | 
| commit | 044eb2f6afba375a914ac9d8024f8f5142bb912e (patch) | |
| tree | 1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /unittests/DebugInfo | |
| parent | eb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff) | |
Notes
Diffstat (limited to 'unittests/DebugInfo')
| -rw-r--r-- | unittests/DebugInfo/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | unittests/DebugInfo/CodeView/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | unittests/DebugInfo/CodeView/RandomAccessVisitorTest.cpp | 14 | ||||
| -rw-r--r-- | unittests/DebugInfo/CodeView/TypeHashingTest.cpp | 156 | ||||
| -rw-r--r-- | unittests/DebugInfo/CodeView/TypeIndexDiscoveryTest.cpp | 50 | ||||
| -rw-r--r-- | unittests/DebugInfo/DWARF/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | unittests/DebugInfo/DWARF/DWARFDebugInfoTest.cpp | 992 | ||||
| -rw-r--r-- | unittests/DebugInfo/DWARF/DWARFFormValueTest.cpp | 18 | ||||
| -rw-r--r-- | unittests/DebugInfo/DWARF/DwarfGenerator.cpp | 15 | ||||
| -rw-r--r-- | unittests/DebugInfo/MSF/CMakeLists.txt | 15 | ||||
| -rw-r--r-- | unittests/DebugInfo/MSF/MSFBuilderTest.cpp (renamed from unittests/DebugInfo/PDB/MSFBuilderTest.cpp) | 38 | ||||
| -rw-r--r-- | unittests/DebugInfo/MSF/MSFCommonTest.cpp | 104 | ||||
| -rw-r--r-- | unittests/DebugInfo/MSF/MappedBlockStreamTest.cpp (renamed from unittests/DebugInfo/PDB/MappedBlockStreamTest.cpp) | 72 | ||||
| -rw-r--r-- | unittests/DebugInfo/PDB/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | unittests/DebugInfo/PDB/PDBApiTest.cpp | 9 | 
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) | 
