blob: dedcf816cf63f32601bf8c894c7d9dbc8ba9a21a [file] [log] [blame]
//===- 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<StringMap<std::unique_ptr<MemoryBuffer>>> 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<DWARFDebugNames::Entry> FirstNameEntries =
to_vector_of<DWARFDebugNames::Entry>(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<DWARFDebugNames::Entry> SecondNameEntries =
to_vector_of<DWARFDebugNames::Entry>(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<StringMap<std::unique_ptr<MemoryBuffer>>> 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<DWARFDebugNames::Entry> Name1Entries =
to_vector_of<DWARFDebugNames::Entry>(NameIndex.equal_range("Name1"));
ASSERT_EQ(Name1Entries.size(), 1u);
Expected<std::optional<DWARFDebugNames::Entry>> Name1Parent =
Name1Entries[0].getParentDIEEntry();
ASSERT_THAT_EXPECTED(Name1Parent, Succeeded());
ASSERT_EQ(*Name1Parent, std::nullopt); // Name1 has no parent
SmallVector<DWARFDebugNames::Entry> Name2Entries =
to_vector_of<DWARFDebugNames::Entry>(NameIndex.equal_range("Name2"));
ASSERT_EQ(Name2Entries.size(), 1u);
Expected<std::optional<DWARFDebugNames::Entry>> Name2Parent =
Name2Entries[0].getParentDIEEntry();
ASSERT_THAT_EXPECTED(Name2Parent, Succeeded());
ASSERT_EQ((**Name2Parent).getDIEUnitOffset(), 0x0); // Name2 parent == Name1
SmallVector<DWARFDebugNames::Entry> Name3Entries =
to_vector_of<DWARFDebugNames::Entry>(NameIndex.equal_range("Name3"));
ASSERT_EQ(Name3Entries.size(), 1u);
Expected<std::optional<DWARFDebugNames::Entry>> Name3Parent =
Name3Entries[0].getParentDIEEntry();
ASSERT_THAT_EXPECTED(Name3Parent, Succeeded());
ASSERT_EQ((**Name3Parent).getDIEUnitOffset(), 0x1); // Name3 parent == Name2
SmallVector<DWARFDebugNames::Entry> Name4Entries =
to_vector_of<DWARFDebugNames::Entry>(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<StringMap<std::unique_ptr<MemoryBuffer>>> 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<StringMap<std::unique_ptr<MemoryBuffer>>> 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<StringMap<std::unique_ptr<MemoryBuffer>>> Sections =
DWARFYAML::emitDebugSections(Yamldata,
/*IsLittleEndian=*/true,
/*Is64BitAddrSize=*/true);
ASSERT_THAT_EXPECTED(
Sections,
FailedWithMessage("unsupported Form for YAML debug_names emitter"));
}
} // end anonymous namespace