Georgii Rymar 99a6401acc Recommit: [llvm-readelf/obj] - Allow dumping of ELF header even if some elements are corrupt.
This is recommit for D90903 with fixes for BB:
1) Used std::move<> when returning Expected<> (http://lab.llvm.org:8011/#/builders/112/builds/913)
2) Fixed the name of temporarily file in the file-headers.test (http://lab.llvm.org:8011/#/builders/36/builds/1269)
   (a local old temporarily file was used before)

For creating `ELFObjectFile` instances we have the factory method
`ELFObjectFile<ELFT>::create(MemoryBufferRef Object)`.

The problem of this method is that it scans the section header to locate some sections.
When a file is truncated or has broken fields in the ELF header, this approach does
not allow us to create the `ELFObjectFile` and dump the ELF header.

This is https://bugs.llvm.org/show_bug.cgi?id=40804

This patch suggests a solution - it allows to delay scaning sections in the
`ELFObjectFile<ELFT>::create`. It now allows user code to call an object
initialization (`initContent()`) later. With that it is possible,
for example, for dumpers just to dump the file header and exit.
By default initialization is still performed as before, what helps to keep
the logic of existent callers untouched.

I've experimented with different approaches when worked on this patch.
I think this approach is better than doing initialization of sections (i.e. scan of them)
on demand, because normally users of `ELFObjectFile` API expect to work with a valid object.
In most cases when a section header table can't be read (because of an error), we don't
have to continue to work with object. So we probably don't need to implement a more complex API.

Differential revision: https://reviews.llvm.org/D90903
2020-11-09 12:53:53 +03:00

235 lines
9.5 KiB
Plaintext

# RUN: yaml2obj %s --docnum=1 -o %t.i386
# RUN: llvm-readobj -h %t.i386 | FileCheck %s --strict-whitespace --match-full-lines -DFILE=%t.i386 --check-prefix I386
# RUN: llvm-readobj --file-header %t.i386 | FileCheck %s --strict-whitespace --match-full-lines -DFILE=%t.i386 --check-prefix I386
# RUN: llvm-readobj --file-headers %t.i386 | FileCheck %s --strict-whitespace --match-full-lines -DFILE=%t.i386 --check-prefix I386
# I386:File: [[FILE]]
# I386-NEXT:Format: elf32-i386
# I386-NEXT:Arch: i386
# I386-NEXT:AddressSize: 32bit
# I386-NEXT:LoadName: <Not found>
# I386-NEXT:ElfHeader {
# I386-NEXT: Ident {
# I386-NEXT: Magic: (7F 45 4C 46)
# I386-NEXT: Class: 32-bit (0x1)
# I386-NEXT: DataEncoding: LittleEndian (0x1)
# I386-NEXT: FileVersion: 1
# I386-NEXT: OS/ABI: GNU/Linux (0x3)
# I386-NEXT: ABIVersion: 0
# I386-NEXT: Unused: (00 00 00 00 00 00 00)
# I386-NEXT: }
# I386-NEXT: Type: Relocatable (0x1)
# I386-NEXT: Machine: EM_386 (0x3)
# I386-NEXT: Version: 1
# I386-NEXT: Entry: 0x0
# I386-NEXT: ProgramHeaderOffset: 0x0
# I386-NEXT: SectionHeaderOffset: 0x48
# I386-NEXT: Flags [ (0x0)
# I386-NEXT: ]
# I386-NEXT: HeaderSize: 52
# I386-NEXT: ProgramHeaderEntrySize: 0
# I386-NEXT: ProgramHeaderCount: 0
# I386-NEXT: SectionHeaderEntrySize: 40
# I386-NEXT: SectionHeaderCount: 3
# I386-NEXT: StringTableSectionIndex: 2
# I386-NEXT:}
# I386-NOT:{{.}}
--- !ELF
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2LSB
OSABI: ELFOSABI_GNU
Type: ET_REL
Machine: EM_386
# RUN: yaml2obj %s --docnum=2 -o %t.x86-64
# RUN: llvm-readobj -h %t.x86-64 \
# RUN: | FileCheck %s --strict-whitespace --match-full-lines -DFILE=%t.x86-64 --check-prefix X86-64
# RUN: llvm-readobj --file-header %t.x86-64 \
# RUN: | FileCheck %s --strict-whitespace --match-full-lines -DFILE=%t.x86-64 --check-prefix X86-64
# RUN: llvm-readobj --file-headers %t.x86-64 \
# RUN: | FileCheck %s --strict-whitespace --match-full-lines -DFILE=%t.x86-64 --check-prefix X86-64
# X86-64:File: [[FILE]]
# X86-64-NEXT:Format: elf64-x86-64
# X86-64-NEXT:Arch: x86_64
# X86-64-NEXT:AddressSize: 64bit
# X86-64-NEXT:LoadName: <Not found>
# X86-64-NEXT:ElfHeader {
# X86-64-NEXT: Ident {
# X86-64-NEXT: Magic: (7F 45 4C 46)
# X86-64-NEXT: Class: 64-bit (0x2)
# X86-64-NEXT: DataEncoding: LittleEndian (0x1)
# X86-64-NEXT: FileVersion: 1
# X86-64-NEXT: OS/ABI: GNU/Linux (0x3)
# X86-64-NEXT: ABIVersion: 0
# X86-64-NEXT: Unused: (00 00 00 00 00 00 00)
# X86-64-NEXT: }
# X86-64-NEXT: Type: Relocatable (0x1)
# X86-64-NEXT: Machine: EM_X86_64 (0x3E)
# X86-64-NEXT: Version: 1
# X86-64-NEXT: Entry: 0x0
# X86-64-NEXT: ProgramHeaderOffset: 0x0
# X86-64-NEXT: SectionHeaderOffset: 0x58
# X86-64-NEXT: Flags [ (0x0)
# X86-64-NEXT: ]
# X86-64-NEXT: HeaderSize: 64
# X86-64-NEXT: ProgramHeaderEntrySize: 0
# X86-64-NEXT: ProgramHeaderCount: 0
# X86-64-NEXT: SectionHeaderEntrySize: 64
# X86-64-NEXT: SectionHeaderCount: 3
# X86-64-NEXT: StringTableSectionIndex: 2
# X86-64-NEXT:}
# X86-64-NOT:{{.}}
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
OSABI: ELFOSABI_GNU
Type: ET_REL
Machine: EM_X86_64
# RUN: yaml2obj %s --docnum=3 -o %t.lanai
# RUN: llvm-readobj -h %t.lanai \
# RUN: | FileCheck %s --strict-whitespace --match-full-lines -DFILE=%t.lanai --check-prefix LANAI
# RUN: llvm-readobj --file-header %t.lanai \
# RUN: | FileCheck %s --strict-whitespace --match-full-lines -DFILE=%t.lanai --check-prefix LANAI
# RUN: llvm-readobj --file-headers %t.lanai \
# RUN: | FileCheck %s --strict-whitespace --match-full-lines -DFILE=%t.lanai --check-prefix LANAI
--- !ELF
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2MSB
Type: ET_REL
Machine: EM_LANAI
# LANAI:File: [[FILE]]
# LANAI-NEXT:Format: elf32-lanai
# LANAI-NEXT:Arch: lanai
# LANAI-NEXT:AddressSize: 32bit
# LANAI-NEXT:LoadName: <Not found>
# LANAI-NEXT:ElfHeader {
# LANAI-NEXT: Ident {
# LANAI-NEXT: Magic: (7F 45 4C 46)
# LANAI-NEXT: Class: 32-bit (0x1)
# LANAI-NEXT: DataEncoding: BigEndian (0x2)
# LANAI-NEXT: FileVersion: 1
# LANAI-NEXT: OS/ABI: SystemV (0x0)
# LANAI-NEXT: ABIVersion: 0
# LANAI-NEXT: Unused: (00 00 00 00 00 00 00)
# LANAI-NEXT: }
# LANAI-NEXT: Type: Relocatable (0x1)
# LANAI-NEXT: Machine: EM_LANAI (0xF4)
# LANAI-NEXT: Version: 1
# LANAI-NEXT: Entry: 0x0
# LANAI-NEXT: ProgramHeaderOffset: 0x0
# LANAI-NEXT: SectionHeaderOffset: 0x48
# LANAI-NEXT: Flags [ (0x0)
# LANAI-NEXT: ]
# LANAI-NEXT: HeaderSize: 52
# LANAI-NEXT: ProgramHeaderEntrySize: 0
# LANAI-NEXT: ProgramHeaderCount: 0
# LANAI-NEXT: SectionHeaderEntrySize: 40
# LANAI-NEXT: SectionHeaderCount: 3
# LANAI-NEXT: StringTableSectionIndex: 2
# LANAI-NEXT:}
# LANAI-NOT:{{.}}
## Check we are able to dump the file header when the section header table can't be read.
# RUN: yaml2obj %s --docnum=4 -o %t.invalid1
# RUN: not llvm-readobj --file-headers %t.invalid1 2>&1 \
# RUN: | FileCheck %s --implicit-check-not=warning: -DFILE=%t.invalid1 \
# RUN: -DSECHDRCOUNT=8192 -DSECHDRSTRTABINDEX=12288 --check-prefix=INVALID-LLVM
# RUN: not llvm-readelf --file-headers %t.invalid1 2>&1 \
# RUN: | FileCheck %s --implicit-check-not=warning: -DFILE=%t.invalid1 \
# RUN: -DSECHDRCOUNT=8192 -DSECHDRSTRTABINDEX=12288 --check-prefix=INVALID-GNU
# INVALID-LLVM: File: [[FILE]]
# INVALID-LLVM-NEXT: Format: elf64-unknown
# INVALID-LLVM-NEXT: Arch: unknown
# INVALID-LLVM-NEXT: AddressSize: 64bit
# INVALID-LLVM-NEXT: LoadName: <Not found>
# INVALID-LLVM-NEXT: ElfHeader {
# INVALID-LLVM-NEXT: Ident {
# INVALID-LLVM-NEXT: Magic: (7F 45 4C 46)
# INVALID-LLVM-NEXT: Class: 64-bit (0x2)
# INVALID-LLVM-NEXT: DataEncoding: LittleEndian (0x1)
# INVALID-LLVM-NEXT: FileVersion: 1
# INVALID-LLVM-NEXT: OS/ABI: SystemV (0x0)
# INVALID-LLVM-NEXT: ABIVersion: 0
# INVALID-LLVM-NEXT: Unused: (00 00 00 00 00 00 00)
# INVALID-LLVM-NEXT: }
# INVALID-LLVM-NEXT: Type: Relocatable (0x1)
# INVALID-LLVM-NEXT: Machine: EM_NONE (0x0)
# INVALID-LLVM-NEXT: Version: 1
# INVALID-LLVM-NEXT: Entry: 0x0
# INVALID-LLVM-NEXT: ProgramHeaderOffset: 0x0
# INVALID-LLVM-NEXT: SectionHeaderOffset: 0x1000
# INVALID-LLVM-NEXT: Flags [ (0x0)
# INVALID-LLVM-NEXT: ]
# INVALID-LLVM-NEXT: HeaderSize: 64
# INVALID-LLVM-NEXT: ProgramHeaderEntrySize: 0
# INVALID-LLVM-NEXT: ProgramHeaderCount: 0
# INVALID-LLVM-NEXT: SectionHeaderEntrySize: 64
# INVALID-LLVM-NEXT: SectionHeaderCount: [[SECHDRCOUNT]]
# INVALID-LLVM-NEXT: StringTableSectionIndex: [[SECHDRSTRTABINDEX]]
# INVALID-LLVM-NEXT: }
# INVALID-LLVM-NEXT: error: '[[FILE]]': unable to continue dumping, the file is corrupt: section header table goes past the end of the file: e_shoff = 0x1000
# INVALID-GNU: ELF Header:
# INVALID-GNU-NEXT: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
# INVALID-GNU-NEXT: Class: ELF64
# INVALID-GNU-NEXT: Data: 2's complement, little endian
# INVALID-GNU-NEXT: Version: 1 (current)
# INVALID-GNU-NEXT: OS/ABI: UNIX - System V
# INVALID-GNU-NEXT: ABI Version: 0
# INVALID-GNU-NEXT: Type: REL (Relocatable file)
# INVALID-GNU-NEXT: Machine: None
# INVALID-GNU-NEXT: Version: 0x1
# INVALID-GNU-NEXT: Entry point address: 0x0
# INVALID-GNU-NEXT: Start of program headers: 0 (bytes into file)
# INVALID-GNU-NEXT: Start of section headers: 4096 (bytes into file)
# INVALID-GNU-NEXT: Flags: 0x0
# INVALID-GNU-NEXT: Size of this header: 64 (bytes)
# INVALID-GNU-NEXT: Size of program headers: 0 (bytes)
# INVALID-GNU-NEXT: Number of program headers: 0
# INVALID-GNU-NEXT: Size of section headers: 64 (bytes)
# INVALID-GNU-NEXT: Number of section headers: [[SECHDRCOUNT]]
# INVALID-GNU-NEXT: Section header string table index: [[SECHDRSTRTABINDEX]]
# INVALID-GNU-NEXT: error: '[[FILE]]': unable to continue dumping, the file is corrupt: section header table goes past the end of the file: e_shoff = 0x1000
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_REL
## The section header table offset goes past the EOF.
EShOff: 0x1000
## The number of section headers is too large, the file is
## too little to contain so many sections.
EShNum: [[SHNUM=0x2000]]
## The index of the section name string table is too large.
## The section would be past the EOF.
EShStrNdx: [[SHSTRNDX=0x3000]]
SectionHeaderTable:
NoHeaders: true
## Check we don't dump anything except the file header when the section header table can't be read.
# RUN: not llvm-readobj -a %t.invalid1 2>&1 \
# RUN: | FileCheck %s -DFILE=%t.invalid1 -DSECHDRCOUNT=8192 -DSECHDRSTRTABINDEX=12288 --check-prefix=INVALID-LLVM
# RUN: not llvm-readelf -a %t.invalid1 2>&1 \
# RUN: | FileCheck %s -DFILE=%t.invalid1 -DSECHDRCOUNT=8192 -DSECHDRSTRTABINDEX=12288 --check-prefix=INVALID-GNU
## Check what we print when e_shnum == 0, e_shstrndx == SHN_XINDEX and the section header table can't be read.
# RUN: yaml2obj %s -DSHNUM=0 -DSHSTRNDX=0xffff --docnum=4 -o %t.invalid2
# RUN: not llvm-readobj --file-headers %t.invalid2 2>&1 \
# RUN: | FileCheck %s -DFILE=%t.invalid2 -DSECHDRCOUNT="<?>" -DSECHDRSTRTABINDEX="<?>" --check-prefix=INVALID-LLVM
# RUN: not llvm-readelf --file-headers %t.invalid2 2>&1 \
# RUN: | FileCheck %s -DFILE=%t.invalid2 -DSECHDRCOUNT="<?>" -DSECHDRSTRTABINDEX="<?>" --check-prefix=INVALID-GNU