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 getUsedSectionNames() 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 @@ -517,6 +518,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,13 @@ DebugLines.size(); } +std::vector DWARFYAML::Data::getUsedSectionNames() const { + std::vector SecNames; + if (!DebugStrings.empty()) + SecNames.push_back("debug_str"); + 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,11 @@ StringTableBuilder &STB, ContiguousBlobAccumulator &CBA, ELFYAML::Section *YAMLSec); + void initDWARFSectionHeader(Elf_Shdr &SHeader, StringRef Name, + ContiguousBlobAccumulator &CBA, + ELFYAML::Section *YAMLSec); + bool generateContentsFromDWARFEntry(Elf_Shdr &SHeader, StringRef Name, + raw_ostream &OS); void setProgramHeaderLayout(std::vector &PHeaders, std::vector &SHeaders); @@ -217,7 +223,7 @@ ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH); void assignSectionAddress(Elf_Shdr &SHeader, ELFYAML::Section *YAMLSec); - + BumpPtrAllocator StringAlloc; uint64_t alignToOffset(ContiguousBlobAccumulator &CBA, uint64_t Align, llvm::Optional Offset); @@ -258,6 +264,11 @@ ImplicitSections.insert(ImplicitSections.end(), {".dynsym", ".dynstr"}); if (Doc.Symbols) ImplicitSections.push_back(".symtab"); + if (Doc.DWARF) + for (StringRef DebugSecName : Doc.DWARF->getUsedSectionNames()) { + std::string SecName = Twine("." + DebugSecName).str(); + ImplicitSections.push_back(StringRef(SecName).copy(StringAlloc)); + } ImplicitSections.insert(ImplicitSections.end(), {".strtab", ".shstrtab"}); // Insert placeholders for implicit sections that are not @@ -391,7 +402,9 @@ initSymtabSectionHeader(Header, SymtabType::Dynamic, CBA, YAMLSec); else if (SecName == ".dynstr") initStrtabSectionHeader(Header, SecName, DotDynstr, CBA, YAMLSec); - else + else if (SecName.startswith(".debug_")) { + initDWARFSectionHeader(Header, SecName, CBA, YAMLSec); + } else return false; LocationCounter += Header.sh_size; @@ -731,6 +744,64 @@ assignSectionAddress(SHeader, YAMLSec); } +template +bool ELFState::generateContentsFromDWARFEntry(Elf_Shdr &SHeader, + StringRef Name, + raw_ostream &OS) { + uint64_t BeginOffset = OS.tell(); + if (Name == ".debug_str" && !Doc.DWARF->DebugStrings.empty()) + DWARFYAML::EmitDebugStr(OS, *Doc.DWARF); + // TODO: Add other debug sections. + else + // If the implicit debug section is not from the "DWARF" entry, the contents + // will be filled according to the "Content" or "Size" later. + return false; + + uint64_t EndOffset = OS.tell(); + SHeader.sh_size = EndOffset - BeginOffset; + return true; +} + +template +void ELFState::initDWARFSectionHeader(Elf_Shdr &SHeader, StringRef Name, + ContiguousBlobAccumulator &CBA, + ELFYAML::Section *YAMLSec) { + zero(SHeader); + SHeader.sh_name = DotShStrtab.getOffset(ELFYAML::dropUniqueSuffix(Name)); + SHeader.sh_type = YAMLSec ? YAMLSec->Type : ELF::SHT_PROGBITS; + SHeader.sh_addralign = YAMLSec ? (uint64_t)YAMLSec->AddressAlign : 1; + SHeader.sh_offset = alignToOffset(CBA, SHeader.sh_addralign, /*Offset=*/None); + + ELFYAML::RawContentSection *RawSec = + dyn_cast_or_null(YAMLSec); + raw_ostream &OS = CBA.getOS(); + + if (Doc.DWARF && generateContentsFromDWARFEntry(SHeader, Name, OS)) { + if (RawSec && (RawSec->Content || RawSec->Size)) + reportError("cannot specify the '" + Name + + "' section contents in the 'DWARF' entry and the 'Content' " + "or 'Size' in the 'Sections' entry at the same time"); + } else if (RawSec) + SHeader.sh_size = writeContent(OS, RawSec->Content, RawSec->Size); + else + llvm_unreachable("initDWARFSectionHeader() failed"); + + 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 @@ -1638,6 +1638,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-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,215 @@ +## 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-readelf --string-dump=.debug_str %t1.o | FileCheck %s + +# CHECK: String dump of section '.debug_str': +# CHECK-NEXT: [ 0] a +# CHECK-NEXT: [ 2] b +# CHECK-NEXT: [ 4] c + +## Check the default sh_type, sh_entsize, sh_info, sh_flags and sh_addralign of 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-readelf --string-dump=.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) Generate the .debug_str section when the "Size" is specified. + +# RUN: yaml2obj --docnum=3 %s -o %t3.o +# RUN: llvm-readelf --section-headers %t3.o | FileCheck %s --check-prefix=SIZE + +# Name Type Address Offset Size ES Flg Lk Inf Al +# SIZE: .debug_str PROGBITS 0000000000000000 000040 000010 01 MS 0 0 0 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_PROGBITS + Size: 0x10 + +## d) Test that yaml2obj emits an error message when both the "Size" and the +## "debug_str" entry are specified at the same time. + +# RUN: not yaml2obj --docnum=4 %s -o %t4.o 2>&1 | FileCheck %s --check-prefix=ERROR + +# ERROR: yaml2obj: error: cannot specify the '.debug_str' section contents in the 'DWARF' entry and the 'Content' or 'Size' in the 'Sections' entry at the same time + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_PROGBITS + Size: 0x10 +DWARF: + debug_str: + - a + +## e) Test that yaml2obj emits an error message when both the "Content" and the +## "debug_str" entry are specified at the same time. + +# RUN: not yaml2obj --docnum=5 %s -o %t5.o 2>&1 | FileCheck %s --check-prefix=ERROR + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_PROGBITS + Content: "6100" +DWARF: + debug_str: + - a + +## f) Test that all the properties can be overriden by the section header when +## the "debug_str" entry is used. + +# RUN: yaml2obj --docnum=6 %s -o %t6.o +# RUN: llvm-readelf --string-dump=.debug_str %t6.o | FileCheck %s +# RUN: llvm-readelf --section-headers %t6.o | FileCheck %s --check-prefix=OVERRIDEN + +# Name Type Address Offset Size ES Flg Lk Inf Al +# OVERRIDEN: .debug_str STRTAB 0000000000000000 000040 000006 02 A 0 1 2 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_STRTAB # SHT_PROGBITS by default. + Flags: [SHF_ALLOC] # [SHF_STRINGS, SHF_MERGE] by default. + EntSize: 2 # 1 by default. + Info: 1 # 0 by default. + AddressAlign: 2 # 1 by default. +DWARF: + debug_str: + - a + - b + - c + +## g) Test that all the properties can be overriden by the section header when +## the "debug_str" entry doesn't exist. + +# RUN: yaml2obj --docnum=7 %s -o %t7.o +# RUN: llvm-readelf --section-headers %t7.o | FileCheck %s --check-prefix=OVERRIDEN + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_STRTAB + Flags: [SHF_ALLOC] # [SHF_STRINGS, SHF_MERGE] by default. + EntSize: 2 # 1 by default. + Info: 1 # 0 by default. + AddressAlign: 2 # 1 by default. + Size: 6 # Set the "Size" so that we can reuse the check tag "OVERRIEDN" + +## h) Check the default values of sh_entsize, sh_flags, sh_info and sh_addralign when +## the "debug_str" entry doesn't exist. + +# RUN: yaml2obj --docnum=8 %s -o %t8.o +# RUN: llvm-readelf --section-headers %t8.o | FileCheck %s --check-prefix=DEFAULT + +# Name Type Address Offset Size ES Flg Lk Inf Al +# DEFAULT: .debug_str PROGBITS 0000000000000000 000040 000000 01 MS 0 0 0 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_PROGBITS + +## i) Set the address for the .debug_str section when the "debug_str" entry exists. + +# RUN: yaml2obj --docnum=9 %s -o %t9.o +# RUN: llvm-readelf --section-headers %t9.o | FileCheck %s --check-prefix=ADDRESS + +# Name Type Address Offset Size ES Flg Lk Inf Al +# ADDRESS: .debug_str PROGBITS 0000000000002020 000040 000002 01 MS 0 0 0 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_PROGBITS + Address: 0x0000000000002020 +DWARF: + debug_str: + - a + +## j) Set the address for the .debug_str section when the "debug_str" entry doesn't exist. + +# RUN: yaml2obj --docnum=10 %s -o %t10.o +# RUN: llvm-readelf --section-headers %t10.o | FileCheck %s --check-prefix=ADDRESS + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_PROGBITS + Address: 0x0000000000002020 + Size: 2 # Set that "Size" so that we can reuse the check tag "ADDRESS"