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 @@ -15,6 +15,7 @@ #ifndef LLVM_OBJECTYAML_DWARFYAML_H #define LLVM_OBJECTYAML_DWARFYAML_H +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Support/YAMLTraits.h" @@ -171,6 +172,8 @@ std::vector DebugLines; bool isEmpty() const; + + SetVector 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 @@ -520,6 +521,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.empty(); } +SetVector DWARFYAML::Data::getUsedSectionNames() const { + SetVector SecNames; + if (!DebugStrings.empty()) + SecNames.insert("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 @@ -13,10 +13,13 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringSet.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELFObjectFile.h" +#include "llvm/ObjectYAML/DWARFEmitter.h" +#include "llvm/ObjectYAML/DWARFYAML.h" #include "llvm/ObjectYAML/ELFYAML.h" #include "llvm/ObjectYAML/yaml2obj.h" #include "llvm/Support/EndianStream.h" @@ -149,6 +152,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); @@ -272,6 +278,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 = ("." + DebugSecName).str(); + ImplicitSections.push_back(StringRef(SecName).copy(StringAlloc)); + } ImplicitSections.insert(ImplicitSections.end(), {".strtab", ".shstrtab"}); // Insert placeholders for implicit sections that are not @@ -428,7 +439,13 @@ initSymtabSectionHeader(Header, SymtabType::Dynamic, CBA, YAMLSec); else if (SecName == ".dynstr") initStrtabSectionHeader(Header, SecName, DotDynstr, CBA, YAMLSec); - else + else if (SecName.startswith(".debug_")) { + // If a ".debug_*" section's type is a preserved one, e.g., SHT_DYNAMIC, we + // will treat it as a dynamic section. + if (YAMLSec && !isa(YAMLSec)) + return false; + initDWARFSectionHeader(Header, SecName, CBA, YAMLSec); + } else return false; LocationCounter += Header.sh_size; @@ -772,6 +789,69 @@ assignSectionAddress(SHeader, YAMLSec); } +static bool shouldEmitDWARF(DWARFYAML::Data &DWARF, StringRef Name) { + SetVector DebugSecNames = DWARF.getUsedSectionNames(); + return Name.consume_front(".") && DebugSecNames.count(Name); +} + +template +uint64_t emitDWARF(typename ELFT::Shdr &SHeader, StringRef Name, + const DWARFYAML::Data &DWARF, raw_ostream &OS) { + uint64_t BeginOffset = OS.tell(); + if (Name == ".debug_str") + DWARFYAML::EmitDebugStr(OS, DWARF); + else + llvm_unreachable("unexpected emitDWARF() call"); + + return OS.tell() - BeginOffset; +} + +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, + YAMLSec ? YAMLSec->Offset : None); + + ELFYAML::RawContentSection *RawSec = + dyn_cast_or_null(YAMLSec); + if (Doc.DWARF && shouldEmitDWARF(*Doc.DWARF, Name)) { + if (RawSec && (RawSec->Content || RawSec->Size)) + reportError("cannot specify section '" + Name + + "' contents in the 'DWARF' entry and the 'Content' " + "or 'Size' in the 'Sections' entry at the same time"); + else + SHeader.sh_size = emitDWARF(SHeader, Name, *Doc.DWARF, CBA.getOS()); + } else if (RawSec) + SHeader.sh_size = writeContent(CBA.getOS(), RawSec->Content, RawSec->Size); + else + llvm_unreachable("debug sections can only be initialized via the 'DWARF' " + "entry or a RawContentSection"); + + 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; + + unsigned Link = 0; + if (YAMLSec && !YAMLSec->Link.empty() && SN2I.lookup(YAMLSec->Link, Link)) + SHeader.sh_link = Link; + + 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,238 @@ +## 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-prefix=DWARF-DEFAULT + +# DWARF-DEFAULT: String dump of section '.debug_str': +# DWARF-DEFAULT-NEXT: [ 0] a +# DWARF-DEFAULT-NEXT: [ 2] b +# DWARF-DEFAULT-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 -S %t1.o | FileCheck %s --check-prefix=SHDRS-DEFAULT + +# Name Type Address Offset Size ES Flg Lk Inf Al +# SHDRS-DEFAULT: .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 --check-prefix=DWARF-DEFAULT +# RUN: llvm-readelf -S %t2.o | FileCheck %s --check-prefix=SHDRS + +# Name Type Address Offset Size ES Flg Lk Inf Al +# SHDRS: .debug_str PROGBITS 0000000000000000 000040 000006 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 + Content: "610062006300" + +## c) Generate the .debug_str section when the "Size" is specified. + +# RUN: yaml2obj --docnum=3 %s -o %t3.o +# RUN: llvm-readelf -S %t3.o | FileCheck %s --check-prefix=SIZE +# RUN: llvm-readelf --hex-dump=.debug_str %t3.o | FileCheck %s --check-prefix=SIZE-CONTENT + +# Name Type Address Offset Size ES Flg Lk Inf Al +# SIZE: .debug_str PROGBITS 0000000000000000 000040 000010 01 MS 0 0 0 + +# SIZE-CONTENT: Hex dump of section '.debug_str': +# SIZE-CONTENT-NEXT: 0x00000000 00000000 00000000 00000000 00000000 ................ +# SIZE-CONTENT-EMPTY: + +--- !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 section '.debug_str' 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 overridden by the section header when +## the "debug_str" entry doesn't exist. + +# RUN: yaml2obj --docnum=6 %s -o %t6.o +# RUN: llvm-readelf -S %t6.o | FileCheck %s --check-prefix=OVERRIDDEN + +# Index Name Type Address Offset Size ES Flg Lk Inf Al +# OVERRIDDEN: [ 1] .sec STRTAB 0000000000000000 000040 000000 00 0 0 0 +# OVERRIDDEN: [ 2] .debug_str STRTAB 0000000000002020 000050 000006 02 A 1 1 2 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .sec # Linked by .debug_str. + Type: SHT_STRTAB + - Name: .debug_str + Type: SHT_STRTAB # SHT_PROGBITS by default. + Flags: [SHF_ALLOC] # [SHF_STRINGS, SHF_MERGE] by default. + Link: .sec # 0 by default. + EntSize: 2 # 1 by default. + Info: 1 # 0 by default. + AddressAlign: 2 # 0 by default. + Address: 0x0000000000002020 # 0x00 by default. + Offset: 0x00000050 # 0x40 for the first section. + Size: 6 # Set the "Size" so that we can reuse the check tag "OVERRIEDDEN" + +## g) Test that all the properties can be overridden by the section header when +## the "debug_str" entry is used. + +# RUN: yaml2obj --docnum=7 %s -o %t7.o +# RUN: llvm-readelf --string-dump=.debug_str %t7.o | FileCheck %s --check-prefix=DWARF-DEFAULT +# RUN: llvm-readelf -S %t7.o | FileCheck %s --check-prefix=OVERRIDDEN + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .sec # Linked by .debug_str. + Type: SHT_STRTAB + - Name: .debug_str + Type: SHT_STRTAB # SHT_PROGBITS by default. + Flags: [SHF_ALLOC] # [SHF_STRINGS, SHF_MERGE] by default. + Link: .sec # 0 by default. + EntSize: 2 # 1 by default. + Info: 1 # 0 by default. + AddressAlign: 2 # 1 by default. + Address: 0x0000000000002020 # 0x00 by default. + Offset: 0x00000050 # 0x40 for the first section. +DWARF: + debug_str: + - a + - b + - c + +## h) Test that yaml2obj will not generate the .debug_str section when the "DWARF" entry exists +## but the "debug_str" entry doesn't exist in the "DWARF" entry or the "Sections" entry. + +# RUN: yaml2obj --docnum=8 %s -o %t8.o +# RUN: llvm-readelf -S %t8.o | FileCheck /dev/null --implicit-check-not=.debug_str + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: + +## i) Test that if we try to initialize the .debug_str section with a preserved "Type", e.g., +## SHT_DYNAMIC, yaml2obj will treat it as a dynamic section and discard the content in the +## "DWARF" entry. + +# RUN: yaml2obj --docnum=9 %s -o %t9.o +# RUN: llvm-readelf -S %t9.o | FileCheck %s --check-prefix=DYN-SHDR +# RUN: llvm-readelf -d %t9.o | FileCheck %s --check-prefix=DYNAMIC + +# RUN: yaml2obj --docnum=10 %s -o %t10.o +# RUN: llvm-readelf -S %t10.o | FileCheck %s --check-prefix=DYN-SHDR +# RUN: llvm-readelf -d %t10.o | FileCheck %s --check-prefix=DYNAMIC + +# Name Type Address Offset Size ES Flg Lk Inf Al +# DYN-SHDR: .debug_str DYNAMIC 0000000000000000 000040 000010 10 0 0 0 + +# DYNAMIC: Dynamic section at offset 0x40 contains 1 entries: +# DYNAMIC-NEXT: Tag Type Name/Value +# DYNAMIC-NEXT: 0x0000000000000000 (NULL) 0x0 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_DYNAMIC + Entries: + - Tag: DT_NULL + Value: 0 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_DYNAMIC + Entries: + - Tag: DT_NULL + Value: 0 +DWARF: + debug_str: + - a