This patch adds a new DWARF entry in ELF YAML file.
Reviewed By: grimar
Differential Revision: https://reviews.llvm.org/D80203
#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"
std::vector<LineTable> DebugLines;
bool isEmpty() const;
+
+ SetVector<StringRef> getUsedSectionNames() const;
};
} // end namespace DWARFYAML
#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 <cstdint>
// being a single SHT_SYMTAB section are upheld.
Optional<std::vector<Symbol>> Symbols;
Optional<std::vector<Symbol>> DynamicSymbols;
+ Optional<DWARFYAML::Data> DWARF;
std::vector<Section *> getSections() {
std::vector<Section *> Ret;
DebugLines.empty();
}
+SetVector<StringRef> DWARFYAML::Data::getUsedSectionNames() const {
+ SetVector<StringRef> SecNames;
+ if (!DebugStrings.empty())
+ SecNames.insert("debug_str");
+ return SecNames;
+}
+
namespace yaml {
void MappingTraits<DWARFYAML::Data>::mapping(IO &IO, DWARFYAML::Data &DWARF) {
#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"
StringTableBuilder &STB,
ContiguousBlobAccumulator &CBA,
ELFYAML::Section *YAMLSec);
+ void initDWARFSectionHeader(Elf_Shdr &SHeader, StringRef Name,
+ ContiguousBlobAccumulator &CBA,
+ ELFYAML::Section *YAMLSec);
void setProgramHeaderLayout(std::vector<Elf_Phdr> &PHeaders,
std::vector<Elf_Shdr> &SHeaders);
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
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 not treat it as a debug section.
+ if (YAMLSec && !isa<ELFYAML::RawContentSection>(YAMLSec))
+ return false;
+ initDWARFSectionHeader(Header, SecName, CBA, YAMLSec);
+ } else
return false;
LocationCounter += Header.sh_size;
assignSectionAddress(SHeader, YAMLSec);
}
+static bool shouldEmitDWARF(DWARFYAML::Data &DWARF, StringRef Name) {
+ SetVector<StringRef> DebugSecNames = DWARF.getUsedSectionNames();
+ return Name.consume_front(".") && DebugSecNames.count(Name);
+}
+
+template <class ELFT>
+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 <class ELFT>
+void ELFState<ELFT>::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<ELFYAML::RawContentSection>(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<ELFT>(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 <class ELFT> void ELFState<ELFT>::reportError(const Twine &Msg) {
ErrHandler(Msg);
HasError = true;
IO.mapOptional("Sections", Object.Chunks);
IO.mapOptional("Symbols", Object.Symbols);
IO.mapOptional("DynamicSymbols", Object.DynamicSymbols);
+ IO.mapOptional("DWARF", Object.DWARF);
IO.setContext(nullptr);
}
--- /dev/null
+## 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