[llvm] bd7f3f8 - [obj2yaml] Add support for dumping the .debug_aranges section.
Xing GUO via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 5 04:19:30 PDT 2020
Author: Xing GUO
Date: 2020-08-05T19:19:05+08:00
New Revision: bd7f3f8a3ed70586f2b6a68b267b83d18e6fbdb4
URL: https://github.com/llvm/llvm-project/commit/bd7f3f8a3ed70586f2b6a68b267b83d18e6fbdb4
DIFF: https://github.com/llvm/llvm-project/commit/bd7f3f8a3ed70586f2b6a68b267b83d18e6fbdb4.diff
LOG: [obj2yaml] Add support for dumping the .debug_aranges section.
This patch adds support for dumping DWARF sections to obj2yaml. The
.debug_aranges section is used to illustrate the basic idea.
Reviewed By: jhenderson
Differential Revision: https://reviews.llvm.org/D85094
Added:
llvm/test/tools/obj2yaml/ELF/DWARF/debug-aranges.yaml
Modified:
llvm/tools/obj2yaml/elf2yaml.cpp
llvm/tools/obj2yaml/obj2yaml.h
Removed:
################################################################################
diff --git a/llvm/test/tools/obj2yaml/ELF/DWARF/debug-aranges.yaml b/llvm/test/tools/obj2yaml/ELF/DWARF/debug-aranges.yaml
new file mode 100644
index 000000000000..39ee4baa97fe
--- /dev/null
+++ b/llvm/test/tools/obj2yaml/ELF/DWARF/debug-aranges.yaml
@@ -0,0 +1,172 @@
+## Test how we dump the .debug_aranges section.
+
+## a) Test dumping the DWARF32/64 address range table from 32/64-bit, little/big endian object files.
+## The .debug_aranges should be written to the 'DWARF' entry and the 'Sections' entry should remain empty.
+
+# RUN: yaml2obj --docnum=1 -DBITS=32 -DENDIAN=LSB %s | obj2yaml | \
+# RUN: FileCheck -DLENGTH1=24 -DLENGTH2=24 -DADDRSIZE=0x04 %s --check-prefix=BASIC --implicit-check-not=Sections
+
+# RUN: yaml2obj --docnum=1 -DBITS=32 -DENDIAN=MSB %s | obj2yaml | \
+# RUN: FileCheck -DLENGTH1=24 -DLENGTH2=24 -DADDRSIZE=0x04 %s --check-prefix=BASIC --implicit-check-not=Sections
+
+# RUN: yaml2obj --docnum=1 -DBITS=64 -DENDIAN=LSB %s | obj2yaml | \
+# RUN: FileCheck -DLENGTH1=3C -DLENGTH2=44 -DADDRSIZE=0x08 %s --check-prefix=BASIC --implicit-check-not=Sections
+
+# RUN: yaml2obj --docnum=1 -DBITS=64 -DENDIAN=MSB %s | obj2yaml | \
+# RUN: FileCheck -DLENGTH1=3C -DLENGTH2=44 -DADDRSIZE=0x08 %s --check-prefix=BASIC --implicit-check-not=Sections
+
+# BASIC: DWARF:
+# BASIC-NEXT: debug_aranges:
+# BASIC-NEXT: - Length: 0x00000000000000[[LENGTH1]]
+# BASIC-NEXT: Version: 2
+# BASIC-NEXT: CuOffset: 0x0000000000001234
+# BASIC-NEXT: AddressSize: [[ADDRSIZE]]
+# BASIC-NEXT: Descriptors:
+# BASIC-NEXT: - Address: 0x0000000000001234
+# BASIC-NEXT: Length: 0x0000000000005678
+# BASIC-NEXT: - Address: 0x0000000000001234
+# BASIC-NEXT: Length: 0x0000000000005678
+# BASIC-NEXT: - Format: DWARF64
+# BASIC-NEXT: Length: 0x00000000000000[[LENGTH2]]
+# BASIC-NEXT: Version: 2
+# BASIC-NEXT: CuOffset: 0x1234567890ABCDEF
+# BASIC-NEXT: AddressSize: [[ADDRSIZE]]
+# BASIC-NEXT: Descriptors:
+# BASIC-NEXT: - Address: 0x0000000000001234
+# BASIC-NEXT: Length: 0x0000000000005678
+# BASIC-NEXT: - Address: 0x0000000000001234
+# BASIC-NEXT: Length: 0x0000000000005678
+# BASIC-NEXT: ...
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS[[BITS]]
+ Data: ELFDATA2[[ENDIAN]]
+ Type: ET_EXEC
+ Machine: EM_X86_64
+DWARF:
+ debug_aranges:
+ - Version: 2
+ CuOffset: 0x1234
+ Descriptors:
+ - Address: 0x1234
+ Length: 0x5678
+ - Address: 0x1234
+ Length: 0x5678
+ - Format: DWARF64
+ Version: 2
+ CuOffset: 0x1234567890abcdef
+ Descriptors:
+ - Address: 0x1234
+ Length: 0x5678
+ - Address: 0x1234
+ Length: 0x5678
+
+## b) Test dumping an .debug_aranges section whose section header properties are overridden.
+
+# RUN: yaml2obj --docnum=2 -DTYPE=SHT_STRTAB %s | obj2yaml | FileCheck %s -DTYPE=STRTAB --check-prefixes=ARANGE,SHDR
+# RUN: yaml2obj --docnum=2 -DFLAGS=[SHF_ALLOC] %s | obj2yaml | FileCheck %s -DTYPE=PROGBITS --check-prefixes=ARANGE,SHDR,FLAGS
+# RUN: yaml2obj --docnum=2 -DLINK='.sec' %s | obj2yaml | FileCheck %s -DTYPE=PROGBITS --check-prefixes=ARANGE,SHDR,LINK
+# RUN: yaml2obj --docnum=2 -DENTSIZE=3 %s | obj2yaml | FileCheck %s -DTYPE=PROGBITS --check-prefixes=ARANGE,SHDR,ENTSIZE
+# RUN: yaml2obj --docnum=2 -DINFO=3 %s | obj2yaml | FileCheck %s -DTYPE=PROGBITS --check-prefixes=ARANGE,SHDR,INFO
+# RUN: yaml2obj --docnum=2 -DADDRALIGN=3 %s | obj2yaml | FileCheck %s -DTYPE=PROGBITS --check-prefixes=ARANGE,SHDR,ADDRALIGN
+# RUN: yaml2obj --docnum=2 -DADDRESS=0x2020 %s | obj2yaml | FileCheck %s -DTYPE=PROGBITS --check-prefixes=ARANGE,SHDR,ADDRESS
+
+# SHDR: - Name: .debug_aranges
+# SHDR-NEXT: Type: SHT_[[TYPE]]
+# FLAGS-NEXT: Flags: [ SHF_ALLOC ]
+# LINK-NEXT: Link: .sec
+# ENTSIZE-NEXT: EntSize: 0x0000000000000003
+# INFO-NEXT: Info: 0x0000000000000003
+# ADDRALIGN-NEXT: AddressAlign: 0x0000000000000003
+# ADDRESS-NEXT: Address: 0x0000000000002020
+
+# ARANGE: DWARF:
+# ARANGE-NEXT: debug_aranges:
+# ARANGE-NEXT: - Length: 0x000000000000001C
+# ARANGE-NEXT: Version: 2
+# ARANGE-NEXT: CuOffset: 0x0000000000001234
+# ARANGE-NEXT: AddressSize: 0x08
+# ARANGE-NEXT: ...
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+Sections:
+ - Name: .debug_aranges
+ Type: [[TYPE=SHT_PROGBITS]]
+ Flags: [[FLAGS=<none>]]
+ Link: [[LINK='']]
+ EntSize: [[ENTSIZE=<none>]]
+ Info: [[INFO=<none>]]
+ AddressAlign: [[ADDRALIGN=0]]
+ Address: [[ADDRESS=<none>]]
+ - Name: .sec
+ Type: SHT_PROGBITS
+DWARF:
+ debug_aranges:
+ - Version: 2
+ CuOffset: 0x1234
+
+## c) Test dumping a .debug_aranges section whose address_size doesn't match the
+## object file's address size.
+
+# RUN: yaml2obj --docnum=3 %s | obj2yaml | \
+# RUN: FileCheck %s -DLENGTH=0x000000000000001C -DADDRSIZE=0x04 -DADDRLEN=0x0000000012345678 --check-prefix=ADDRSIZE
+
+# ADDRSIZE: DWARF:
+# ADDRSIZE-NEXT: debug_aranges:
+# ADDRSIZE-NEXT: - Length: [[LENGTH]]
+# ADDRSIZE-NEXT: Version: 2
+# ADDRSIZE-NEXT: CuOffset: 0x0000000000001234
+# ADDRSIZE-NEXT: AddressSize: [[ADDRSIZE]]
+# ADDRSIZE-NEXT: Descriptors:
+# ADDRSIZE-NEXT: - Address: [[ADDRLEN]]
+# ADDRSIZE-NEXT: Length: [[ADDRLEN]]
+# ADDRSIZE-NEXT: ...
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS[[BITS=64]]
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+DWARF:
+ debug_aranges:
+ - Version: 2
+ CuOffset: 0x1234
+ AddressSize: [[ADDRSIZE=0x04]]
+ Descriptors:
+ - Address: [[ADDRLEN=0x12345678]]
+ Length: [[ADDRLEN=0x12345678]]
+
+# RUN: yaml2obj --docnum=3 -DBITS=32 -DADDRSIZE=0x08 -DADDRLEN=0x1234567890abcdef %s | \
+# RUN: obj2yaml | \
+# RUN: FileCheck %s -DLENGTH=0x000000000000002C -DADDRSIZE=0x08 -DADDRLEN=0x1234567890ABCDEF --check-prefix=ADDRSIZE
+
+## d) Test dumping a .debug_aranges section whose length field doesn't match the actual length.
+## This makes the DWARF parser fail to parse it and we will dump it as a raw content section.
+
+# RUN: yaml2obj --docnum=4 %s | obj2yaml | FileCheck %s --check-prefix=RAW-CONTENT
+
+# RAW-CONTENT: Sections:
+# RAW-CONTENT-NEXT: - Name: .debug_aranges
+# RAW-CONTENT-NEXT: Type: SHT_PROGBITS
+# RAW-CONTENT-NEXT: AddressAlign: 0x0000000000000001
+# RAW-CONTENT-NEXT: Content: '3412000002003412000008000000000000000000000000000000000000000000'
+# RAW-CONTENT-NEXT: ...
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+DWARF:
+ debug_aranges:
+ - Length: 0x1234
+ Version: 2
+ CuOffset: 0x1234
diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index b45098538f87..d36d6227334d 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -7,10 +7,13 @@
//===----------------------------------------------------------------------===//
#include "Error.h"
+#include "obj2yaml.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/ObjectYAML/DWARFYAML.h"
#include "llvm/ObjectYAML/ELFYAML.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/ErrorHandling.h"
@@ -50,11 +53,15 @@ class ELFDumper {
Expected<StringRef> getSymbolName(uint32_t SymtabNdx, uint32_t SymbolNdx);
const object::ELFFile<ELFT> &Obj;
+ std::unique_ptr<DWARFContext> DWARFCtx;
ArrayRef<Elf_Word> ShndxTable;
Expected<std::vector<ELFYAML::ProgramHeader>>
dumpProgramHeaders(ArrayRef<std::unique_ptr<ELFYAML::Chunk>> Sections);
+ Optional<DWARFYAML::Data>
+ dumpDWARFSections(std::vector<std::unique_ptr<ELFYAML::Chunk>> &Sections);
+
Error dumpSymbols(const Elf_Shdr *Symtab,
std::vector<ELFYAML::Symbol> &Symbols);
Error dumpSymbol(const Elf_Sym *Sym, const Elf_Shdr *SymTab,
@@ -95,18 +102,20 @@ class ELFDumper {
Expected<ELFYAML::RawContentSection *>
dumpPlaceholderSection(const Elf_Shdr *Shdr);
- bool shouldPrintSection(const ELFYAML::Section &S, const Elf_Shdr &SHdr);
+ bool shouldPrintSection(const ELFYAML::Section &S, const Elf_Shdr &SHdr,
+ Optional<DWARFYAML::Data> DWARF);
public:
- ELFDumper(const object::ELFFile<ELFT> &O);
+ ELFDumper(const object::ELFFile<ELFT> &O, std::unique_ptr<DWARFContext> DCtx);
Expected<ELFYAML::Object *> dump();
};
}
template <class ELFT>
-ELFDumper<ELFT>::ELFDumper(const object::ELFFile<ELFT> &O)
- : Obj(O) {}
+ELFDumper<ELFT>::ELFDumper(const object::ELFFile<ELFT> &O,
+ std::unique_ptr<DWARFContext> DCtx)
+ : Obj(O), DWARFCtx(std::move(DCtx)) {}
template <class ELFT>
Expected<StringRef>
@@ -173,7 +182,8 @@ ELFDumper<ELFT>::getUniquedSymbolName(const Elf_Sym *Sym, StringRef StrTable,
template <class ELFT>
bool ELFDumper<ELFT>::shouldPrintSection(const ELFYAML::Section &S,
- const Elf_Shdr &SHdr) {
+ const Elf_Shdr &SHdr,
+ Optional<DWARFYAML::Data> DWARF) {
// We only print the SHT_NULL section at index 0 when it
// has at least one non-null field, because yaml2obj
// normally creates the zero section at index 0 implicitly.
@@ -183,6 +193,19 @@ bool ELFDumper<ELFT>::shouldPrintSection(const ELFYAML::Section &S,
return std::find_if(Begin, End, [](uint8_t V) { return V != 0; }) != End;
}
+ // Normally we use "DWARF:" to describe contents of DWARF sections. Sometimes
+ // the content of DWARF sections can be successfully parsed into the "DWARF:"
+ // entry but their section headers may have special flags, entry size, address
+ // alignment, etc. We will preserve the header for them under such
+ // circumstances.
+ if (DWARF && DWARF->getNonEmptySectionNames().count(S.Name.substr(1))) {
+ if (const ELFYAML::RawContentSection *RawSec =
+ dyn_cast<const ELFYAML::RawContentSection>(&S))
+ return RawSec->Type != ELF::SHT_PROGBITS || RawSec->Flags ||
+ !RawSec->Link.empty() || RawSec->Info ||
+ RawSec->AddressAlign != 1 || RawSec->EntSize;
+ }
+
// Normally we use "Symbols:" and "DynamicSymbols:" to describe contents of
// symbol tables. We also build and emit corresponding string tables
// implicitly. But sometimes it is important to preserve positions and virtual
@@ -284,9 +307,12 @@ template <class ELFT> Expected<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
return PhdrsOrErr.takeError();
Y->ProgramHeaders = std::move(*PhdrsOrErr);
- llvm::erase_if(Chunks, [this](const std::unique_ptr<ELFYAML::Chunk> &C) {
+ // Dump DWARF sections.
+ Y->DWARF = dumpDWARFSections(Chunks);
+
+ llvm::erase_if(Chunks, [this, &Y](const std::unique_ptr<ELFYAML::Chunk> &C) {
const ELFYAML::Section &S = cast<ELFYAML::Section>(*C.get());
- return !shouldPrintSection(S, Sections[S.OriginalSecNdx]);
+ return !shouldPrintSection(S, Sections[S.OriginalSecNdx], Y->DWARF);
});
Y->Chunks = std::move(Chunks);
@@ -363,6 +389,36 @@ ELFDumper<ELFT>::dumpProgramHeaders(
return Ret;
}
+template <class ELFT>
+Optional<DWARFYAML::Data> ELFDumper<ELFT>::dumpDWARFSections(
+ std::vector<std::unique_ptr<ELFYAML::Chunk>> &Sections) {
+ DWARFYAML::Data DWARF;
+ for (std::unique_ptr<ELFYAML::Chunk> &C : Sections) {
+ if (!C->Name.startswith(".debug_"))
+ continue;
+
+ if (ELFYAML::RawContentSection *RawSec =
+ dyn_cast<ELFYAML::RawContentSection>(C.get())) {
+ Error Err = Error::success();
+ cantFail(std::move(Err));
+
+ if (RawSec->Name == ".debug_aranges")
+ Err = dumpDebugARanges(*DWARFCtx.get(), DWARF);
+
+ // If the DWARF section cannot be successfully parsed, emit raw content
+ // instead of an entry in the DWARF section of the YAML.
+ if (Err)
+ consumeError(std::move(Err));
+ else
+ RawSec->Content.reset();
+ }
+ }
+
+ if (DWARF.getNonEmptySectionNames().empty())
+ return None;
+ return DWARF;
+}
+
template <class ELFT>
Expected<ELFYAML::RawContentSection *>
ELFDumper<ELFT>::dumpPlaceholderSection(const Elf_Shdr *Shdr) {
@@ -1298,8 +1354,9 @@ ELFDumper<ELFT>::dumpMipsABIFlags(const Elf_Shdr *Shdr) {
}
template <class ELFT>
-static Error elf2yaml(raw_ostream &Out, const object::ELFFile<ELFT> &Obj) {
- ELFDumper<ELFT> Dumper(Obj);
+static Error elf2yaml(raw_ostream &Out, const object::ELFFile<ELFT> &Obj,
+ std::unique_ptr<DWARFContext> DWARFCtx) {
+ ELFDumper<ELFT> Dumper(Obj, std::move(DWARFCtx));
Expected<ELFYAML::Object *> YAMLOrErr = Dumper.dump();
if (!YAMLOrErr)
return YAMLOrErr.takeError();
@@ -1312,17 +1369,18 @@ static Error elf2yaml(raw_ostream &Out, const object::ELFFile<ELFT> &Obj) {
}
Error elf2yaml(raw_ostream &Out, const object::ObjectFile &Obj) {
+ std::unique_ptr<DWARFContext> DWARFCtx = DWARFContext::create(Obj);
if (const auto *ELFObj = dyn_cast<object::ELF32LEObjectFile>(&Obj))
- return elf2yaml(Out, *ELFObj->getELFFile());
+ return elf2yaml(Out, *ELFObj->getELFFile(), std::move(DWARFCtx));
if (const auto *ELFObj = dyn_cast<object::ELF32BEObjectFile>(&Obj))
- return elf2yaml(Out, *ELFObj->getELFFile());
+ return elf2yaml(Out, *ELFObj->getELFFile(), std::move(DWARFCtx));
if (const auto *ELFObj = dyn_cast<object::ELF64LEObjectFile>(&Obj))
- return elf2yaml(Out, *ELFObj->getELFFile());
+ return elf2yaml(Out, *ELFObj->getELFFile(), std::move(DWARFCtx));
if (const auto *ELFObj = dyn_cast<object::ELF64BEObjectFile>(&Obj))
- return elf2yaml(Out, *ELFObj->getELFFile());
+ return elf2yaml(Out, *ELFObj->getELFFile(), std::move(DWARFCtx));
llvm_unreachable("unknown ELF file format");
}
diff --git a/llvm/tools/obj2yaml/obj2yaml.h b/llvm/tools/obj2yaml/obj2yaml.h
index b538ff87ac2b..9dcb2fac3b83 100644
--- a/llvm/tools/obj2yaml/obj2yaml.h
+++ b/llvm/tools/obj2yaml/obj2yaml.h
@@ -41,5 +41,6 @@ struct Data;
}
llvm::Error dwarf2yaml(llvm::DWARFContext &DCtx, llvm::DWARFYAML::Data &Y);
-
+llvm::Error dumpDebugARanges(llvm::DWARFContext &DCtx,
+ llvm::DWARFYAML::Data &Y);
#endif
More information about the llvm-commits
mailing list