# RUN: llvm-readelf --all %t.bad-size 2>&1 \
# RUN: | FileCheck %s -DFILE=%t.bad-size --implicit-check-not=warning --check-prefix WARN-GNU
-# WARN-NOT: warning
# WARN: warning: '[[FILE]]': invalid section size (4) or entity size (16)
+# WARN: warning: '[[FILE]]': invalid section size (4) or entity size (16)
+# WARN: warning: '[[FILE]]': no valid dynamic table was found
# WARN-EMPTY:
-# WARN-NEXT: File:
-# WARN: Symbols [
-# WARN: ]
-# WARN-EMPTY:
-## A warning is printed at the place where a normal dynamic table should be.
-# WARN-NEXT: warning: '[[FILE]]': invalid section size (4) or entity size (16)
-# WARN-NEXT: ProgramHeaders [
-
-# WARN-GNU-NOT: warning
-# WARN-GNU: warning: '[[FILE]]': invalid section size (4) or entity size (16)
+# WARN: File:
+# WARN: Symbols [
+# WARN: ]
+# WARN: ProgramHeaders [
+
+# WARN-GNU: warning: '[[FILE]]': invalid section size (4) or entity size (16)
+# WARN-GNU: warning: '[[FILE]]': invalid section size (4) or entity size (16)
+# WARN-GNU: warning: '[[FILE]]': no valid dynamic table was found
# WARN-GNU-NEXT: ELF Header:
# WARN-GNU: Symbol table '.symtab' contains 1 entries:
# WARN-GNU: 0:
-# WARN-GNU-EMPTY:
-## A warning is printed at the place where a normal dynamic table should be.
-# WARN-GNU: warning: '[[FILE]]': invalid section size (4) or entity size (16)
-# WARN-GNU-EMPTY:
--- !ELF
FileHeader:
-## Show that llvm-readobj/llvm-readelf tools can dump the .dynamic
-## section when it is not in a PT_DYNAMIC segment.
+## Show that llvm-readobj/llvm-readelf tools sometimes can dump the
+## dynamic table when it is not in a PT_DYNAMIC segment.
-# RUN: yaml2obj %s -o %t.o
-# RUN: llvm-readobj --dynamic-table %t.o 2>&1 \
-# RUN: | FileCheck -DFILE=%t.o --check-prefixes=WARNING,LLVM %s
-# RUN: llvm-readelf --dynamic-table %t.o 2>&1 \
-# RUN: | FileCheck -DFILE=%t.o --check-prefixes=WARNING,GNU %s
+## Case 1: The dynamic table found using the dynamic program header is corrupted
+## (<size of data> % <size of dynamic entry> != 0). So the table is taken
+## from the section header.
-# WARNING: warning: '[[FILE]]': The SHT_DYNAMIC section '.dynamic' is not contained within the PT_DYNAMIC segment
+# RUN: yaml2obj --docnum=1 %s -o %t1.o
+# RUN: llvm-readobj --dynamic-table %t1.o 2>&1 \
+# RUN: | FileCheck -DFILE=%t1.o --check-prefixes=WARNING1,LLVM1 %s
+# RUN: llvm-readelf --dynamic-table %t1.o 2>&1 \
+# RUN: | FileCheck -DFILE=%t1.o --check-prefixes=WARNING1,GNU1 %s
-# LLVM: DynamicSection [ (2 entries)
-# LLVM-NEXT: Tag Type Name/Value
-# LLVM-NEXT: 0x0000000000000018 BIND_NOW 0x1
-# LLVM-NEXT: 0x0000000000000000 NULL 0x0
-# LLVM-NEXT: ]
+# WARNING1: warning: '[[FILE]]': The SHT_DYNAMIC section '.dynamic' is not contained within the PT_DYNAMIC segment
+# WARNING1: warning: '[[FILE]]': invalid section size (1) or entity size (16)
+# WARNING1: warning: '[[FILE]]': SHT_DYNAMIC section header and PT_DYNAMIC program header disagree about the location of the dynamic table
+# WARNING1: warning: '[[FILE]]': PT_DYNAMIC dynamic table is invalid: SHT_DYNAMIC will be used
-# GNU: Dynamic section at offset 0x{{.*}} contains 2 entries:
-# GNU-NEXT: Tag Type Name/Value
-# GNU-NEXT: 0x0000000000000018 (BIND_NOW) 0x1
-# GNU-NEXT: 0x0000000000000000 (NULL) 0x0
+# LLVM1: DynamicSection [ (2 entries)
+# LLVM1-NEXT: Tag Type Name/Value
+# LLVM1-NEXT: 0x0000000000000018 BIND_NOW 0x1
+# LLVM1-NEXT: 0x0000000000000000 NULL 0x0
+# LLVM1-NEXT: ]
+
+# GNU1: Dynamic section at offset 0x{{.*}} contains 2 entries:
+# GNU1-NEXT: Tag Type Name/Value
+# GNU1-NEXT: 0x0000000000000018 (BIND_NOW) 0x1
+# GNU1-NEXT: 0x0000000000000000 (NULL) 0x0
+
+--- !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
+
+## Case 2: The dynamic table found using the dynamic program header is different from the
+## table found using the section header table.
+
+# RUN: yaml2obj --docnum=2 %s -o %t2.o
+# RUN: llvm-readobj --dynamic-table %t2.o 2>&1 \
+# RUN: | FileCheck -DFILE=%t2.o --check-prefixes=WARNING2,LLVM2 %s
+# RUN: llvm-readelf --dynamic-table %t2.o 2>&1 \
+# RUN: | FileCheck -DFILE=%t2.o --check-prefixes=WARNING2,GNU2 %s
+
+# WARNING2: warning: '[[FILE]]': The SHT_DYNAMIC section '.dynamic' is not contained within the PT_DYNAMIC segment
+# WARNING2: warning: '[[FILE]]': SHT_DYNAMIC section header and PT_DYNAMIC program header disagree about the location of the dynamic table
+
+# LLVM2: DynamicSection [ (1 entries)
+# LLVM2-NEXT: Tag Type Name/Value
+# LLVM2-NEXT: 0x0000000000000000 NULL 0x0
+# LLVM2-NEXT: ]
+
+# GNU2: Dynamic section at offset 0x{{.*}} contains 1 entries:
+# GNU2-NEXT: Tag Type Name/Value
+# GNU2-NEXT: 0x0000000000000000 (NULL) 0x0
--- !ELF
FileHeader:
Flags: [SHF_ALLOC]
Address: 0x1100
AddressAlign: 0x100
+ Content: "00000000000000000000000000000000"
+ProgramHeaders:
+ - Type: PT_LOAD
+ VAddr: 0x1000
+ Sections:
+ - Section: .dynamic
+ - Section: .text
+ - Type: PT_DYNAMIC
+ VAddr: 0x1000
+ Sections:
+ - Section: .text
+
+## Case 3: Both dynamic tables found using SHT_DYNAMIC/PT_DYNAMIC are corrupted.
+
+# RUN: yaml2obj --docnum=3 %s -o %t3.o
+# RUN: llvm-readobj --dynamic-table %t3.o 2>&1 \
+# RUN: | FileCheck -DFILE=%t3.o --check-prefix=WARNING3 --implicit-check-not="Dynamic" %s
+# RUN: llvm-readelf --dynamic-table %t3.o 2>&1 \
+# RUN: | FileCheck -DFILE=%t3.o --check-prefix=WARNING3 --implicit-check-not="Dynamic" %s
+
+# WARNING3: warning: '[[FILE]]': invalid section size (1) or entity size (16)
+# WARNING3: warning: '[[FILE]]': SHT_DYNAMIC section header and PT_DYNAMIC program header disagree about the location of the dynamic table
+# WARNING3: warning: '[[FILE]]': no valid dynamic table was found
+
+--- !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
+ Content: "00"
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [SHF_ALLOC]
+ Address: 0x1100
+ AddressAlign: 0x100
Content: "00"
ProgramHeaders:
- Type: PT_LOAD
## 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 \
-# RUN: | FileCheck %s --DFILE=%t.o --check-prefixes=WARNING,LLVM
-# RUN: llvm-readelf --dynamic-table %t.o 2>&1 \
-# RUN: | FileCheck %s --DFILE=%t.o --check-prefixes=WARNING,GNU
+# RUN: yaml2obj --docnum=1 %s -o %t1.o
+# RUN: llvm-readobj --dynamic-table %t1.o 2>&1 \
+# RUN: | FileCheck %s --DFILE=%t1.o --check-prefixes=WARNING,LLVM
+# RUN: llvm-readelf --dynamic-table %t1.o 2>&1 \
+# RUN: | FileCheck %s --DFILE=%t1.o --check-prefixes=WARNING,GNU
-# WARNING: warning: '[[FILE]]': The SHT_DYNAMIC section '.dynamic' is not at the start of PT_DYNAMIC segment
+# WARNING: warning: '[[FILE]]': The SHT_DYNAMIC section '.dynamic' is not at the start of PT_DYNAMIC segment
+# WARNING: warning: '[[FILE]]': invalid section size (33) or entity size (16)
+# WARNING: warning: '[[FILE]]': SHT_DYNAMIC section header and PT_DYNAMIC program header disagree about the location of the dynamic table
+# WARNING: warning: '[[FILE]]': PT_DYNAMIC dynamic table is invalid: SHT_DYNAMIC will be used
# LLVM: DynamicSection [ (2 entries)
# LLVM-NEXT: Tag Type Name/Value
- Name: .dynamic
Type: SHT_DYNAMIC
Flags: [SHF_ALLOC]
- Address: 0x1100
- AddressAlign: 0x1000
+ Address: 0x1001
Entries:
- Tag: DT_BIND_NOW
Value: 0x1
- Section: .text
- Section: .dynamic
-## In the second case .text goes after .dynamic and we don't display any warnings.
+## In this case .text goes after .dynamic and we don't display any warnings,
+## though the content of the .text is used for dumping the dynamic table.
+
+# RUN: yaml2obj --docnum=2 %s -o %t2.o
+# RUN: llvm-readobj --dynamic-table %t2.o 2>&1 | FileCheck %s --check-prefix=LLVM2
+# RUN: llvm-readelf --dynamic-table %t2.o 2>&1 | FileCheck %s --check-prefix=GNU2
+
+# LLVM2: DynamicSection [ (3 entries)
+# LLVM2-NEXT: Tag Type Name/Value
+# LLVM2-NEXT: 0x0000000000000018 BIND_NOW 0x1
+# LLVM2-NEXT: 0x0000000000000018 BIND_NOW 0x2
+# LLVM2-NEXT: 0x0000000000000000 NULL 0x0
+# LLVM2-NEXT: ]
+
+# GNU2: Dynamic section at offset 0x{{.*}} contains 3 entries:
+# GNU2-NEXT: Tag Type Name/Value
+# GNU2-NEXT: 0x0000000000000018 (BIND_NOW) 0x1
+# GNU2-NEXT: 0x0000000000000018 (BIND_NOW) 0x2
+# GNU2-NEXT: 0x0000000000000000 (NULL) 0x0
+
+--- !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_BIND_NOW
+ Value: 0x2
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [SHF_ALLOC]
+ Address: 0x1100
+ AddressAlign: 0x100
+ Content: "00000000000000000000000000000000"
+ProgramHeaders:
+ - Type: PT_LOAD
+ VAddr: 0x1000
+ Sections:
+ - Section: .dynamic
+ - Section: .text
+ - Type: PT_DYNAMIC
+ VAddr: 0x1000
+ Sections:
+ - Section: .dynamic
+ - Section: .text
+
+## In this case .text goes after .dynamic, but (PT_DYNAMIC segment size % dynamic entry size != 0)
+## and we have to use the information from the section header instead.
+
+# RUN: yaml2obj --docnum=3 %s -o %t3.o
+# RUN: llvm-readobj --dynamic-table %t3.o 2>&1 | FileCheck %s --DFILE=%t3.o --check-prefixes=WARNING2,LLVM3
+# RUN: llvm-readelf --dynamic-table %t3.o 2>&1 | FileCheck %s --DFILE=%t3.o --check-prefixes=WARNING2,GNU3
+
+# WARNING2: warning: '[[FILE]]': invalid section size (257) or entity size (16)
+# WARNING2: warning: '[[FILE]]': PT_DYNAMIC dynamic table is invalid: SHT_DYNAMIC will be used
+
+# LLVM3: DynamicSection [ (2 entries)
+# LLVM3-NEXT: Tag Type Name/Value
+# LLVM3-NEXT: 0x0000000000000018 BIND_NOW 0x1
+# LLVM3-NEXT: 0x0000000000000000 NULL 0x0
+# LLVM3-NEXT: ]
-# 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"
+# GNU3: Dynamic section at offset 0x{{.*}} contains 2 entries:
+# GNU3-NEXT: Tag Type Name/Value
+# GNU3-NEXT: 0x0000000000000018 (BIND_NOW) 0x1
+# GNU3-NEXT: 0x0000000000000000 (NULL) 0x0
--- !ELF
FileHeader:
S->sh_entsize, ObjF->getFileName()});
}
+ std::pair<const Elf_Phdr *, const Elf_Shdr *>
+ findDynamic(const ELFFile<ELFT> *Obj);
void loadDynamicTable(const ELFFile<ELFT> *Obj);
void parseDynamicTable();
}
template <typename ELFT>
-void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) {
+std::pair<const typename ELFT::Phdr *, const typename ELFT::Shdr *>
+ELFDumper<ELFT>::findDynamic(const ELFFile<ELFT> *Obj) {
// Try to locate the PT_DYNAMIC header.
const Elf_Phdr *DynamicPhdr = nullptr;
for (const Elf_Phdr &Phdr :
break;
}
- // Information in the section header has priority over the information
- // in a PT_DYNAMIC header.
+ if (DynamicPhdr && DynamicPhdr->p_offset + DynamicPhdr->p_filesz >
+ ObjF->getMemoryBufferRef().getBufferSize()) {
+ reportWarning(
+ createError(
+ "PT_DYNAMIC segment offset + size exceeds the size of the file"),
+ ObjF->getFileName());
+ // Don't use the broken dynamic header.
+ DynamicPhdr = nullptr;
+ }
+
+ if (DynamicPhdr && DynamicSec) {
+ StringRef Name =
+ unwrapOrError(ObjF->getFileName(), Obj->getSectionName(DynamicSec));
+ if (DynamicSec->sh_addr + DynamicSec->sh_size >
+ DynamicPhdr->p_vaddr + DynamicPhdr->p_memsz ||
+ DynamicSec->sh_addr < DynamicPhdr->p_vaddr)
+ reportWarning(createError("The SHT_DYNAMIC section '" + Name +
+ "' is not contained within the "
+ "PT_DYNAMIC segment"),
+ ObjF->getFileName());
+
+ if (DynamicSec->sh_addr != DynamicPhdr->p_vaddr)
+ reportWarning(createError("The SHT_DYNAMIC section '" + Name +
+ "' is not at the start of "
+ "PT_DYNAMIC segment"),
+ ObjF->getFileName());
+ }
+
+ return std::make_pair(DynamicPhdr, DynamicSec);
+}
+
+template <typename ELFT>
+void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) {
+ const Elf_Phdr *DynamicPhdr;
+ const Elf_Shdr *DynamicSec;
+ std::tie(DynamicPhdr, DynamicSec) = findDynamic(Obj);
+ if (!DynamicPhdr && !DynamicSec)
+ return;
+
+ DynRegionInfo FromPhdr(ObjF->getFileName());
+ bool IsPhdrTableValid = false;
+ if (DynamicPhdr) {
+ FromPhdr = createDRIFrom(DynamicPhdr, sizeof(Elf_Dyn));
+ IsPhdrTableValid = !FromPhdr.getAsArrayRef<Elf_Dyn>().empty();
+ }
+
+ // Locate the dynamic table described in a section 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
+ // This allows us to dump dynamic sections with a broken sh_entsize
// field.
+ DynRegionInfo FromSec(ObjF->getFileName());
+ bool IsSecTableValid = false;
if (DynamicSec) {
- DynamicTable =
+ FromSec =
checkDRI({ObjF->getELFFile()->base() + DynamicSec->sh_offset,
DynamicSec->sh_size, sizeof(Elf_Dyn), ObjF->getFileName()});
- parseDynamicTable();
+ IsSecTableValid = !FromSec.getAsArrayRef<Elf_Dyn>().empty();
}
- // If we have a PT_DYNAMIC header, we will either check the found dynamic
- // section or take the dynamic table data directly from the header.
- if (!DynamicPhdr)
- return;
-
- if (DynamicPhdr->p_offset + DynamicPhdr->p_filesz >
- ObjF->getMemoryBufferRef().getBufferSize()) {
- reportWarning(
- createError(
- "PT_DYNAMIC segment offset + size exceeds the size of the file"),
- ObjF->getFileName());
+ // When we only have information from one of the SHT_DYNAMIC section header or
+ // PT_DYNAMIC program header, just use that.
+ if (!DynamicPhdr || !DynamicSec) {
+ if ((DynamicPhdr && IsPhdrTableValid) || (DynamicSec && IsSecTableValid)) {
+ DynamicTable = DynamicPhdr ? FromPhdr : FromSec;
+ parseDynamicTable();
+ } else {
+ reportWarning(createError("no valid dynamic table was found"),
+ ObjF->getFileName());
+ }
return;
}
- if (!DynamicSec) {
- DynamicTable = createDRIFrom(DynamicPhdr, sizeof(Elf_Dyn));
- parseDynamicTable();
- return;
- }
+ // At this point we have tables found from the section header and from the
+ // dynamic segment. Usually they match, but we have to do sanity checks to
+ // verify that.
- StringRef Name =
- unwrapOrError(ObjF->getFileName(), Obj->getSectionName(DynamicSec));
- if (DynamicSec->sh_addr + DynamicSec->sh_size >
- DynamicPhdr->p_vaddr + DynamicPhdr->p_memsz ||
- DynamicSec->sh_addr < DynamicPhdr->p_vaddr)
- reportWarning(createError("The SHT_DYNAMIC section '" + Name +
- "' is not contained within the "
- "PT_DYNAMIC segment"),
+ if (FromPhdr.Addr != FromSec.Addr)
+ reportWarning(createError("SHT_DYNAMIC section header and PT_DYNAMIC "
+ "program header disagree about "
+ "the location of the dynamic table"),
ObjF->getFileName());
- if (DynamicSec->sh_addr != DynamicPhdr->p_vaddr)
- reportWarning(createError("The SHT_DYNAMIC section '" + Name +
- "' is not at the start of "
- "PT_DYNAMIC segment"),
+ if (!IsPhdrTableValid && !IsSecTableValid) {
+ reportWarning(createError("no valid dynamic table was found"),
ObjF->getFileName());
+ return;
+ }
+
+ // Information in the PT_DYNAMIC program header has priority over the information
+ // in a section header.
+ if (IsPhdrTableValid) {
+ if (!IsSecTableValid)
+ reportWarning(
+ createError(
+ "SHT_DYNAMIC dynamic table is invalid: PT_DYNAMIC will be used"),
+ ObjF->getFileName());
+ DynamicTable = FromPhdr;
+ } else {
+ reportWarning(
+ createError(
+ "PT_DYNAMIC dynamic table is invalid: SHT_DYNAMIC will be used"),
+ ObjF->getFileName());
+ DynamicTable = FromSec;
+ }
+
+ parseDynamicTable();
}
template <typename ELFT>