[llvm] a8b4c11 - [DWARFYAML] Implement debug_names support (#79666)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 12 09:24:49 PST 2024
Author: Felipe de Azevedo Piovezan
Date: 2024-02-12T09:24:46-08:00
New Revision: a8b4c11f9d51f3d735f76c98367c87d6ff328a32
URL: https://github.com/llvm/llvm-project/commit/a8b4c11f9d51f3d735f76c98367c87d6ff328a32
DIFF: https://github.com/llvm/llvm-project/commit/a8b4c11f9d51f3d735f76c98367c87d6ff328a32.diff
LOG: [DWARFYAML] Implement debug_names support (#79666)
This commit brings support for debug_names in DWARFYAML. It parses YAML
and generates emits a DWARF5 Accelerator table with the following
limitations:
1. All forms must have a fixed length (zero length is also ok).
2. Hard-coded support for DWARF 5 and DWARF32.
3. The generated table does not contain a hash index
All of these limitations can be lifted in the future, but for now this
is good enough to enable testing.
Added:
Modified:
llvm/include/llvm/ObjectYAML/DWARFEmitter.h
llvm/include/llvm/ObjectYAML/DWARFYAML.h
llvm/lib/ObjectYAML/DWARFEmitter.cpp
llvm/lib/ObjectYAML/DWARFYAML.cpp
llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ObjectYAML/DWARFEmitter.h b/llvm/include/llvm/ObjectYAML/DWARFEmitter.h
index ee421b2efc72bc..5e1b88f4fef649 100644
--- a/llvm/include/llvm/ObjectYAML/DWARFEmitter.h
+++ b/llvm/include/llvm/ObjectYAML/DWARFEmitter.h
@@ -42,6 +42,7 @@ Error emitDebugAddr(raw_ostream &OS, const Data &DI);
Error emitDebugStrOffsets(raw_ostream &OS, const Data &DI);
Error emitDebugRnglists(raw_ostream &OS, const Data &DI);
Error emitDebugLoclists(raw_ostream &OS, const Data &DI);
+Error emitDebugNames(raw_ostream &OS, const Data &DI);
std::function<Error(raw_ostream &, const Data &)>
getDWARFEmitterByName(StringRef SecName);
diff --git a/llvm/include/llvm/ObjectYAML/DWARFYAML.h b/llvm/include/llvm/ObjectYAML/DWARFYAML.h
index a70ddf3a180a2d..0b3bea786d31c7 100644
--- a/llvm/include/llvm/ObjectYAML/DWARFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/DWARFYAML.h
@@ -118,6 +118,28 @@ struct Unit {
std::vector<Entry> Entries;
};
+struct IdxForm {
+ dwarf::Index Idx;
+ dwarf::Form Form;
+};
+
+struct DebugNameAbbreviation {
+ yaml::Hex64 Code;
+ dwarf::Tag Tag;
+ std::vector<IdxForm> Indices;
+};
+
+struct DebugNameEntry {
+ yaml::Hex32 NameStrp;
+ yaml::Hex64 Code;
+ std::vector<yaml::Hex64> Values;
+};
+
+struct DebugNamesSection {
+ std::vector<DebugNameAbbreviation> Abbrevs;
+ std::vector<DebugNameEntry> Entries;
+};
+
struct File {
StringRef Name;
uint64_t DirIdx;
@@ -228,6 +250,7 @@ struct Data {
std::vector<LineTable> DebugLines;
std::optional<std::vector<ListTable<RnglistEntry>>> DebugRnglists;
std::optional<std::vector<ListTable<LoclistEntry>>> DebugLoclists;
+ std::optional<DebugNamesSection> DebugNames;
bool isEmpty() const;
@@ -276,6 +299,9 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(
llvm::DWARFYAML::ListEntries<DWARFYAML::LoclistEntry>)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::LoclistEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::DWARFOperation)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::DebugNameEntry)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::DebugNameAbbreviation)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::DWARFYAML::IdxForm)
namespace llvm {
namespace yaml {
@@ -324,6 +350,19 @@ template <> struct MappingTraits<DWARFYAML::Unit> {
static void mapping(IO &IO, DWARFYAML::Unit &Unit);
};
+template <> struct MappingTraits<DWARFYAML::DebugNamesSection> {
+ static void mapping(IO &IO, DWARFYAML::DebugNamesSection &);
+};
+template <> struct MappingTraits<DWARFYAML::DebugNameEntry> {
+ static void mapping(IO &IO, DWARFYAML::DebugNameEntry &);
+};
+template <> struct MappingTraits<DWARFYAML::DebugNameAbbreviation> {
+ static void mapping(IO &IO, DWARFYAML::DebugNameAbbreviation &);
+};
+template <> struct MappingTraits<DWARFYAML::IdxForm> {
+ static void mapping(IO &IO, DWARFYAML::IdxForm &);
+};
+
template <> struct MappingTraits<DWARFYAML::Entry> {
static void mapping(IO &IO, DWARFYAML::Entry &Entry);
};
@@ -437,6 +476,16 @@ template <> struct ScalarEnumerationTraits<dwarf::Form> {
}
};
+#define HANDLE_DW_IDX(unused, name) \
+ io.enumCase(value, "DW_IDX_" #name, dwarf::DW_IDX_##name);
+
+template <> struct ScalarEnumerationTraits<dwarf::Index> {
+ static void enumeration(IO &io, dwarf::Index &value) {
+#include "llvm/BinaryFormat/Dwarf.def"
+ io.enumFallback<Hex16>(value);
+ }
+};
+
#define HANDLE_DW_UT(unused, name) \
io.enumCase(value, "DW_UT_" #name, dwarf::DW_UT_##name);
diff --git a/llvm/lib/ObjectYAML/DWARFEmitter.cpp b/llvm/lib/ObjectYAML/DWARFEmitter.cpp
index a26e93f65ed7c5..39195bf63f2f46 100644
--- a/llvm/lib/ObjectYAML/DWARFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/DWARFEmitter.cpp
@@ -691,6 +691,194 @@ Error DWARFYAML::emitDebugStrOffsets(raw_ostream &OS, const Data &DI) {
return Error::success();
}
+namespace {
+/// Emits the header for a DebugNames section.
+void emitDebugNamesHeader(raw_ostream &OS, bool IsLittleEndian,
+ uint32_t NameCount, uint32_t AbbrevSize,
+ uint32_t CombinedSizeOtherParts) {
+ // Use the same AugmentationString as AsmPrinter.
+ StringRef AugmentationString = "LLVM0700";
+ size_t TotalSize = CombinedSizeOtherParts + 5 * sizeof(uint32_t) +
+ 2 * sizeof(uint16_t) + sizeof(NameCount) +
+ sizeof(AbbrevSize) + AugmentationString.size();
+ writeInteger(uint32_t(TotalSize), OS, IsLittleEndian); // Unit length
+
+ // Everything below is included in total size.
+ writeInteger(uint16_t(5), OS, IsLittleEndian); // Version
+ writeInteger(uint16_t(0), OS, IsLittleEndian); // Padding
+ writeInteger(uint32_t(1), OS, IsLittleEndian); // Compilation Unit count
+ writeInteger(uint32_t(0), OS, IsLittleEndian); // Local Type Unit count
+ writeInteger(uint32_t(0), OS, IsLittleEndian); // Foreign Type Unit count
+ writeInteger(uint32_t(0), OS, IsLittleEndian); // Bucket count
+ writeInteger(NameCount, OS, IsLittleEndian);
+ writeInteger(AbbrevSize, OS, IsLittleEndian);
+ writeInteger(uint32_t(AugmentationString.size()), OS, IsLittleEndian);
+ OS.write(AugmentationString.data(), AugmentationString.size());
+ return;
+}
+
+/// Emits the abbreviations for a DebugNames section.
+std::string
+emitDebugNamesAbbrev(ArrayRef<DWARFYAML::DebugNameAbbreviation> Abbrevs) {
+ std::string Data;
+ raw_string_ostream OS(Data);
+ for (const DWARFYAML::DebugNameAbbreviation &Abbrev : Abbrevs) {
+ encodeULEB128(Abbrev.Code, OS);
+ encodeULEB128(Abbrev.Tag, OS);
+ for (auto [Idx, Form] : Abbrev.Indices) {
+ encodeULEB128(Idx, OS);
+ encodeULEB128(Form, OS);
+ }
+ encodeULEB128(0, OS);
+ encodeULEB128(0, OS);
+ }
+ encodeULEB128(0, OS);
+ return Data;
+}
+
+/// Emits a simple CU offsets list for a DebugNames section containing a single
+/// CU at offset 0.
+std::string emitDebugNamesCUOffsets(bool IsLittleEndian) {
+ std::string Data;
+ raw_string_ostream OS(Data);
+ writeInteger(uint32_t(0), OS, IsLittleEndian);
+ return Data;
+}
+
+/// Emits the "NameTable" for a DebugNames section; according to the spec, it
+/// consists of two arrays: an array of string offsets, followed immediately by
+/// an array of entry offsets. The string offsets are emitted in the order
+/// provided in `Entries`.
+std::string emitDebugNamesNameTable(
+ bool IsLittleEndian,
+ const DenseMap<uint32_t, std::vector<DWARFYAML::DebugNameEntry>> &Entries,
+ ArrayRef<uint32_t> EntryPoolOffsets) {
+ assert(Entries.size() == EntryPoolOffsets.size());
+
+ std::string Data;
+ raw_string_ostream OS(Data);
+
+ for (uint32_t Strp : make_first_range(Entries))
+ writeInteger(Strp, OS, IsLittleEndian);
+ for (uint32_t PoolOffset : EntryPoolOffsets)
+ writeInteger(PoolOffset, OS, IsLittleEndian);
+ return Data;
+}
+
+/// Groups entries based on their name (strp) code and returns a map.
+DenseMap<uint32_t, std::vector<DWARFYAML::DebugNameEntry>>
+groupEntries(ArrayRef<DWARFYAML::DebugNameEntry> Entries) {
+ DenseMap<uint32_t, std::vector<DWARFYAML::DebugNameEntry>> StrpToEntries;
+ for (const DWARFYAML::DebugNameEntry &Entry : Entries)
+ StrpToEntries[Entry.NameStrp].push_back(Entry);
+ return StrpToEntries;
+}
+
+/// Finds the abbreviation whose code is AbbrevCode and returns a list
+/// containing the expected size of all non-zero-length forms.
+Expected<SmallVector<uint8_t>>
+getNonZeroDataSizesFor(uint32_t AbbrevCode,
+ ArrayRef<DWARFYAML::DebugNameAbbreviation> Abbrevs) {
+ const auto *AbbrevIt = find_if(Abbrevs, [&](const auto &Abbrev) {
+ return Abbrev.Code.value == AbbrevCode;
+ });
+ if (AbbrevIt == Abbrevs.end())
+ return createStringError(inconvertibleErrorCode(),
+ "did not find an Abbreviation for this code");
+
+ SmallVector<uint8_t> DataSizes;
+ dwarf::FormParams Params{/*Version=*/5, /*AddrSize=*/4, dwarf::DWARF32};
+ for (auto [Idx, Form] : AbbrevIt->Indices) {
+ std::optional<uint8_t> FormSize = dwarf::getFixedFormByteSize(Form, Params);
+ if (!FormSize)
+ return createStringError(inconvertibleErrorCode(),
+ "unsupported Form for YAML debug_names emitter");
+ if (FormSize == 0)
+ continue;
+ DataSizes.push_back(*FormSize);
+ }
+ return DataSizes;
+}
+
+struct PoolOffsetsAndData {
+ std::string PoolData;
+ std::vector<uint32_t> PoolOffsets;
+};
+
+/// Emits the entry pool and returns an array of offsets containing the start
+/// offset for the entries of each unique name.
+/// Verifies that the provided number of data values match those expected by
+/// the abbreviation table.
+Expected<PoolOffsetsAndData> emitDebugNamesEntryPool(
+ bool IsLittleEndian,
+ const DenseMap<uint32_t, std::vector<DWARFYAML::DebugNameEntry>>
+ &StrpToEntries,
+ ArrayRef<DWARFYAML::DebugNameAbbreviation> Abbrevs) {
+ PoolOffsetsAndData Result;
+ raw_string_ostream OS(Result.PoolData);
+
+ for (ArrayRef<DWARFYAML::DebugNameEntry> EntriesWithSameName :
+ make_second_range(StrpToEntries)) {
+ Result.PoolOffsets.push_back(Result.PoolData.size());
+
+ for (const DWARFYAML::DebugNameEntry &Entry : EntriesWithSameName) {
+ encodeULEB128(Entry.Code, OS);
+
+ Expected<SmallVector<uint8_t>> DataSizes =
+ getNonZeroDataSizesFor(Entry.Code, Abbrevs);
+ if (!DataSizes)
+ return DataSizes.takeError();
+ if (DataSizes->size() != Entry.Values.size())
+ return createStringError(
+ inconvertibleErrorCode(),
+ "mismatch between provided and required number of values");
+
+ for (auto [Value, ValueSize] : zip_equal(Entry.Values, *DataSizes))
+ if (Error E =
+ writeVariableSizedInteger(Value, ValueSize, OS, IsLittleEndian))
+ return std::move(E);
+ }
+ encodeULEB128(0, OS);
+ }
+
+ return Result;
+}
+} // namespace
+
+Error DWARFYAML::emitDebugNames(raw_ostream &OS, const Data &DI) {
+ assert(DI.DebugNames && "unexpected emitDebugNames() call");
+ const DebugNamesSection DebugNames = DI.DebugNames.value();
+
+ DenseMap<uint32_t, std::vector<DebugNameEntry>> StrpToEntries =
+ groupEntries(DebugNames.Entries);
+
+ // Emit all sub-sections into individual strings so that we may compute
+ // relative offsets and sizes.
+ Expected<PoolOffsetsAndData> PoolInfo = emitDebugNamesEntryPool(
+ DI.IsLittleEndian, StrpToEntries, DebugNames.Abbrevs);
+ if (!PoolInfo)
+ return PoolInfo.takeError();
+ std::string NamesTableData = emitDebugNamesNameTable(
+ DI.IsLittleEndian, StrpToEntries, PoolInfo->PoolOffsets);
+
+ std::string AbbrevData = emitDebugNamesAbbrev(DebugNames.Abbrevs);
+ std::string CUOffsetsData = emitDebugNamesCUOffsets(DI.IsLittleEndian);
+
+ size_t TotalSize = PoolInfo->PoolData.size() + NamesTableData.size() +
+ AbbrevData.size() + CUOffsetsData.size();
+
+ // Start real emission by combining all individual strings.
+ emitDebugNamesHeader(OS, DI.IsLittleEndian, StrpToEntries.size(),
+ AbbrevData.size(), TotalSize);
+ OS.write(CUOffsetsData.data(), CUOffsetsData.size());
+ // No local TUs, no foreign TUs, no hash lookups table.
+ OS.write(NamesTableData.data(), NamesTableData.size());
+ OS.write(AbbrevData.data(), AbbrevData.size());
+ OS.write(PoolInfo->PoolData.data(), PoolInfo->PoolData.size());
+
+ return Error::success();
+}
+
static Error checkOperandCount(StringRef EncodingString,
ArrayRef<yaml::Hex64> Values,
uint64_t ExpectedOperands) {
@@ -1024,6 +1212,7 @@ DWARFYAML::getDWARFEmitterByName(StringRef SecName) {
.Case("debug_rnglists", DWARFYAML::emitDebugRnglists)
.Case("debug_str", DWARFYAML::emitDebugStr)
.Case("debug_str_offsets", DWARFYAML::emitDebugStrOffsets)
+ .Case("debug_names", DWARFYAML::emitDebugNames)
.Default([&](raw_ostream &, const DWARFYAML::Data &) {
return createStringError(errc::not_supported,
SecName + " is not supported");
diff --git a/llvm/lib/ObjectYAML/DWARFYAML.cpp b/llvm/lib/ObjectYAML/DWARFYAML.cpp
index 2bddeed4641353..5207671f57d930 100644
--- a/llvm/lib/ObjectYAML/DWARFYAML.cpp
+++ b/llvm/lib/ObjectYAML/DWARFYAML.cpp
@@ -52,6 +52,8 @@ SetVector<StringRef> DWARFYAML::Data::getNonEmptySectionNames() const {
SecNames.insert("debug_rnglists");
if (DebugLoclists)
SecNames.insert("debug_loclists");
+ if (DebugNames)
+ SecNames.insert("debug_names");
return SecNames;
}
@@ -105,6 +107,7 @@ void MappingTraits<DWARFYAML::Data>::mapping(IO &IO, DWARFYAML::Data &DWARF) {
IO.mapOptional("debug_str_offsets", DWARF.DebugStrOffsets);
IO.mapOptional("debug_rnglists", DWARF.DebugRnglists);
IO.mapOptional("debug_loclists", DWARF.DebugLoclists);
+ IO.mapOptional("debug_names", DWARF.DebugNames);
IO.setContext(OldContext);
}
@@ -122,6 +125,32 @@ void MappingTraits<DWARFYAML::Abbrev>::mapping(IO &IO,
IO.mapOptional("Attributes", Abbrev.Attributes);
}
+void MappingTraits<DWARFYAML::IdxForm>::mapping(IO &IO,
+ DWARFYAML::IdxForm &IdxForm) {
+ IO.mapRequired("Idx", IdxForm.Idx);
+ IO.mapRequired("Form", IdxForm.Form);
+}
+
+void MappingTraits<DWARFYAML::DebugNameAbbreviation>::mapping(
+ IO &IO, DWARFYAML::DebugNameAbbreviation &DebugNameAbbreviation) {
+ IO.mapRequired("Code", DebugNameAbbreviation.Code);
+ IO.mapRequired("Tag", DebugNameAbbreviation.Tag);
+ IO.mapRequired("Indices", DebugNameAbbreviation.Indices);
+}
+
+void MappingTraits<DWARFYAML::DebugNameEntry>::mapping(
+ IO &IO, DWARFYAML::DebugNameEntry &DebugNameEntry) {
+ IO.mapRequired("Name", DebugNameEntry.NameStrp);
+ IO.mapRequired("Code", DebugNameEntry.Code);
+ IO.mapOptional("Values", DebugNameEntry.Values);
+}
+
+void MappingTraits<DWARFYAML::DebugNamesSection>::mapping(
+ IO &IO, DWARFYAML::DebugNamesSection &DebugNames) {
+ IO.mapRequired("Abbreviations", DebugNames.Abbrevs);
+ IO.mapRequired("Entries", DebugNames.Entries);
+}
+
void MappingTraits<DWARFYAML::AttributeAbbrev>::mapping(
IO &IO, DWARFYAML::AttributeAbbrev &AttAbbrev) {
IO.mapRequired("Attribute", AttAbbrev.Attribute);
diff --git a/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp b/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp
index 38f3e076ace213..dedcf816cf63f3 100644
--- a/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp
+++ b/llvm/unittests/DebugInfo/DWARF/DWARFAcceleratorTableTest.cpp
@@ -8,6 +8,7 @@
#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"
@@ -46,4 +47,256 @@ TEST(DWARFDebugNames, TooSmallForDWARF64) {
"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
More information about the llvm-commits
mailing list