[llvm] r361165 - [llvm-readelf] - Rework how we parse the .dynamic section.

George Rimar via llvm-commits llvm-commits at lists.llvm.org
Mon May 20 08:41:48 PDT 2019


Author: grimar
Date: Mon May 20 08:41:48 2019
New Revision: 361165

URL: http://llvm.org/viewvc/llvm-project?rev=361165&view=rev
Log:
[llvm-readelf] - Rework how we parse the .dynamic section.

This is a result of what I found during my work on https://bugs.llvm.org/show_bug.cgi?id=41679.

Previously LLVM readelf took the information about .dynamic section
from its PT_DYNAMIC segment only. GNU tools have a bit different logic.
They also use the information from the .dynamic section header if it is available.
This patch changes the code to improve the compatibility with the GNU Binutils.

Differential revision: https://reviews.llvm.org/D61937


Added:
    llvm/trunk/test/tools/llvm-readobj/elf-dynamic-not-in-pt-dynamic.test
    llvm/trunk/test/tools/llvm-readobj/elf-non-dynamic-in-pt-dynamic.test
Modified:
    llvm/trunk/test/Object/Inputs/corrupt-invalid-dynamic-table-size.elf.x86-64
    llvm/trunk/test/Object/corrupt.test
    llvm/trunk/test/tools/llvm-readobj/elf-malformed-pt-dynamic.test
    llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
    llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp
    llvm/trunk/tools/llvm-readobj/llvm-readobj.h

Modified: llvm/trunk/test/Object/Inputs/corrupt-invalid-dynamic-table-size.elf.x86-64
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/corrupt-invalid-dynamic-table-size.elf.x86-64?rev=361165&r1=361164&r2=361165&view=diff
==============================================================================
Binary files llvm/trunk/test/Object/Inputs/corrupt-invalid-dynamic-table-size.elf.x86-64 (original) and llvm/trunk/test/Object/Inputs/corrupt-invalid-dynamic-table-size.elf.x86-64 Mon May 20 08:41:48 2019 differ

Modified: llvm/trunk/test/Object/corrupt.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/corrupt.test?rev=361165&r1=361164&r2=361165&view=diff
==============================================================================
--- llvm/trunk/test/Object/corrupt.test (original)
+++ llvm/trunk/test/Object/corrupt.test Mon May 20 08:41:48 2019
@@ -62,11 +62,11 @@ RUN: not llvm-readobj --dyn-relocations
 RUN:   %p/Inputs/corrupt-invalid-dynamic-table-offset.elf.x86-64 2>&1 | \
 RUN:   FileCheck --check-prefix=DYN-TABLE-OFFSET %s
 
-DYN-TABLE-OFFSET: error: Invalid data was encountered while parsing the file
+DYN-TABLE-OFFSET: error: PT_DYNAMIC segment offset + size exceeds the size of the file
 
 
 RUN: not llvm-readobj --dyn-relocations \
 RUN:   %p/Inputs/corrupt-invalid-dynamic-table-too-large.elf.x86-64 2>&1 | \
 RUN:   FileCheck --check-prefix=DYN-TABLE-TOO-LARGE %s
 
-DYN-TABLE-TOO-LARGE: error: Invalid data was encountered while parsing the file
+DYN-TABLE-TOO-LARGE: error: PT_DYNAMIC segment offset + size exceeds the size of the file

Added: llvm/trunk/test/tools/llvm-readobj/elf-dynamic-not-in-pt-dynamic.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/elf-dynamic-not-in-pt-dynamic.test?rev=361165&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/elf-dynamic-not-in-pt-dynamic.test (added)
+++ llvm/trunk/test/tools/llvm-readobj/elf-dynamic-not-in-pt-dynamic.test Mon May 20 08:41:48 2019
@@ -0,0 +1,47 @@
+## Show that llvm-readobj/llvm-readelf tools can dump the .dynamic
+## section when it is not in a PT_DYNAMIC segment.
+
+# RUN: yaml2obj %s -o %t.o
+# RUN: llvm-readobj --dynamic-table %t.o 2>&1 | FileCheck %s
+# RUN: llvm-readelf --dynamic-table %t.o 2>&1 | FileCheck %s
+
+# CHECK:      warning: The SHT_DYNAMIC section '.dynamic' is not contained within the PT_DYNAMIC segment
+# CHECK:      DynamicSection [ (2 entries)
+# CHECK-NEXT:   Tag                Type     Name/Value
+# CHECK-NEXT:   0x0000000000000018 BIND_NOW 0x1
+# CHECK-NEXT:   0x0000000000000000 NULL     0x0
+# CHECK-NEXT: ]
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name: .dynamic
+    Type: SHT_DYNAMIC
+    Flags: [SHF_ALLOC]
+    Address: 0x1000
+    AddressAlign: 0x1000
+    Entries:
+      - Tag:   DT_BIND_NOW
+        Value: 0x1
+      - Tag:   DT_NULL
+        Value: 0x0
+  - Name: .text
+    Type: SHT_PROGBITS
+    Flags: [SHF_ALLOC]
+    Address: 0x1100
+    AddressAlign: 0x100
+    Content: "00"
+ProgramHeaders:
+  - Type: PT_LOAD
+    VAddr: 0x1000
+    Sections:
+      - Section: .dynamic
+      - Section: .text
+  - Type: PT_DYNAMIC
+    VAddr: 0x1000
+    Sections:
+      - Section: .text

Modified: llvm/trunk/test/tools/llvm-readobj/elf-malformed-pt-dynamic.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/elf-malformed-pt-dynamic.test?rev=361165&r1=361164&r2=361165&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/elf-malformed-pt-dynamic.test (original)
+++ llvm/trunk/test/tools/llvm-readobj/elf-malformed-pt-dynamic.test Mon May 20 08:41:48 2019
@@ -1,6 +1,5 @@
 # If the offset and/or size fields of the PT_DYNAMIC field become corrupted,
-# it will be impossible to read the dynamic segment validly. This test shows
-# that a sensible error message is given in this situation.
+# we should report a sensible error message.
 
 # Creating such a malformed file is hard. The easiest way to simulate it is to
 # truncate the file. Note that the section headers must first be stripped or
@@ -21,7 +20,7 @@
 # RUN: %python -c "with open(r'%t.truncated2', 'r+') as f: f.truncate(0xFFF)"
 # RUN: not llvm-readobj %t.truncated2 --dynamic-table 2>&1 | FileCheck %s
 
-# CHECK: error: Invalid data was encountered while parsing the file
+# CHECK: error: PT_DYNAMIC segment offset + size exceeds the size of the file
 
 --- !ELF
 FileHeader:

Added: llvm/trunk/test/tools/llvm-readobj/elf-non-dynamic-in-pt-dynamic.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/elf-non-dynamic-in-pt-dynamic.test?rev=361165&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/elf-non-dynamic-in-pt-dynamic.test (added)
+++ llvm/trunk/test/tools/llvm-readobj/elf-non-dynamic-in-pt-dynamic.test Mon May 20 08:41:48 2019
@@ -0,0 +1,92 @@
+## Show that llvm-readobj/llvm-readelf tools can dump the .dynamic section which
+## is not alone in PT_DYNAMIC segment.
+
+## In the first case .text is placed before .dynamic.
+## We check that we warn about this case.
+
+# RUN: yaml2obj --docnum=1 %s -o %t.o
+# RUN: llvm-readobj --dynamic-table %t.o 2>&1 | FileCheck %s --check-prefixes=WARNING,CHECK
+# RUN: llvm-readelf --dynamic-table %t.o 2>&1 | FileCheck %s --check-prefixes=WARNING,CHECK
+
+# WARNING:    warning: The SHT_DYNAMIC section '.dynamic' is not at the start of PT_DYNAMIC segment
+# CHECK:      DynamicSection [ (2 entries)
+# CHECK-NEXT:   Tag                Type     Name/Value
+# CHECK-NEXT:   0x0000000000000018 BIND_NOW 0x1
+# CHECK-NEXT:   0x0000000000000000 NULL     0x0
+# CHECK-NEXT: ]
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name: .text
+    Type: SHT_PROGBITS
+    Flags: [SHF_ALLOC]
+    Address: 0x1000
+    AddressAlign: 0x100
+    Content: "00"
+  - Name: .dynamic
+    Type: SHT_DYNAMIC
+    Flags: [SHF_ALLOC]
+    Address: 0x1100
+    AddressAlign: 0x1000
+    Entries:
+      - Tag:   DT_BIND_NOW
+        Value: 0x1
+      - Tag:   DT_NULL
+        Value: 0x0
+ProgramHeaders:
+  - Type: PT_LOAD
+    VAddr: 0x1000
+    Sections:
+      - Section: .text
+      - Section: .dynamic
+  - Type: PT_DYNAMIC
+    VAddr: 0x1000
+    Sections:
+      - Section: .text
+      - Section: .dynamic
+
+## In the second case .text goes after .dynamic and we don't display any warnings.
+
+# RUN: yaml2obj --docnum=2 %s -o %t.o
+# RUN: llvm-readobj --dynamic-table %t.o | FileCheck %s --implicit-check-not="warning"
+# RUN: llvm-readelf --dynamic-table %t.o | FileCheck %s --implicit-check-not="warning"
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_EXEC
+  Machine: EM_X86_64
+Sections:
+  - Name: .dynamic
+    Type: SHT_DYNAMIC
+    Flags: [SHF_ALLOC]
+    Address: 0x1000
+    AddressAlign: 0x1000
+    Entries:
+      - Tag:   DT_BIND_NOW
+        Value: 0x1
+      - Tag:   DT_NULL
+        Value: 0x0
+  - Name: .text
+    Type: SHT_PROGBITS
+    Flags: [SHF_ALLOC]
+    Address: 0x1100
+    AddressAlign: 0x100
+    Content: "00"
+ProgramHeaders:
+  - Type: PT_LOAD
+    VAddr: 0x1000
+    Sections:
+      - Section: .dynamic
+      - Section: .text
+  - Type: PT_DYNAMIC
+    VAddr: 0x1000
+    Sections:
+      - Section: .dynamic
+      - Section: .text

Modified: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ELFDumper.cpp?rev=361165&r1=361164&r2=361165&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp Mon May 20 08:41:48 2019
@@ -203,7 +203,8 @@ private:
         {ObjF->getELFFile()->base() + S->sh_offset, S->sh_size, S->sh_entsize});
   }
 
-  void parseDynamicTable(ArrayRef<const Elf_Phdr *> LoadSegments);
+  void loadDynamicTable(const ELFFile<ELFT> *Obj);
+  void parseDynamicTable();
 
   void printValue(uint64_t Type, uint64_t Value);
 
@@ -1329,21 +1330,72 @@ static const char *getElfMipsOptionsOdkT
 }
 
 template <typename ELFT>
-ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,
-    ScopedPrinter &Writer)
-    : ObjDumper(Writer), ObjF(ObjF) {
-  SmallVector<const Elf_Phdr *, 4> LoadSegments;
-  const ELFFile<ELFT> *Obj = ObjF->getELFFile();
+void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) {
+  const Elf_Phdr *DynamicPhdr = nullptr;
   for (const Elf_Phdr &Phdr : unwrapOrError(Obj->program_headers())) {
-    if (Phdr.p_type == ELF::PT_DYNAMIC) {
-      DynamicTable = createDRIFrom(&Phdr, sizeof(Elf_Dyn));
+    if (Phdr.p_type != ELF::PT_DYNAMIC)
       continue;
-    }
-    if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0)
+    DynamicPhdr = &Phdr;
+    break;
+  }
+
+  // We do not want to dump dynamic section if we have no PT_DYNAMIC header.
+  // This matches GNU's behavior.
+  if (!DynamicPhdr)
+    return;
+
+  // Try to locate the .dynamic section in the sections header table.
+  const Elf_Shdr *DynamicSec = nullptr;
+  for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) {
+    if (Sec.sh_type != ELF::SHT_DYNAMIC)
       continue;
-    LoadSegments.push_back(&Phdr);
+    DynamicSec = &Sec;
+    break;
+  }
+
+  // Information in the section header has priority over the information
+  // in a PT_DYNAMIC header.
+  // Ignore sh_entsize and use the expected value for entry size explicitly.
+  // This allows us to dump the dynamic sections with a broken sh_entsize
+  // field.
+  if (DynamicSec)
+    DynamicTable = checkDRI({ObjF->getELFFile()->base() + DynamicSec->sh_offset,
+                             DynamicSec->sh_size, sizeof(Elf_Dyn)});
+
+  if (DynamicPhdr->p_offset + DynamicPhdr->p_filesz >
+      ObjF->getMemoryBufferRef().getBufferSize())
+    reportError(
+        "PT_DYNAMIC segment offset + size exceeds the size of the file");
+
+  if (!DynamicSec) {
+    DynamicTable = createDRIFrom(DynamicPhdr, sizeof(Elf_Dyn));
+    parseDynamicTable();
+    return;
   }
 
+  StringRef Name = unwrapOrError(Obj->getSectionName(DynamicSec));
+
+  if (DynamicSec->sh_addr + DynamicSec->sh_size >
+          DynamicPhdr->p_vaddr + DynamicPhdr->p_memsz ||
+      DynamicSec->sh_addr < DynamicPhdr->p_vaddr)
+    reportWarning("The SHT_DYNAMIC section '" + Name +
+                  "' is not contained within the "
+                  "PT_DYNAMIC segment");
+
+  if (DynamicSec->sh_addr != DynamicPhdr->p_vaddr)
+    reportWarning("The SHT_DYNAMIC section '" + Name +
+                  "' is not at the start of "
+                  "PT_DYNAMIC segment");
+
+  parseDynamicTable();
+}
+
+template <typename ELFT>
+ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,
+    ScopedPrinter &Writer)
+    : ObjDumper(Writer), ObjF(ObjF) {
+  const ELFFile<ELFT> *Obj = ObjF->getELFFile();
+
   for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) {
     switch (Sec.sh_type) {
     case ELF::SHT_SYMTAB:
@@ -1390,7 +1442,7 @@ ELFDumper<ELFT>::ELFDumper(const object:
     }
   }
 
-  parseDynamicTable(LoadSegments);
+  loadDynamicTable(Obj);
 
   if (opts::Output == opts::GNU)
     ELFDumperStyle.reset(new GNUStyle<ELFT>(Writer, this));
@@ -1398,9 +1450,7 @@ ELFDumper<ELFT>::ELFDumper(const object:
     ELFDumperStyle.reset(new LLVMStyle<ELFT>(Writer, this));
 }
 
-template <typename ELFT>
-void ELFDumper<ELFT>::parseDynamicTable(
-    ArrayRef<const Elf_Phdr *> LoadSegments) {
+template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() {
   auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * {
     auto MappedAddrOrError = ObjF->getELFFile()->toMappedAddr(VAddr);
     if (!MappedAddrOrError)

Modified: llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp?rev=361165&r1=361164&r2=361165&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp Mon May 20 08:41:48 2019
@@ -373,6 +373,11 @@ LLVM_ATTRIBUTE_NORETURN void reportError
   exit(1);
 }
 
+void reportWarning(Twine Msg) {
+  errs() << "\n";
+  WithColor::warning(errs()) << Msg << "\n";
+}
+
 void error(Error EC) {
   if (!EC)
     return;

Modified: llvm/trunk/tools/llvm-readobj/llvm-readobj.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/llvm-readobj.h?rev=361165&r1=361164&r2=361165&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/llvm-readobj.h (original)
+++ llvm/trunk/tools/llvm-readobj/llvm-readobj.h Mon May 20 08:41:48 2019
@@ -22,6 +22,7 @@ namespace llvm {
 
   // Various helper functions.
   LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
+  void reportWarning(Twine Msg);
   void error(std::error_code EC);
   void error(llvm::Error EC);
   template <typename T> T error(llvm::Expected<T> &&E) {




More information about the llvm-commits mailing list