[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