//===- DWARFAcceleratorTableTest.cpp --------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/ObjectYAML/DWARFEmitter.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" using namespace llvm; static Error ExtractDebugNames(StringRef NamesSecData, StringRef StrSecData) { DWARFDataExtractor NamesExtractor(NamesSecData, /*isLittleEndian=*/true, /*AddrSize=*/4); DataExtractor StrExtractor(StrSecData, /*isLittleEndian=*/true, /*AddrSize=*/4); DWARFDebugNames Table(NamesExtractor, StrExtractor); return Table.extract(); } namespace { TEST(DWARFDebugNames, ReservedUnitLength) { static const char NamesSecData[64] = "\xf0\xff\xff\xff"; // Reserved unit length value EXPECT_THAT_ERROR( ExtractDebugNames(StringRef(NamesSecData, sizeof(NamesSecData)), StringRef()), FailedWithMessage("parsing .debug_names header at 0x0: unsupported " "reserved unit length of value 0xfffffff0")); } TEST(DWARFDebugNames, TooSmallForDWARF64) { // DWARF64 header takes at least 44 bytes. static const char NamesSecData[43] = "\xff\xff\xff\xff"; // DWARF64 mark EXPECT_THAT_ERROR( ExtractDebugNames(StringRef(NamesSecData, sizeof(NamesSecData)), StringRef()), FailedWithMessage("parsing .debug_names header at 0x0: unexpected end of " "data at offset 0x2b while reading [0x28, 0x2c)")); } TEST(DWARFDebugNames, BasicTestEntries) { const char *Yamldata = R"( --- !ELF debug_str: - 'NameType1' - 'NameType2' debug_names: Abbreviations: - Code: 0x1 Tag: DW_TAG_namespace Indices: - Idx: DW_IDX_compile_unit Form: DW_FORM_data4 - Idx: DW_IDX_die_offset Form: DW_FORM_ref4 Entries: - Name: 0x0 # strp to NameType1 Code: 0x1 Values: - 0x0 # Compile unit - 0x0 # DIE Offset - Name: 0xa # strp to NameType2 Code: 0x1 Values: - 0x1 # Compile unit - 0x1 # DIE Offset - Name: 0x0 # strp to NameType1 Code: 0x1 Values: - 0x2 # Compile unit - 0x2 # DIE Offset )"; Expected>> Sections = DWARFYAML::emitDebugSections(Yamldata, /*IsLittleEndian=*/true, /*Is64BitAddrSize=*/true); ASSERT_THAT_EXPECTED(Sections, Succeeded()); auto Ctx = DWARFContext::create(*Sections, 4, /*isLittleEndian=*/true); const DWARFDebugNames &DebugNames = Ctx->getDebugNames(); ASSERT_NE(DebugNames.begin(), DebugNames.end()); const DWARFDebugNames::NameIndex &NameIndex = *DebugNames.begin(); ASSERT_EQ(NameIndex.getNameCount(), 2u); ASSERT_EQ(NameIndex.getBucketCount(), 0u); ASSERT_EQ(NameIndex.getCUCount(), 1u); ASSERT_EQ(NameIndex.getCUOffset(0), 0u); ASSERT_EQ(NameIndex.getForeignTUCount(), 0u); ASSERT_EQ(NameIndex.getLocalTUCount(), 0u); // Check "NameEntries": there should be one per unique name. // These are indexed starting on 1. DWARFDebugNames::NameTableEntry FirstEntry = NameIndex.getNameTableEntry(1); ASSERT_EQ(FirstEntry.getString(), StringRef("NameType1")); DWARFDebugNames::NameTableEntry SecondEntry = NameIndex.getNameTableEntry(2); ASSERT_EQ(SecondEntry.getString(), StringRef("NameType2")); SmallVector FirstNameEntries = to_vector_of(NameIndex.equal_range("NameType1")); ASSERT_EQ(FirstNameEntries.size(), 2u); ASSERT_EQ(FirstNameEntries[0].getCUIndex(), 0u); ASSERT_EQ(FirstNameEntries[1].getCUIndex(), 0x2); ASSERT_EQ(FirstNameEntries[0].getDIEUnitOffset(), 0x0); ASSERT_EQ(FirstNameEntries[1].getDIEUnitOffset(), 0x2); SmallVector SecondNameEntries = to_vector_of(NameIndex.equal_range("NameType2")); ASSERT_EQ(SecondNameEntries.size(), 1u); ASSERT_EQ(SecondNameEntries[0].getCUIndex(), 0x1); ASSERT_EQ(SecondNameEntries[0].getDIEUnitOffset(), 0x1); } TEST(DWARFDebugNames, ParentEntries) { const char *Yamldata = R"( --- !ELF debug_str: - 'Name1' - 'Name2' - 'Name3' - 'Name4' debug_names: Abbreviations: - Code: 0x11 Tag: DW_TAG_namespace Indices: - Idx: DW_IDX_parent Form: DW_FORM_flag_present - Idx: DW_IDX_die_offset Form: DW_FORM_ref4 - Code: 0x22 Tag: DW_TAG_namespace Indices: - Idx: DW_IDX_parent Form: DW_FORM_ref4 - Idx: DW_IDX_die_offset Form: DW_FORM_ref4 - Code: 0x33 Tag: DW_TAG_namespace Indices: - Idx: DW_IDX_die_offset Form: DW_FORM_ref4 Entries: - Name: 0x0 # strp to Name1 Code: 0x11 Values: - 0x0 # Die offset - Name: 0x6 # strp to Name2 Code: 0x22 Values: - 0x0 # Parent = First entry - 0x1 # Die offset - Name: 0xc # strp to Name3 Code: 0x22 Values: - 0x6 # Parent = Second entry - 0x1 # Die offset - Name: 0x12 # strp to Name4 Code: 0x33 Values: - 0x1 # Die offset )"; Expected>> Sections = DWARFYAML::emitDebugSections(Yamldata, /*IsLittleEndian=*/true, /*Is64BitAddrSize=*/true); ASSERT_THAT_EXPECTED(Sections, Succeeded()); auto Ctx = DWARFContext::create(*Sections, 4, /*isLittleEndian=*/true); const DWARFDebugNames &DebugNames = Ctx->getDebugNames(); ASSERT_NE(DebugNames.begin(), DebugNames.end()); const DWARFDebugNames::NameIndex &NameIndex = *DebugNames.begin(); SmallVector Name1Entries = to_vector_of(NameIndex.equal_range("Name1")); ASSERT_EQ(Name1Entries.size(), 1u); Expected> Name1Parent = Name1Entries[0].getParentDIEEntry(); ASSERT_THAT_EXPECTED(Name1Parent, Succeeded()); ASSERT_EQ(*Name1Parent, std::nullopt); // Name1 has no parent SmallVector Name2Entries = to_vector_of(NameIndex.equal_range("Name2")); ASSERT_EQ(Name2Entries.size(), 1u); Expected> Name2Parent = Name2Entries[0].getParentDIEEntry(); ASSERT_THAT_EXPECTED(Name2Parent, Succeeded()); ASSERT_EQ((**Name2Parent).getDIEUnitOffset(), 0x0); // Name2 parent == Name1 SmallVector Name3Entries = to_vector_of(NameIndex.equal_range("Name3")); ASSERT_EQ(Name3Entries.size(), 1u); Expected> Name3Parent = Name3Entries[0].getParentDIEEntry(); ASSERT_THAT_EXPECTED(Name3Parent, Succeeded()); ASSERT_EQ((**Name3Parent).getDIEUnitOffset(), 0x1); // Name3 parent == Name2 SmallVector Name4Entries = to_vector_of(NameIndex.equal_range("Name4")); ASSERT_EQ(Name4Entries.size(), 1u); ASSERT_FALSE(Name4Entries[0].hasParentInformation()); } TEST(DWARFDebugNames, InvalidAbbrevCode) { const char *Yamldata = R"( --- !ELF debug_str: - 'NameType1' debug_names: Abbreviations: - Code: 0x1 Tag: DW_TAG_namespace Indices: - Idx: DW_IDX_compile_unit Form: DW_FORM_data4 Entries: - Name: 0x0 # strp to NameType1 Code: 0x123456 Values: - 0x0 # Compile unit )"; Expected>> Sections = DWARFYAML::emitDebugSections(Yamldata, /*IsLittleEndian=*/true, /*Is64BitAddrSize=*/true); ASSERT_THAT_EXPECTED( Sections, FailedWithMessage("did not find an Abbreviation for this code")); } TEST(DWARFDebugNames, InvalidNumOfValues) { const char *Yamldata = R"( --- !ELF debug_str: - 'NameType1' debug_names: Abbreviations: - Code: 0x1 Tag: DW_TAG_namespace Indices: - Idx: DW_IDX_compile_unit Form: DW_FORM_data4 Entries: - Name: 0x0 # strp to NameType1 Code: 0x1 Values: - 0x0 # Compile unit - 0x0 # Compile unit - 0x0 # Compile unit )"; Expected>> Sections = DWARFYAML::emitDebugSections(Yamldata, /*IsLittleEndian=*/true, /*Is64BitAddrSize=*/true); ASSERT_THAT_EXPECTED( Sections, FailedWithMessage( "mismatch between provided and required number of values")); } TEST(DWARFDebugNames, UnsupportedForm) { const char *Yamldata = R"( --- !ELF debug_str: - 'NameType1' debug_names: Abbreviations: - Code: 0x1 Tag: DW_TAG_namespace Indices: - Idx: DW_IDX_compile_unit Form: DW_FORM_strx Entries: - Name: 0x0 # strp to NameType1 Code: 0x1 Values: - 0x0 # Compile unit )"; Expected>> Sections = DWARFYAML::emitDebugSections(Yamldata, /*IsLittleEndian=*/true, /*Is64BitAddrSize=*/true); ASSERT_THAT_EXPECTED( Sections, FailedWithMessage("unsupported Form for YAML debug_names emitter")); } } // end anonymous namespace