diff --git a/llvm/include/llvm/ObjectYAML/DWARFEmitter.h b/llvm/include/llvm/ObjectYAML/DWARFEmitter.h --- a/llvm/include/llvm/ObjectYAML/DWARFEmitter.h +++ b/llvm/include/llvm/ObjectYAML/DWARFEmitter.h @@ -34,7 +34,7 @@ Error emitDebugAranges(raw_ostream &OS, const Data &DI); Error emitDebugRanges(raw_ostream &OS, const Data &DI); Error emitPubSection(raw_ostream &OS, const PubSection &Sect, - bool IsLittleEndian); + bool IsLittleEndian, bool IsGNUPubSec = false); Error emitDebugInfo(raw_ostream &OS, const Data &DI); Error emitDebugLine(raw_ostream &OS, const Data &DI); Error emitDebugAddr(raw_ostream &OS, const Data &DI); diff --git a/llvm/include/llvm/ObjectYAML/DWARFYAML.h b/llvm/include/llvm/ObjectYAML/DWARFYAML.h --- a/llvm/include/llvm/ObjectYAML/DWARFYAML.h +++ b/llvm/include/llvm/ObjectYAML/DWARFYAML.h @@ -98,11 +98,7 @@ uint16_t Version; uint32_t UnitOffset; uint32_t UnitSize; - bool IsGNUStyle = false; std::vector Entries; - - PubSection() = default; - PubSection(bool IsGNUStyle) : IsGNUStyle(IsGNUStyle) {} }; struct FormValue { @@ -116,6 +112,12 @@ std::vector Values; }; +/// Class that contains helpful context information when mapping YAML into DWARF +/// data structures. +struct DWARFContext { + bool IsGNUPubSec = false; +}; + struct Unit { dwarf::DwarfFormat Format; uint64_t Length; diff --git a/llvm/lib/ObjectYAML/DWARFEmitter.cpp b/llvm/lib/ObjectYAML/DWARFEmitter.cpp --- a/llvm/lib/ObjectYAML/DWARFEmitter.cpp +++ b/llvm/lib/ObjectYAML/DWARFEmitter.cpp @@ -188,14 +188,14 @@ Error DWARFYAML::emitPubSection(raw_ostream &OS, const DWARFYAML::PubSection &Sect, - bool IsLittleEndian) { + bool IsLittleEndian, bool IsGNUPubSec) { writeInitialLength(Sect.Length, OS, IsLittleEndian); writeInteger((uint16_t)Sect.Version, OS, IsLittleEndian); writeInteger((uint32_t)Sect.UnitOffset, OS, IsLittleEndian); writeInteger((uint32_t)Sect.UnitSize, OS, IsLittleEndian); for (auto Entry : Sect.Entries) { writeInteger((uint32_t)Entry.DieOffset, OS, IsLittleEndian); - if (Sect.IsGNUStyle) + if (IsGNUPubSec) writeInteger((uint8_t)Entry.Descriptor, OS, IsLittleEndian); OS.write(Entry.Name.data(), Entry.Name.size()); OS.write('\0'); diff --git a/llvm/lib/ObjectYAML/DWARFYAML.cpp b/llvm/lib/ObjectYAML/DWARFYAML.cpp --- a/llvm/lib/ObjectYAML/DWARFYAML.cpp +++ b/llvm/lib/ObjectYAML/DWARFYAML.cpp @@ -48,6 +48,9 @@ namespace yaml { void MappingTraits::mapping(IO &IO, DWARFYAML::Data &DWARF) { + void *OldContext = IO.getContext(); + DWARFYAML::DWARFContext DWARFCtx; + IO.setContext(&DWARFCtx); IO.mapOptional("debug_str", DWARF.DebugStrings); IO.mapOptional("debug_abbrev", DWARF.AbbrevDecls); if (!DWARF.ARanges.empty() || !IO.outputting()) @@ -56,11 +59,13 @@ IO.mapOptional("debug_ranges", DWARF.DebugRanges); IO.mapOptional("debug_pubnames", DWARF.PubNames); IO.mapOptional("debug_pubtypes", DWARF.PubTypes); + DWARFCtx.IsGNUPubSec = true; IO.mapOptional("debug_gnu_pubnames", DWARF.GNUPubNames); IO.mapOptional("debug_gnu_pubtypes", DWARF.GNUPubTypes); IO.mapOptional("debug_info", DWARF.CompileUnits); IO.mapOptional("debug_line", DWARF.DebugLines); IO.mapOptional("debug_addr", DWARF.DebugAddr); + IO.setContext(OldContext); } void MappingTraits::mapping(IO &IO, @@ -112,23 +117,18 @@ void MappingTraits::mapping(IO &IO, DWARFYAML::PubEntry &Entry) { IO.mapRequired("DieOffset", Entry.DieOffset); - if (reinterpret_cast(IO.getContext())->IsGNUStyle) + if (static_cast(IO.getContext())->IsGNUPubSec) IO.mapRequired("Descriptor", Entry.Descriptor); IO.mapRequired("Name", Entry.Name); } void MappingTraits::mapping( IO &IO, DWARFYAML::PubSection &Section) { - auto OldContext = IO.getContext(); - IO.setContext(&Section); - IO.mapRequired("Length", Section.Length); IO.mapRequired("Version", Section.Version); IO.mapRequired("UnitOffset", Section.UnitOffset); IO.mapRequired("UnitSize", Section.UnitSize); IO.mapRequired("Entries", Section.Entries); - - IO.setContext(OldContext); } void MappingTraits::mapping(IO &IO, DWARFYAML::Unit &Unit) { diff --git a/llvm/tools/obj2yaml/dwarf2yaml.cpp b/llvm/tools/obj2yaml/dwarf2yaml.cpp --- a/llvm/tools/obj2yaml/dwarf2yaml.cpp +++ b/llvm/tools/obj2yaml/dwarf2yaml.cpp @@ -122,7 +122,7 @@ bool IsGNUStyle) { DWARFDataExtractor PubSectionData(DCtx.getDWARFObj(), Section, DCtx.isLittleEndian(), 0); - DWARFYAML::PubSection Y(IsGNUStyle); + DWARFYAML::PubSection Y; uint64_t Offset = 0; dumpInitialLength(PubSectionData, Offset, Y.Length); Y.Version = PubSectionData.getU16(&Offset); diff --git a/llvm/unittests/ObjectYAML/DWARFYAMLTest.cpp b/llvm/unittests/ObjectYAML/DWARFYAMLTest.cpp --- a/llvm/unittests/ObjectYAML/DWARFYAMLTest.cpp +++ b/llvm/unittests/ObjectYAML/DWARFYAMLTest.cpp @@ -8,11 +8,36 @@ #include "llvm/ObjectYAML/DWARFYAML.h" #include "llvm/ObjectYAML/DWARFEmitter.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/YAMLTraits.h" #include "llvm/Testing/Support/Error.h" #include "gtest/gtest.h" using namespace llvm; +static Expected parseDWARFYAML(StringRef Yaml, + bool IsLittleEndian = false, + bool Is64bit = true) { + DWARFYAML::Data Data; + Data.IsLittleEndian = IsLittleEndian; + Data.Is64bit = Is64bit; + + SMDiagnostic GenerateDiag; + yaml::Input YIn( + Yaml, /*Ctxt=*/nullptr, + [](const SMDiagnostic &Diag, void *DiagContext) { + *static_cast(DiagContext) = Diag; + }, + &GenerateDiag); + + YIn >> Data; + if (YIn.error()) + return createStringError(YIn.error(), GenerateDiag.getMessage()); + + return Data; +} + TEST(DebugAddrSection, TestParseDebugAddrYAML) { StringRef Yaml = R"( debug_addr: @@ -47,3 +72,140 @@ EXPECT_THAT_ERROR(SectionsOrErr.takeError(), FailedWithMessage("unknown key 'Blah'")); } + +TEST(DebugPubSection, TestDebugPubSection) { + StringRef Yaml = R"( +debug_pubnames: + Length: + TotalLength: 0x1234 + Version: 2 + UnitOffset: 0x4321 + UnitSize: 0x00 + Entries: + - DieOffset: 0x1234 + Name: abc + - DieOffset: 0x4321 + Name: def +debug_pubtypes: + Length: + TotalLength: 0x1234 + Version: 2 + UnitOffset: 0x4321 + UnitSize: 0x00 + Entries: + - DieOffset: 0x1234 + Name: abc + - DieOffset: 0x4321 + Name: def +)"; + auto DWARFOrErr = parseDWARFYAML(Yaml); + ASSERT_THAT_EXPECTED(DWARFOrErr, Succeeded()); + + ASSERT_TRUE(DWARFOrErr->PubNames.hasValue()); + DWARFYAML::PubSection PubNames = DWARFOrErr->PubNames.getValue(); + + ASSERT_EQ(PubNames.Entries.size(), 2u); + EXPECT_EQ((uint32_t)PubNames.Entries[0].DieOffset, 0x1234u); + EXPECT_EQ(PubNames.Entries[0].Name, "abc"); + EXPECT_EQ((uint32_t)PubNames.Entries[1].DieOffset, 0x4321u); + EXPECT_EQ(PubNames.Entries[1].Name, "def"); + + ASSERT_TRUE(DWARFOrErr->PubTypes.hasValue()); + DWARFYAML::PubSection PubTypes = DWARFOrErr->PubTypes.getValue(); + + ASSERT_EQ(PubTypes.Entries.size(), 2u); + EXPECT_EQ((uint32_t)PubTypes.Entries[0].DieOffset, 0x1234u); + EXPECT_EQ(PubTypes.Entries[0].Name, "abc"); + EXPECT_EQ((uint32_t)PubTypes.Entries[1].DieOffset, 0x4321u); + EXPECT_EQ(PubTypes.Entries[1].Name, "def"); +} + +TEST(DebugPubSection, TestUnexpectedDescriptor) { + StringRef Yaml = R"( +debug_pubnames: + Length: + TotalLength: 0x1234 + Version: 2 + UnitOffset: 0x4321 + UnitSize: 0x00 + Entries: + - DieOffset: 0x1234 + Descriptor: 0x12 + Name: abcd +)"; + auto DWARFOrErr = parseDWARFYAML(Yaml); + EXPECT_THAT_ERROR(DWARFOrErr.takeError(), + FailedWithMessage("unknown key 'Descriptor'")); +} + +TEST(DebugGNUPubSection, TestDebugGNUPubSections) { + StringRef Yaml = R"( +debug_gnu_pubnames: + Length: + TotalLength: 0x1234 + Version: 2 + UnitOffset: 0x4321 + UnitSize: 0x00 + Entries: + - DieOffset: 0x1234 + Descriptor: 0x12 + Name: abc + - DieOffset: 0x4321 + Descriptor: 0x34 + Name: def +debug_gnu_pubtypes: + Length: + TotalLength: 0x1234 + Version: 2 + UnitOffset: 0x4321 + UnitSize: 0x00 + Entries: + - DieOffset: 0x1234 + Descriptor: 0x12 + Name: abc + - DieOffset: 0x4321 + Descriptor: 0x34 + Name: def +)"; + auto DWARFOrErr = parseDWARFYAML(Yaml); + ASSERT_THAT_EXPECTED(DWARFOrErr, Succeeded()); + + ASSERT_TRUE(DWARFOrErr->GNUPubNames.hasValue()); + DWARFYAML::PubSection GNUPubNames = DWARFOrErr->GNUPubNames.getValue(); + + ASSERT_EQ(GNUPubNames.Entries.size(), 2u); + EXPECT_EQ((uint32_t)GNUPubNames.Entries[0].DieOffset, 0x1234u); + EXPECT_EQ((uint8_t)GNUPubNames.Entries[0].Descriptor, 0x12); + EXPECT_EQ(GNUPubNames.Entries[0].Name, "abc"); + EXPECT_EQ((uint32_t)GNUPubNames.Entries[1].DieOffset, 0x4321u); + EXPECT_EQ((uint8_t)GNUPubNames.Entries[1].Descriptor, 0x34); + EXPECT_EQ(GNUPubNames.Entries[1].Name, "def"); + + ASSERT_TRUE(DWARFOrErr->GNUPubTypes.hasValue()); + DWARFYAML::PubSection GNUPubTypes = DWARFOrErr->GNUPubTypes.getValue(); + + ASSERT_EQ(GNUPubTypes.Entries.size(), 2u); + EXPECT_EQ((uint32_t)GNUPubTypes.Entries[0].DieOffset, 0x1234u); + EXPECT_EQ((uint8_t)GNUPubTypes.Entries[0].Descriptor, 0x12); + EXPECT_EQ(GNUPubTypes.Entries[0].Name, "abc"); + EXPECT_EQ((uint32_t)GNUPubTypes.Entries[1].DieOffset, 0x4321u); + EXPECT_EQ((uint8_t)GNUPubTypes.Entries[1].Descriptor, 0x34); + EXPECT_EQ(GNUPubTypes.Entries[1].Name, "def"); +} + +TEST(DebugGNUPubSection, TestMissingDescriptor) { + StringRef Yaml = R"( +debug_gnu_pubnames: + Length: + TotalLength: 0x1234 + Version: 2 + UnitOffset: 0x4321 + UnitSize: 0x00 + Entries: + - DieOffset: 0x1234 + Name: abcd +)"; + auto DWARFOrErr = parseDWARFYAML(Yaml); + EXPECT_THAT_ERROR(DWARFOrErr.takeError(), + FailedWithMessage("missing required key 'Descriptor'")); +}