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 @@ -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(); } +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); @@ -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 = ("." + DebugSecName).str(); + ImplicitSections.push_back(StringRef(SecName).copy(StringAlloc)); + } ImplicitSections.insert(ImplicitSections.end(), {".strtab", ".shstrtab"}); // Insert placeholders for implicit sections that are not @@ -391,6 +402,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; @@ -731,6 +744,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 the 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 @@ -1245,6 +1245,27 @@ } IO.mapRequired("Type", Type); + + StringRef Name; + IO.mapOptional("Name", Name, StringRef()); + Name = ELFYAML::dropUniqueSuffix(Name); + + // For sections identified by their names, we have to set the section type + // for them earlier. + if (ELFYAML::StackSizesSection::nameMatches(Name)) + // TODO: Test the .stack_sizes section being initialized from + // raw section content with the preserved sh_type, e.g., SHT_DYNAMIC. + Section.reset(new ELFYAML::StackSizesSection()); + else if (Name.startswith(".debug_")) + Section.reset(new ELFYAML::RawContentSection()); + } + + if (Section) { + if (auto *S = dyn_cast(Section.get())) + sectionMapping(IO, *S); + else if (auto *S = cast(Section.get())) + sectionMapping(IO, *S); + return; } switch (Type) { @@ -1336,21 +1357,9 @@ sectionMapping(IO, *cast(Section.get())); break; default: - if (!IO.outputting()) { - StringRef Name; - IO.mapOptional("Name", Name, StringRef()); - Name = ELFYAML::dropUniqueSuffix(Name); - - if (ELFYAML::StackSizesSection::nameMatches(Name)) - Section = std::make_unique(); - else - Section = std::make_unique(); - } - - if (auto S = dyn_cast(Section.get())) - sectionMapping(IO, *S); - else - sectionMapping(IO, *cast(Section.get())); + if (!IO.outputting()) + Section.reset(new ELFYAML::RawContentSection()); + sectionMapping(IO, *cast(Section.get())); } } @@ -1638,6 +1647,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,286 @@ +## 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 yaml2obj will generate the .debug_str section whose sh_type is a preserved one, +## e.g. SHT_DYNAMIC + +# RUN: yaml2obj --docnum=9 %s -o %t9.o +# RUN: llvm-readelf -S %t9.o | FileCheck %s --check-prefix=DYNAMIC-EMPTY + +# Name Type Address Offset Size ES Flg Lk Inf Al +# DYNAMIC-EMPTY: .debug_str DYNAMIC 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_DYNAMIC + +# RUN: yaml2obj --docnum=10 %s -o %t10.o +# RUN: llvm-readelf -S %t10.o | FileCheck %s --check-prefix=DYNAMIC-SIZE + +# Name Type Address Offset Size ES Flg Lk Inf Al +# DYNAMIC-SIZE: .debug_str DYNAMIC 0000000000000000 000040 00000a 01 MS 0 0 0 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_DYNAMIC + Size: 10 + +# RUN: yaml2obj --docnum=11 %s -o %t11.o +# RUN: llvm-readelf -S %t11.o | FileCheck %s --check-prefix=DYNAMIC-CONTENT +# RUN: llvm-readelf --string-dump=.debug_str %t11.o | FileCheck %s --check-prefix=DYNAMIC-STR + +# Name Type Address Offset Size ES Flg Lk Inf Al +# DYNAMIC-CONTENT: .debug_str DYNAMIC 0000000000000000 000040 000003 01 MS 0 0 0 + +# DYNAMIC-STR: String dump of section '.debug_str': +# DYNAMIC-STR-NEXT: [ 1] a +# DYNAMIC-STR-EMPTY: + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_DYNAMIC + Content: 006100 + +# RUN: yaml2obj --docnum=12 %s -o %t12.o +# RUN: llvm-readelf -S %t12.o | FileCheck %s --check-prefix=DYNAMIC-CONTENT +# RUN: llvm-readelf --string-dump=.debug_str %t12.o | FileCheck %s --check-prefix=DYNAMIC-STR + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_DYNAMIC +DWARF: + debug_str: + - '' + - a + +## j) Test that yaml2obj rejects our input at the lexical level, if we try to +## initialize the .debug_str section from non-RawContentSection. + +# RUN: not yaml2obj --docnum=13 %s 2>&1 | FileCheck %s --check-prefix=INVALID-ENTRY + +# INVALID-ENTRY: error: unknown key 'Entries' + +--- !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