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 IsGNUStyle = 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 IsGNUStylePubSec = false; +}; + struct Unit { InitialLength Length; uint16_t Version; 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 @@ -183,14 +183,14 @@ Error DWARFYAML::emitPubSection(raw_ostream &OS, const DWARFYAML::PubSection &Sect, - bool IsLittleEndian) { + bool IsLittleEndian, bool IsGNUStyle) { 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 (IsGNUStyle) 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) { + auto *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.IsGNUStylePubSec = 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())->IsGNUStylePubSec) 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/CMakeLists.txt b/llvm/unittests/ObjectYAML/CMakeLists.txt --- a/llvm/unittests/ObjectYAML/CMakeLists.txt +++ b/llvm/unittests/ObjectYAML/CMakeLists.txt @@ -1,9 +1,11 @@ set(LLVM_LINK_COMPONENTS + DebugInfoDWARF Object ObjectYAML ) add_llvm_unittest(ObjectYAMLTests + DWARFYAMLTest.cpp ELFYAMLTest.cpp MinidumpYAMLTest.cpp YAML2ObjTest.cpp diff --git a/llvm/unittests/ObjectYAML/DWARFYAMLTest.cpp b/llvm/unittests/ObjectYAML/DWARFYAMLTest.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/ObjectYAML/DWARFYAMLTest.cpp @@ -0,0 +1,127 @@ +//===- DWARFYAMLTest.cpp - Tests for DWARFYAML.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/ObjectYAML/DWARFYAML.h" +#include "llvm/ObjectYAML/DWARFEmitter.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" + +using namespace llvm; + +TEST(DWARFPubSections, TestUnexpectedDescriptor) { + StringRef Yaml = R"( +debug_pubnames: + Length: + TotalLength: 0x1234 + Version: 2 + UnitOffset: 0x4321 + UnitSize: 0x00 + Entries: + - DieOffset: 0x1234 + Descriptor: 0x12 + Name: abcd +)"; + testing::internal::CaptureStderr(); + auto SectionsOrErr = + DWARFYAML::emitDebugSections(Yaml); + EXPECT_THAT_ERROR(SectionsOrErr.takeError(), Failed()); + ASSERT_EQ(testing::internal::GetCapturedStderr(), + std::string("YAML:10:19: error: unknown key 'Descriptor'\n" + " Descriptor: 0x12\n" + " ^~~~\n")); +} + +TEST(DWARFPubSections, TestDWARFPubSections) { + StringRef Yaml = R"( +debug_pubnames: + Length: + TotalLength: 0x1234 + Version: 2 + UnitOffset: 0x4321 + UnitSize: 0x00 + Entries: + - DieOffset: 0x1234 + Descriptor: 0x12 + Name: abc + - DieOffset: 0x4321 + Descriptor: 0x34 + Name: def +debug_pubtypes: + Length: + TotalLength: 0x1234 + Version: 2 + UnitOffset: 0x4321 + UnitSize: 0x00 + Entries: + - DieOffset: 0x1234 + Descriptor: 0x12 + Name: abc + - DieOffset: 0x4321 + Descriptor: 0x34 + Name: def +)"; + auto SectionsOrErr = + DWARFYAML::emitDebugSections(Yaml); + EXPECT_THAT_EXPECTED(SectionsOrErr, Succeeded()); +} + +TEST(DWARFGNUPubSections, TestMissingDescriptor) { + StringRef Yaml = R"( +debug_gnu_pubnames: + Length: + TotalLength: 0x1234 + Version: 2 + UnitOffset: 0x4321 + UnitSize: 0x00 + Entries: + - DieOffset: 0x1234 + Name: abcd +)"; + testing::internal::CaptureStderr(); + auto SectionsOrErr = + DWARFYAML::emitDebugSections(Yaml); + EXPECT_THAT_ERROR(SectionsOrErr.takeError(), Failed()); + ASSERT_EQ(testing::internal::GetCapturedStderr(), + std::string("YAML:9:7: error: missing required key 'Descriptor'\n" + " - DieOffset: 0x1234\n" + " ^\n")); +} + +TEST(DWARFGNUPubSections, TestDWARFGNUPubSections) { + 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 SectionsOrErr = + DWARFYAML::emitDebugSections(Yaml); + EXPECT_THAT_EXPECTED(SectionsOrErr, Succeeded()); +}