mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 20:51:52 +01:00
[llvm-readobj/libObject] - Allow dumping objects that has a broken SHT_SYMTAB_SHNDX section.
Currently it is impossible to create an instance of ELFObjectFile when the SHT_SYMTAB_SHNDX can't be read. We error out when fail to parse the SHT_SYMTAB_SHNDX section in the factory method. This change delays reading of the SHT_SYMTAB_SHNDX section entries, with it llvm-readobj is now able to work with such inputs. Differential revision: https://reviews.llvm.org/D89379
This commit is contained in:
parent
cf35e6aad4
commit
d2ae6e2eba
@ -249,14 +249,14 @@ public:
|
|||||||
private:
|
private:
|
||||||
ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF,
|
ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF,
|
||||||
const Elf_Shdr *DotDynSymSec, const Elf_Shdr *DotSymtabSec,
|
const Elf_Shdr *DotDynSymSec, const Elf_Shdr *DotSymtabSec,
|
||||||
ArrayRef<Elf_Word> ShndxTable);
|
const Elf_Shdr *DotSymtabShndxSec);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ELFFile<ELFT> EF;
|
ELFFile<ELFT> EF;
|
||||||
|
|
||||||
const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section.
|
const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section.
|
||||||
const Elf_Shdr *DotSymtabSec = nullptr; // Symbol table section.
|
const Elf_Shdr *DotSymtabSec = nullptr; // Symbol table section.
|
||||||
ArrayRef<Elf_Word> ShndxTable;
|
const Elf_Shdr *DotSymtabShndxSec = nullptr; // SHT_SYMTAB_SHNDX section.
|
||||||
|
|
||||||
void moveSymbolNext(DataRefImpl &Symb) const override;
|
void moveSymbolNext(DataRefImpl &Symb) const override;
|
||||||
Expected<StringRef> getSymbolName(DataRefImpl Symb) const override;
|
Expected<StringRef> getSymbolName(DataRefImpl Symb) const override;
|
||||||
@ -538,6 +538,16 @@ ELFObjectFile<ELFT>::getSymbolAddress(DataRefImpl Symb) const {
|
|||||||
return SymTabOrErr.takeError();
|
return SymTabOrErr.takeError();
|
||||||
|
|
||||||
if (EF.getHeader().e_type == ELF::ET_REL) {
|
if (EF.getHeader().e_type == ELF::ET_REL) {
|
||||||
|
ArrayRef<Elf_Word> ShndxTable;
|
||||||
|
if (DotSymtabShndxSec) {
|
||||||
|
// TODO: Test this error.
|
||||||
|
if (Expected<ArrayRef<Elf_Word>> ShndxTableOrErr =
|
||||||
|
EF.getSHNDXTable(*DotSymtabShndxSec))
|
||||||
|
ShndxTable = *ShndxTableOrErr;
|
||||||
|
else
|
||||||
|
return ShndxTableOrErr.takeError();
|
||||||
|
}
|
||||||
|
|
||||||
Expected<const Elf_Shdr *> SectionOrErr =
|
Expected<const Elf_Shdr *> SectionOrErr =
|
||||||
EF.getSection(*ESym, *SymTabOrErr, ShndxTable);
|
EF.getSection(*ESym, *SymTabOrErr, ShndxTable);
|
||||||
if (!SectionOrErr)
|
if (!SectionOrErr)
|
||||||
@ -684,6 +694,16 @@ template <class ELFT>
|
|||||||
Expected<section_iterator>
|
Expected<section_iterator>
|
||||||
ELFObjectFile<ELFT>::getSymbolSection(const Elf_Sym *ESym,
|
ELFObjectFile<ELFT>::getSymbolSection(const Elf_Sym *ESym,
|
||||||
const Elf_Shdr *SymTab) const {
|
const Elf_Shdr *SymTab) const {
|
||||||
|
ArrayRef<Elf_Word> ShndxTable;
|
||||||
|
if (DotSymtabShndxSec) {
|
||||||
|
// TODO: Test this error.
|
||||||
|
Expected<ArrayRef<Elf_Word>> ShndxTableOrErr =
|
||||||
|
EF.getSHNDXTable(*DotSymtabShndxSec);
|
||||||
|
if (!ShndxTableOrErr)
|
||||||
|
return ShndxTableOrErr.takeError();
|
||||||
|
ShndxTable = *ShndxTableOrErr;
|
||||||
|
}
|
||||||
|
|
||||||
auto ESecOrErr = EF.getSection(*ESym, SymTab, ShndxTable);
|
auto ESecOrErr = EF.getSection(*ESym, SymTab, ShndxTable);
|
||||||
if (!ESecOrErr)
|
if (!ESecOrErr)
|
||||||
return ESecOrErr.takeError();
|
return ESecOrErr.takeError();
|
||||||
@ -984,7 +1004,7 @@ ELFObjectFile<ELFT>::create(MemoryBufferRef Object) {
|
|||||||
|
|
||||||
const Elf_Shdr *DotDynSymSec = nullptr;
|
const Elf_Shdr *DotDynSymSec = nullptr;
|
||||||
const Elf_Shdr *DotSymtabSec = nullptr;
|
const Elf_Shdr *DotSymtabSec = nullptr;
|
||||||
ArrayRef<Elf_Word> ShndxTable;
|
const Elf_Shdr *DotSymtabShndxSec = nullptr;
|
||||||
for (const Elf_Shdr &Sec : *SectionsOrErr) {
|
for (const Elf_Shdr &Sec : *SectionsOrErr) {
|
||||||
switch (Sec.sh_type) {
|
switch (Sec.sh_type) {
|
||||||
case ELF::SHT_DYNSYM: {
|
case ELF::SHT_DYNSYM: {
|
||||||
@ -998,33 +1018,31 @@ ELFObjectFile<ELFT>::create(MemoryBufferRef Object) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ELF::SHT_SYMTAB_SHNDX: {
|
case ELF::SHT_SYMTAB_SHNDX: {
|
||||||
auto TableOrErr = EF.getSHNDXTable(Sec);
|
if (!DotSymtabShndxSec)
|
||||||
if (!TableOrErr)
|
DotSymtabShndxSec = &Sec;
|
||||||
return TableOrErr.takeError();
|
|
||||||
ShndxTable = *TableOrErr;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ELFObjectFile<ELFT>(Object, EF, DotDynSymSec, DotSymtabSec,
|
return ELFObjectFile<ELFT>(Object, EF, DotDynSymSec, DotSymtabSec,
|
||||||
ShndxTable);
|
DotSymtabShndxSec);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
ELFObjectFile<ELFT>::ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF,
|
ELFObjectFile<ELFT>::ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF,
|
||||||
const Elf_Shdr *DotDynSymSec,
|
const Elf_Shdr *DotDynSymSec,
|
||||||
const Elf_Shdr *DotSymtabSec,
|
const Elf_Shdr *DotSymtabSec,
|
||||||
ArrayRef<Elf_Word> ShndxTable)
|
const Elf_Shdr *DotSymtabShndx)
|
||||||
: ELFObjectFileBase(
|
: ELFObjectFileBase(
|
||||||
getELFType(ELFT::TargetEndianness == support::little, ELFT::Is64Bits),
|
getELFType(ELFT::TargetEndianness == support::little, ELFT::Is64Bits),
|
||||||
Object),
|
Object),
|
||||||
EF(EF), DotDynSymSec(DotDynSymSec), DotSymtabSec(DotSymtabSec),
|
EF(EF), DotDynSymSec(DotDynSymSec), DotSymtabSec(DotSymtabSec),
|
||||||
ShndxTable(ShndxTable) {}
|
DotSymtabShndxSec(DotSymtabShndx) {}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
ELFObjectFile<ELFT>::ELFObjectFile(ELFObjectFile<ELFT> &&Other)
|
ELFObjectFile<ELFT>::ELFObjectFile(ELFObjectFile<ELFT> &&Other)
|
||||||
: ELFObjectFile(Other.Data, Other.EF, Other.DotDynSymSec,
|
: ELFObjectFile(Other.Data, Other.EF, Other.DotDynSymSec,
|
||||||
Other.DotSymtabSec, Other.ShndxTable) {}
|
Other.DotSymtabSec, Other.DotSymtabShndxSec) {}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
basic_symbol_iterator ELFObjectFile<ELFT>::symbol_begin() const {
|
basic_symbol_iterator ELFObjectFile<ELFT>::symbol_begin() const {
|
||||||
|
@ -211,9 +211,9 @@ Sections:
|
|||||||
## sizeof(.symtab_shndx) = (sizeof(.symtab) / entsize(.symtab)) * entsize(.symtab_shndx)
|
## sizeof(.symtab_shndx) = (sizeof(.symtab) / entsize(.symtab)) * entsize(.symtab_shndx)
|
||||||
|
|
||||||
# RUN: yaml2obj %s --docnum=11 -o %t11
|
# RUN: yaml2obj %s --docnum=11 -o %t11
|
||||||
# RUN: not llvm-readobj --symbols %t11 2>&1 | FileCheck --check-prefix=INVALID-XINDEX-SIZE %s
|
# RUN: llvm-readobj --symbols %t11 2>&1 | FileCheck --check-prefix=INVALID-XINDEX-SIZE %s
|
||||||
|
|
||||||
# INVALID-XINDEX-SIZE: error: {{.*}}: SHT_SYMTAB_SHNDX has 2 entries, but the symbol table associated has 1
|
# INVALID-XINDEX-SIZE: warning: {{.*}}: SHT_SYMTAB_SHNDX has 2 entries, but the symbol table associated has 1
|
||||||
|
|
||||||
--- !ELF
|
--- !ELF
|
||||||
FileHeader:
|
FileHeader:
|
||||||
|
@ -254,3 +254,60 @@ Symbols:
|
|||||||
Index: SHN_XINDEX
|
Index: SHN_XINDEX
|
||||||
- Name: no_shndx2
|
- Name: no_shndx2
|
||||||
Index: SHN_XINDEX
|
Index: SHN_XINDEX
|
||||||
|
|
||||||
|
## Check we can dump symbols even when the number of entries in the
|
||||||
|
## SHT_SYMTAB_SHNDX section doesn't match the number of symbols in the symbol table.
|
||||||
|
|
||||||
|
# RUN: yaml2obj --docnum=4 %s -o %t4
|
||||||
|
# RUN: llvm-readelf --symbols %t4 2>&1 | FileCheck %s -DFILE=%t4 --check-prefix=SHNDX-ERR-GNU
|
||||||
|
# RUN: llvm-readobj --symbols %t4 2>&1 | FileCheck %s -DFILE=%t4 --check-prefix=SHNDX-ERR-LLVM
|
||||||
|
|
||||||
|
# SHNDX-ERR-GNU: warning: '[[FILE]]': SHT_SYMTAB_SHNDX has 3 entries, but the symbol table associated has 2
|
||||||
|
# SHNDX-ERR-GNU-EMPTY:
|
||||||
|
# SHNDX-ERR-GNU-NEXT: Symbol table '.symtab' contains 2 entries:
|
||||||
|
# SHNDX-ERR-GNU-NEXT: Num: Value Size Type Bind Vis Ndx Name
|
||||||
|
# SHNDX-ERR-GNU-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
|
||||||
|
# SHNDX-ERR-GNU-NEXT: warning: '[[FILE]]': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0
|
||||||
|
# SHNDX-ERR-GNU-NEXT: 1: 0000000000000000 0 NOTYPE LOCAL DEFAULT RSV[0xffff]
|
||||||
|
# SHNDX-ERR-GNU-EMPTY:
|
||||||
|
# SHNDX-ERR-GNU-NOT:{{.}}
|
||||||
|
|
||||||
|
# SHNDX-ERR-LLVM: warning: '[[FILE]]': SHT_SYMTAB_SHNDX has 3 entries, but the symbol table associated has 2
|
||||||
|
# SHNDX-ERR-LLVM: Format: elf64-unknown
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Arch: unknown
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: AddressSize: 64bit
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: LoadName: <Not found>
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Symbols [
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Symbol {
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Name: (0)
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Value: 0x0
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Size: 0
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Binding: Local (0x0)
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Type: None (0x0)
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Other: 0
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Section: Undefined (0x0)
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: }
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Symbol {
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Name: (0)
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Value: 0x0
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Size: 0
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Binding: Local (0x0)
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Type: None (0x0)
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Other: 0
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: warning: '[[FILE]]': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: Section: Reserved (0xFFFF)
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: }
|
||||||
|
# SHNDX-ERR-LLVM-NEXT: ]
|
||||||
|
|
||||||
|
--- !ELF
|
||||||
|
FileHeader:
|
||||||
|
Class: ELFCLASS64
|
||||||
|
Data: ELFDATA2LSB
|
||||||
|
Type: ET_REL
|
||||||
|
Sections:
|
||||||
|
- Name: .symtab_shndx
|
||||||
|
Type: SHT_SYMTAB_SHNDX
|
||||||
|
Entries: [ 0, 1, 2 ]
|
||||||
|
Link: .symtab
|
||||||
|
Symbols:
|
||||||
|
- Index: SHN_XINDEX
|
||||||
|
@ -143,7 +143,7 @@ Symbols: []
|
|||||||
# RUN: yaml2obj --docnum=6 %s -o %t6
|
# RUN: yaml2obj --docnum=6 %s -o %t6
|
||||||
# RUN: not obj2yaml %t6 2>&1 | FileCheck %s -DFILE=%t6 --check-prefix=CASE6
|
# RUN: not obj2yaml %t6 2>&1 | FileCheck %s -DFILE=%t6 --check-prefix=CASE6
|
||||||
|
|
||||||
# CASE6: Error reading file: [[FILE]]: SHT_SYMTAB_SHNDX section is linked with SHT_PROGBITS section (expected SHT_SYMTAB/SHT_DYNSYM)
|
# CASE6: Error reading file: [[FILE]]: only SHT_SYMTAB_SHNDX associated with SHT_SYMTAB are supported
|
||||||
|
|
||||||
--- !ELF
|
--- !ELF
|
||||||
FileHeader:
|
FileHeader:
|
||||||
|
@ -107,9 +107,9 @@ Symbols:
|
|||||||
## Check we can set a custom sh_entsize for SHT_SYMTAB_SHNDX section.
|
## Check we can set a custom sh_entsize for SHT_SYMTAB_SHNDX section.
|
||||||
|
|
||||||
# RUN: yaml2obj --docnum=5 %s -o %t5
|
# RUN: yaml2obj --docnum=5 %s -o %t5
|
||||||
# RUN: not llvm-readelf -S 2>&1 %t5 | FileCheck %s -DFILE=%t5 --check-prefix=CASE5
|
# RUN: llvm-readelf -S 2>&1 %t5 | FileCheck %s -DFILE=%t5 --check-prefix=CASE5
|
||||||
|
|
||||||
# CASE5: error: '[[FILE]]': section [index 1] has an invalid sh_entsize: 2
|
# CASE5: warning: '[[FILE]]': section [index 1] has an invalid sh_entsize: 2
|
||||||
|
|
||||||
--- !ELF
|
--- !ELF
|
||||||
FileHeader:
|
FileHeader:
|
||||||
|
@ -2026,7 +2026,10 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> &O,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ELF::SHT_SYMTAB_SHNDX:
|
case ELF::SHT_SYMTAB_SHNDX:
|
||||||
ShndxTable = unwrapOrError(ObjF.getFileName(), Obj.getSHNDXTable(Sec));
|
if (Expected<ArrayRef<Elf_Word>> ShndxTableOrErr = Obj.getSHNDXTable(Sec))
|
||||||
|
ShndxTable = *ShndxTableOrErr;
|
||||||
|
else
|
||||||
|
this->reportUniqueWarning(ShndxTableOrErr.takeError());
|
||||||
break;
|
break;
|
||||||
case ELF::SHT_GNU_versym:
|
case ELF::SHT_GNU_versym:
|
||||||
if (!SymbolVersionSection)
|
if (!SymbolVersionSection)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
set(LLVM_LINK_COMPONENTS
|
set(LLVM_LINK_COMPONENTS
|
||||||
BinaryFormat
|
BinaryFormat
|
||||||
Object
|
Object
|
||||||
|
ObjectYAML
|
||||||
)
|
)
|
||||||
|
|
||||||
add_llvm_unittest(ObjectTests
|
add_llvm_unittest(ObjectTests
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "llvm/Object/ELFObjectFile.h"
|
#include "llvm/Object/ELFObjectFile.h"
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
|
#include "llvm/ObjectYAML/yaml2obj.h"
|
||||||
|
#include "llvm/Support/YAMLTraits.h"
|
||||||
#include "llvm/Testing/Support/Error.h"
|
#include "llvm/Testing/Support/Error.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
@ -291,9 +293,38 @@ TEST(ELFObjectFileTest, MachineTestForCSKY) {
|
|||||||
checkFormatAndArch(D, Formats[I++], Triple::csky);
|
checkFormatAndArch(D, Formats[I++], Triple::csky);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ELF relative relocation type test.
|
// ELF relative relocation type test.
|
||||||
TEST(ELFObjectFileTest, RelativeRelocationTypeTest) {
|
TEST(ELFObjectFileTest, RelativeRelocationTypeTest) {
|
||||||
EXPECT_EQ(ELF::R_CKCORE_RELATIVE, getELFRelativeRelocationType(ELF::EM_CSKY));
|
EXPECT_EQ(ELF::R_CKCORE_RELATIVE, getELFRelativeRelocationType(ELF::EM_CSKY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class ELFT>
|
||||||
|
static Expected<ELFObjectFile<ELFT>> toBinary(SmallVectorImpl<char> &Storage,
|
||||||
|
StringRef Yaml) {
|
||||||
|
raw_svector_ostream OS(Storage);
|
||||||
|
yaml::Input YIn(Yaml);
|
||||||
|
if (!yaml::convertYAML(YIn, OS, [](const Twine &Msg) {}))
|
||||||
|
return createStringError(std::errc::invalid_argument,
|
||||||
|
"unable to convert YAML");
|
||||||
|
return ELFObjectFile<ELFT>::create(MemoryBufferRef(OS.str(), "dummyELF"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check we are able to create an ELFObjectFile even when the content of the
|
||||||
|
// SHT_SYMTAB_SHNDX section can't be read properly.
|
||||||
|
TEST(ELFObjectFileTest, InvalidSymtabShndxTest) {
|
||||||
|
SmallString<0> Storage;
|
||||||
|
Expected<ELFObjectFile<ELF64LE>> ExpectedFile = toBinary<ELF64LE>(Storage, R"(
|
||||||
|
--- !ELF
|
||||||
|
FileHeader:
|
||||||
|
Class: ELFCLASS64
|
||||||
|
Data: ELFDATA2LSB
|
||||||
|
Type: ET_REL
|
||||||
|
Sections:
|
||||||
|
- Name: .symtab_shndx
|
||||||
|
Type: SHT_SYMTAB_SHNDX
|
||||||
|
Entries: [ 0 ]
|
||||||
|
ShSize: 0xFFFFFFFF
|
||||||
|
)");
|
||||||
|
|
||||||
|
ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user