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,11 @@ StringTableBuilder &STB, ContiguousBlobAccumulator &CBA, ELFYAML::Section *YAMLSec); + void initDWARFSectionHeader(Elf_Shdr &SHeader, StringRef Name, + ContiguousBlobAccumulator &CBA, + ELFYAML::Section *YAMLSec); + static uint64_t emitDWARF(Elf_Shdr &SHeader, StringRef Name, + const DWARFYAML::Data &DWARF, raw_ostream &OS); void setProgramHeaderLayout(std::vector &PHeaders, std::vector &SHeaders); @@ -217,7 +225,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 +266,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 +404,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 +746,69 @@ assignSectionAddress(SHeader, YAMLSec); } +static bool shouldEmitDWARF(DWARFYAML::Data &DWARF, StringRef Name) { + SetVector DebugSecNames = DWARF.getUsedSectionNames(); + if (!Name.empty() && Name[0] == '.' && DebugSecNames.count(Name.drop_front())) + return true; + return false; +} + +template +uint64_t ELFState::emitDWARF(Elf_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 the '" + Name + + "' section 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 + reportError("the '" + Name + + "' section can only be initialized from the 'DWARF' entry or " + "the raw content section"); + + 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,202 @@ +## 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 --section-headers %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 --section-headers %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 --section-headers %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 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 overridden 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 --check-prefix=DWARF-DEFAULT +# RUN: llvm-readelf --section-headers %t6.o | FileCheck %s --check-prefix=OVERRIDDEN + +# Name Type Address Offset Size ES Flg Lk Inf Al +# OVERRIDDEN: .debug_str STRTAB 0000000000002020 000050 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. + Address: 0x0000000000002020 # 0x00 by default. + Offset: 0x00000050 # 0x40 for the first section. +DWARF: + debug_str: + - a + - b + - c + +## g) Test that all the properties can be overridden 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=OVERRIDDEN + +--- !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 # 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" + +## h) Test that yaml2obj emits an error message if we initialize the .debug_str section with +## a preserved type, e.g., SHT_DYNAMIC. + +# RUN: not yaml2obj --docnum=8 %s -o %t8.o 2>&1 | FileCheck %s --check-prefix=TYPE-ERROR + +# TYPE-ERROR: yaml2obj: error: the '.debug_str' section can only be initialized from the 'DWARF' entry or the raw content section + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .debug_str + Type: SHT_DYNAMIC + +## i) 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=9 %s -o %t9.o +# RUN: llvm-readelf --section-headers %t9.o | FileCheck %s --check-prefix=NO-DEBUGSTR --implicit-check-not=.debug_str + +# NO-DEBUGSTR: Section Headers: + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +DWARF: