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 @@ -171,6 +171,7 @@ std::vector DebugLines; bool isEmpty() const; + std::vector getELFSectionNames() const; }; } // end namespace DWARFYAML diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h --- a/llvm/include/llvm/ObjectYAML/ELFYAML.h +++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -16,6 +16,7 @@ #define LLVM_OBJECTYAML_ELFYAML_H #include "llvm/ADT/StringRef.h" +#include "llvm/ObjectYAML/DWARFYAML.h" #include "llvm/ObjectYAML/YAML.h" #include "llvm/Support/YAMLTraits.h" #include @@ -521,6 +522,7 @@ // being a single SHT_SYMTAB section are upheld. Optional> Symbols; Optional> DynamicSymbols; + Optional DWARF; std::vector
getSections() { std::vector
Ret; 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 @@ -23,6 +23,32 @@ DebugLines.size(); } +std::vector DWARFYAML::Data::getELFSectionNames() const { + std::vector SecNames; + if (!DebugStrings.empty()) + SecNames.push_back(".debug_str"); + if (!AbbrevDecls.empty()) + SecNames.push_back(".debug_abbrev"); + if (!ARanges.empty()) + SecNames.push_back(".debug_aranges"); + if (!DebugRanges.empty()) + SecNames.push_back(".debug_ranges"); + if (!PubNames.Entries.empty()) + SecNames.push_back(".debug_pubnames"); + if (!PubTypes.Entries.empty()) + SecNames.push_back(".debug_pubtypes"); + if (!GNUPubNames.Entries.empty()) + SecNames.push_back(".debug_gnu_pubnames"); + if (!GNUPubTypes.Entries.empty()) + SecNames.push_back(".debug_gnu_pubtypes"); + if (!CompileUnits.empty()) + SecNames.push_back(".debug_info"); + if (!DebugLines.empty()) + SecNames.push_back(".debug_line"); + + return SecNames; +} + namespace yaml { void MappingTraits::mapping(IO &IO, DWARFYAML::Data &DWARF) { diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -17,6 +17,7 @@ #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELFObjectFile.h" +#include "llvm/ObjectYAML/DWARFEmitter.h" #include "llvm/ObjectYAML/ELFYAML.h" #include "llvm/ObjectYAML/yaml2obj.h" #include "llvm/Support/EndianStream.h" @@ -149,6 +150,9 @@ StringTableBuilder &STB, ContiguousBlobAccumulator &CBA, ELFYAML::Section *YAMLSec); + void initDWARFSectionHeader(Elf_Shdr &SHeader, StringRef Name, + ContiguousBlobAccumulator &CBA, + ELFYAML::Section *YAMLSec); void setProgramHeaderLayout(std::vector &PHeaders, std::vector &SHeaders); @@ -258,6 +262,9 @@ ImplicitSections.insert(ImplicitSections.end(), {".dynsym", ".dynstr"}); if (Doc.Symbols) ImplicitSections.push_back(".symtab"); + if (Doc.DWARF) + for (StringRef DebugSecName : Doc.DWARF->getELFSectionNames()) + ImplicitSections.push_back(DebugSecName); ImplicitSections.insert(ImplicitSections.end(), {".strtab", ".shstrtab"}); // Insert placeholders for implicit sections that are not @@ -391,6 +398,8 @@ initSymtabSectionHeader(Header, SymtabType::Dynamic, CBA, YAMLSec); else if (SecName == ".dynstr") initStrtabSectionHeader(Header, SecName, DotDynstr, CBA, YAMLSec); + else if (SecName.startswith(".debug_")) + initDWARFSectionHeader(Header, SecName, CBA, YAMLSec); else return false; @@ -720,6 +729,53 @@ assignSectionAddress(SHeader, YAMLSec); } +template +void ELFState::initDWARFSectionHeader(Elf_Shdr &SHeader, StringRef Name, + ContiguousBlobAccumulator &CBA, + ELFYAML::Section *YAMLSec) { + zero(SHeader); + SHeader.sh_name = DotShStrtab.getOffset(Name); + SHeader.sh_type = YAMLSec ? YAMLSec->Type : ELF::SHT_PROGBITS; + SHeader.sh_addralign = YAMLSec ? (uint64_t)YAMLSec->AddressAlign : 1; + + ELFYAML::RawContentSection *RawSec = + dyn_cast_or_null(YAMLSec); + + SHeader.sh_offset = alignToOffset(CBA, SHeader.sh_addralign, /*Offset=*/None); + raw_ostream &OS = CBA.getOS(); + + if (RawSec && (RawSec->Content || RawSec->Size)) { + SHeader.sh_size = writeContent(OS, RawSec->Content, RawSec->Size); + } else if (Doc.DWARF) { + uint64_t BeginOffset = OS.tell(); + + if (Name == ".debug_str") + DWARFYAML::EmitDebugStr(OS, *Doc.DWARF); + else + // TODO: Support more debug sections. + reportError(Name + " section is not implemented"); + + uint64_t EndOffset = OS.tell(); + SHeader.sh_size = EndOffset - BeginOffset; + } else + reportError("the content of the " + Name + " section should be specified"); + + if (YAMLSec && YAMLSec->EntSize) + SHeader.sh_entsize = *YAMLSec->EntSize; + else if (Name == ".debug_str") + SHeader.sh_entsize = 1; + + if (RawSec && RawSec->Info) + SHeader.sh_info = *RawSec->Info; + + if (YAMLSec && YAMLSec->Flags) + SHeader.sh_flags = *YAMLSec->Flags; + else if (Name == ".debug_str") + SHeader.sh_flags = ELF::SHF_MERGE | ELF::SHF_STRINGS; + + assignSectionAddress(SHeader, YAMLSec); +} + template void ELFState::reportError(const Twine &Msg) { ErrHandler(Msg); HasError = true; diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -1637,6 +1637,7 @@ IO.mapOptional("Sections", Object.Chunks); IO.mapOptional("Symbols", Object.Symbols); IO.mapOptional("DynamicSymbols", Object.DynamicSymbols); + IO.mapOptional("DWARF", Object.DWARF); IO.setContext(nullptr); } diff --git a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-info.yaml b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-info.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-info.yaml @@ -0,0 +1,22 @@ +## Test that yaml2obj emits .debug_info section. + +## a) TODO: Generate the .debug_info section from the "DWARF" entry. +# RUN: not yaml2obj --docnum=1 %s -o %t1.o 2>&1 | FileCheck %s --check-prefix="NOIMPL" + +# NOIMPL: yaml2obj: error: .debug_info section is not implemented + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_info: + - Length: + TotalLength: 0x0 + Version: 0 + AbbrOffset: 0x0 + AddrSize: 0x0 + Entries: +... diff --git a/llvm/test/tools/yaml2obj/ELF/DWARF/debug-str.yaml b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-str.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/yaml2obj/ELF/DWARF/debug-str.yaml @@ -0,0 +1,62 @@ +## Test that yaml2obj emits .debug_str section. + +## a) Generate the .debug_str section from the "DWARF" entry. +# RUN: yaml2obj --docnum=1 %s -o %t1.o +# RUN: llvm-dwarfdump --debug-str %t1.o | FileCheck %s + +# CHECK: .debug_str contents: +# CHECK-NEXT: 0x00000000: "a" +# CHECK-NEXT: 0x00000002: "b" +# CHECK-NEXT: 0x00000004: "c" + +## Check the .debug_str section header. +# RUN: llvm-readelf --section-headers %t1.o | FileCheck %s --check-prefix="READELF" + +# Name Type Address Offset Size ES Flg Lk Inf Al +# READELF: .debug_str PROGBITS 0000000000000000 000040 000006 01 MS 0 0 1 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + debug_str: + - a + - b + - c +... + +## b) Generate the .debug_str section from the raw section content. +# RUN: yaml2obj --docnum=2 %s -o %t2.o +# RUN: llvm-dwarfdump --debug-str %t2.o | FileCheck %s + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_PROGBITS + Flags: [SHF_MERGE, SHF_STRINGS] + Content: "610062006300" +... + +## c) Request generating the .debug_str section without specifing the section content or size. +# RUN: not yaml2obj --docnum=3 %s -o %t3.o 2>&1 | FileCheck %s --check-prefix="ERROR" + +# ERROR: yaml2obj: error: the content of the .debug_str section should be specified + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_PROGBITS +...