1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

[llvm-readelf/obj] - Add support of multiple SHT_SYMTAB_SHNDX sections.

Currently we don't support multiple SHT_SYMTAB_SHNDX sections
and the DT_SYMTAB_SHNDX tag currently.

This patch implements it and fixes the
https://bugs.llvm.org/show_bug.cgi?id=43991.

I had to introduce the `struct DataRegion` to ELF.h,
it is used to represent a region that might have no known size.
It is needed, because we don't know the size of the extended
section indices table when it is located via DT_SYMTAB_SHNDX.
In this case we still want to validate that we don't read
past the end of the file.

Differential revision: https://reviews.llvm.org/D92923
This commit is contained in:
Georgii Rymar 2020-12-08 12:39:04 +03:00
parent 3b162ef2a9
commit 8e4afeec9b
13 changed files with 593 additions and 96 deletions

View File

@ -57,6 +57,36 @@ enum PPCInstrMasks : uint64_t {
template <class ELFT> class ELFFile;
template <class T> struct DataRegion {
// This constructor is used when we know the start and the size of a data
// region. We assume that Arr does not go past the end of the file.
DataRegion(ArrayRef<T> Arr) : First(Arr.data()), Size(Arr.size()) {}
// Sometimes we only know the start of a data region. We still don't want to
// read past the end of the file, so we provide the end of a buffer.
DataRegion(const T *Data, const uint8_t *BufferEnd)
: First(Data), BufEnd(BufferEnd) {}
Expected<T> operator[](uint64_t N) {
assert(Size || BufEnd);
if (Size) {
if (N >= *Size)
return createError(
"the index is greater than or equal to the number of entries (" +
Twine(*Size) + ")");
} else {
const uint8_t *EntryStart = (const uint8_t *)First + N * sizeof(T);
if (EntryStart + sizeof(T) > BufEnd)
return createError("can't read past the end of the file");
}
return *(First + N);
}
const T *First;
Optional<uint64_t> Size = None;
const uint8_t *BufEnd = nullptr;
};
template <class ELFT>
std::string getSecIndexForError(const ELFFile<ELFT> &Obj,
const typename ELFT::Shdr &Sec) {
@ -99,6 +129,7 @@ public:
using WarningHandler = llvm::function_ref<Error(const Twine &Msg)>;
const uint8_t *base() const { return Buf.bytes_begin(); }
const uint8_t *end() const { return base() + getBufSize(); }
size_t getBufSize() const { return Buf.size(); }
@ -274,13 +305,13 @@ public:
Elf_Shdr_Range Sections,
WarningHandler WarnHandler = &defaultWarningHandler) const;
Expected<uint32_t> getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms,
ArrayRef<Elf_Word> ShndxTable) const;
DataRegion<Elf_Word> ShndxTable) const;
Expected<const Elf_Shdr *> getSection(const Elf_Sym &Sym,
const Elf_Shdr *SymTab,
ArrayRef<Elf_Word> ShndxTable) const;
DataRegion<Elf_Word> ShndxTable) const;
Expected<const Elf_Shdr *> getSection(const Elf_Sym &Sym,
Elf_Sym_Range Symtab,
ArrayRef<Elf_Word> ShndxTable) const;
DataRegion<Elf_Word> ShndxTable) const;
Expected<const Elf_Shdr *> getSection(uint32_t Index) const;
Expected<const Elf_Sym *> getSymbol(const Elf_Shdr *Sec,
@ -313,22 +344,25 @@ getSection(typename ELFT::ShdrRange Sections, uint32_t Index) {
template <class ELFT>
inline Expected<uint32_t>
getExtendedSymbolTableIndex(const typename ELFT::Sym &Sym, unsigned SymIndex,
ArrayRef<typename ELFT::Word> ShndxTable) {
DataRegion<typename ELFT::Word> ShndxTable) {
assert(Sym.st_shndx == ELF::SHN_XINDEX);
if (SymIndex >= ShndxTable.size())
if (!ShndxTable.First)
return createError(
"extended symbol index (" + Twine(SymIndex) +
") is past the end of the SHT_SYMTAB_SHNDX section of size " +
Twine(ShndxTable.size()));
"found an extended symbol index (" + Twine(SymIndex) +
"), but unable to locate the extended symbol index table");
// The size of the table was checked in getSHNDXTable.
return ShndxTable[SymIndex];
Expected<typename ELFT::Word> TableOrErr = ShndxTable[SymIndex];
if (!TableOrErr)
return createError("unable to read an extended symbol table at index " +
Twine(SymIndex) + ": " +
toString(TableOrErr.takeError()));
return *TableOrErr;
}
template <class ELFT>
Expected<uint32_t>
ELFFile<ELFT>::getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms,
ArrayRef<Elf_Word> ShndxTable) const {
DataRegion<Elf_Word> ShndxTable) const {
uint32_t Index = Sym.st_shndx;
if (Index == ELF::SHN_XINDEX) {
Expected<uint32_t> ErrorOrIndex =
@ -345,7 +379,7 @@ ELFFile<ELFT>::getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms,
template <class ELFT>
Expected<const typename ELFT::Shdr *>
ELFFile<ELFT>::getSection(const Elf_Sym &Sym, const Elf_Shdr *SymTab,
ArrayRef<Elf_Word> ShndxTable) const {
DataRegion<Elf_Word> ShndxTable) const {
auto SymsOrErr = symbols(SymTab);
if (!SymsOrErr)
return SymsOrErr.takeError();
@ -355,7 +389,7 @@ ELFFile<ELFT>::getSection(const Elf_Sym &Sym, const Elf_Shdr *SymTab,
template <class ELFT>
Expected<const typename ELFT::Shdr *>
ELFFile<ELFT>::getSection(const Elf_Sym &Sym, Elf_Sym_Range Symbols,
ArrayRef<Elf_Word> ShndxTable) const {
DataRegion<Elf_Word> ShndxTable) const {
auto IndexOrErr = getSectionIndex(Sym, Symbols, ShndxTable);
if (!IndexOrErr)
return IndexOrErr.takeError();

View File

@ -244,7 +244,7 @@ Symbols: []
# RUN: llvm-readobj --symbols %p/Inputs/invalid-ext-symtab-index.elf-x86-64 2>&1 | \
# RUN: FileCheck -DFILE=%p/Inputs/invalid-ext-symtab-index.elf-x86-64 --check-prefix=INVALID-EXT-SYMTAB-INDEX %s
# INVALID-EXT-SYMTAB-INDEX: warning: '[[FILE]]': extended symbol index (0) is past the end of the SHT_SYMTAB_SHNDX section of size 0
# INVALID-EXT-SYMTAB-INDEX: warning: '[[FILE]]': found an extended symbol index (0), but unable to locate the extended symbol index table
# INVALID-EXT-SYMTAB-INDEX: Section: Reserved (0xFFFF)
## Check that llvm-readobj reports an error if a relocation section

View File

@ -364,14 +364,14 @@ DynamicSymbols:
# VERSIONED-SEC-SYM-XINDEX-LLVM: Name: (0)
# VERSIONED-SEC-SYM-XINDEX-LLVM: Name: foo (12)
# VERSIONED-SEC-SYM-XINDEX-LLVM: warning: '[[FILE]]': extended symbol index (2) is past the end of the SHT_SYMTAB_SHNDX section of size 0
# VERSIONED-SEC-SYM-XINDEX-LLVM: warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table
# VERSIONED-SEC-SYM-XINDEX-LLVM-NEXT: Symbol {
# VERSIONED-SEC-SYM-XINDEX-LLVM-NEXT: Name: <?> (0)
# VERSIONED-SEC-SYM-XINDEX-LLVM: Name: <?> (0)
# VERSIONED-SEC-SYM-XINDEX-GNU: Symbol table '.dynsym' contains 4 entries:
# VERSIONED-SEC-SYM-XINDEX-GNU: Num: {{.*}} Ndx Name
# VERSIONED-SEC-SYM-XINDEX-GNU: warning: '[[FILE]]': extended symbol index (2) is past the end of the SHT_SYMTAB_SHNDX section of size 0
# VERSIONED-SEC-SYM-XINDEX-GNU: warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table
# VERSIONED-SEC-SYM-XINDEX-GNU-NEXT: 2: {{.*}} RSV[0xffff] <?>
## Case 8: Check what we print when:

View File

@ -487,6 +487,7 @@ Sections:
# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': DT_SYMENT value of 0x987 is not the size of a symbol (0x18)
# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_REL: invalid e_phentsize: 1
# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_JMPREL: invalid e_phentsize: 1
# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_SYMTAB_SHNDX: invalid e_phentsize: 1
# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_RELR: invalid e_phentsize: 1
# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_ANDROID_RELR: invalid e_phentsize: 1
# PHENTSIZE-WARN-NEXT: warning: '[[FILE]]': unable to parse DT_GNU_HASH: invalid e_phentsize: 1

View File

@ -558,7 +558,7 @@ DynamicSymbols:
# SEC-SYMS-LLVM-NEXT: }
# SEC-SYMS-LLVM-NEXT: Entry {
# SEC-SYMS-LLVM: Type: Section (0x3)
# SEC-SYMS-LLVM-NEXT: warning: '[[FILE]]': extended symbol index (4) is past the end of the SHT_SYMTAB_SHNDX section of size 0
# SEC-SYMS-LLVM-NEXT: warning: '[[FILE]]': found an extended symbol index (4), but unable to locate the extended symbol index table
# SEC-SYMS-LLVM-NEXT: Section: Reserved (0xFFFF)
# SEC-SYMS-LLVM-NEXT: Name: <?> (0)
# SEC-SYMS-LLVM-NEXT: }
@ -571,7 +571,7 @@ DynamicSymbols:
# SEC-SYMS-GNU-NEXT: {{.*}} 1 .got
# SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': unable to get section index for symbol with st_shndx = 0xfff2 (SHN_COMMON)
# SEC-SYMS-GNU-NEXT: {{.*}} COM <?>
# SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': extended symbol index (4) is past the end of the SHT_SYMTAB_SHNDX section of size 0
# SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (4), but unable to locate the extended symbol index table
# SEC-SYMS-GNU-NEXT: {{.*}} RSV[0xffff] <?>
--- !ELF

View File

@ -189,7 +189,7 @@ DynamicSymbols: []
# SEC-SYMS-LLVM-NEXT: }
# SEC-SYMS-LLVM-NEXT: Entry {
# SEC-SYMS-LLVM: Type: Section (0x3)
# SEC-SYMS-LLVM-NEXT: warning: '[[FILE]]': extended symbol index (4) is past the end of the SHT_SYMTAB_SHNDX section of size 0
# SEC-SYMS-LLVM-NEXT: warning: '[[FILE]]': found an extended symbol index (4), but unable to locate the extended symbol index table
# SEC-SYMS-LLVM-NEXT: Section: Reserved (0xFFFF)
# SEC-SYMS-LLVM-NEXT: Name: <?> (0)
# SEC-SYMS-LLVM-NEXT: }
@ -204,7 +204,7 @@ DynamicSymbols: []
# SEC-SYMS-GNU-NEXT: 0000000000002018 {{.*}} 2 .got.plt
# SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': unable to get section index for symbol with st_shndx = 0xfff2 (SHN_COMMON)
# SEC-SYMS-GNU-NEXT: 0000000000002020 {{.*}} COM <?>
# SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': extended symbol index (4) is past the end of the SHT_SYMTAB_SHNDX section of size 0
# SEC-SYMS-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (4), but unable to locate the extended symbol index table
# SEC-SYMS-GNU-NEXT: 0000000000002028 {{.*}} RSV[0xffff] <?>
--- !ELF

View File

@ -150,7 +150,7 @@ Symbols:
# GNU2-NEXT: 0: {{.*}} NOTYPE {{.*}} UND {{$}}
# GNU2-NEXT: 1: {{.*}} SECTION {{.*}} RSV[0xffff] <?>
# WARN2: warning: '{{.*}}.tmp2': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0
# WARN2: warning: '{{.*}}.tmp2': found an extended symbol index (1), but unable to locate the extended symbol index table
--- !ELF
FileHeader:

View File

@ -241,8 +241,8 @@ Symbols:
# GNU3-NEXT: 1: {{.*}} RSV[0xffff] no_shndx
# GNU3-NEXT: 2: {{.*}} RSV[0xffff] no_shndx2
# NO-SYMTAB-SHNDX: warning: '{{.*}}tmp3': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0
# NO-SYMTAB-SHNDX: warning: '{{.*}}tmp3': extended symbol index (2) is past the end of the SHT_SYMTAB_SHNDX section of size 0
# NO-SYMTAB-SHNDX: warning: '{{.*}}tmp3': found an extended symbol index (1), but unable to locate the extended symbol index table
# NO-SYMTAB-SHNDX: warning: '{{.*}}tmp3': found an extended symbol index (2), but unable to locate the extended symbol index table
--- !ELF
FileHeader:
@ -267,7 +267,7 @@ Symbols:
# 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: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table
# SHNDX-ERR-GNU-NEXT: 1: 0000000000000000 0 NOTYPE LOCAL DEFAULT RSV[0xffff]
# SHNDX-ERR-GNU-EMPTY:
# SHNDX-ERR-GNU-NOT:{{.}}
@ -294,7 +294,7 @@ Symbols:
# 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: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table
# SHNDX-ERR-LLVM-NEXT: Section: Reserved (0xFFFF)
# SHNDX-ERR-LLVM-NEXT: }
# SHNDX-ERR-LLVM-NEXT: ]

View File

@ -0,0 +1,331 @@
## In this file we have tests for the SHT_SYMTAB_SHNDX section
## and the DT_SYMTAB_SHNDX dynamic tag.
## Check that different SHT_SYMTAB_SHNDX sections can be used with different symbol tables.
## In this test we check that we print different section indexes for regular and dynamic
## symbol tables that are linked to different SHT_SYMTAB_SHNDX sections.
# RUN: yaml2obj --docnum=1 %s -o %t1
# RUN: llvm-readelf --symbols --dyn-syms %t1 2>&1 | FileCheck %s --check-prefix=GNU
# RUN: llvm-readobj --symbols --dyn-syms %t1 2>&1 | FileCheck %s --check-prefix=LLVM
# GNU: Symbol table '.dynsym' contains 3 entries:
# GNU-NEXT: Num: Value Size Type Bind Vis Ndx Name
# GNU-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
# GNU-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT 3 dynsym1
# GNU-NEXT: 2: 00000000 0 NOTYPE LOCAL DEFAULT 2 dynsym2
# GNU: Symbol table '.symtab' contains 3 entries:
# GNU-NEXT: Num: Value Size Type Bind Vis Ndx Name
# GNU-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
# GNU-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT 2 sym1
# GNU-NEXT: 2: 00000000 0 NOTYPE LOCAL DEFAULT 1 sym2
# LLVM: Symbols [
# LLVM-NEXT: Symbol {
# LLVM-NEXT: Name: (0)
# LLVM: Section: Undefined (0x0)
# LLVM-NEXT: }
# LLVM-NEXT: Symbol {
# LLVM-NEXT: Name: sym1 (6)
# LLVM: Section: .section2 (0x2)
# LLVM-NEXT: }
# LLVM-NEXT: Symbol {
# LLVM-NEXT: Name: sym2 (1)
# LLVM: Section: .section1 (0x1)
# LLVM-NEXT: }
# LLVM-NEXT: ]
# LLVM: DynamicSymbols [
# LLVM-NEXT: Symbol {
# LLVM-NEXT: Name: (0)
# LLVM: Section: Undefined (0x0)
# LLVM-NEXT: }
# LLVM-NEXT: Symbol {
# LLVM-NEXT: Name: dynsym1 (9)
# LLVM: Section: .section3 (0x3)
# LLVM-NEXT: }
# LLVM-NEXT: Symbol {
# LLVM-NEXT: Name: dynsym2 (1)
# LLVM: Section: .section2 (0x2)
# LLVM-NEXT: }
# LLVM-NEXT: ]
--- !ELF
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2LSB
Type: ET_REL
Sections:
- Name: .section1
Type: SHT_PROGBITS
- Name: .section2
Type: SHT_PROGBITS
- Name: .section3
Type: SHT_PROGBITS
- Name: .dynamic
Type: SHT_DYNAMIC
Flags: [ SHF_ALLOC ]
Address: 0x1000
Offset: 0x1000
Entries:
- Tag: [[TAGNAME=DT_SYMTAB_SHNDX]]
Value: [[SYMTABSHNDX=0x2100]] ## Address of .bar section.
- Tag: DT_NULL
Value: 0
## By naming the SHT_SYMTAB_SHNDX sections to .foo and .bar we verify that we
## don't use their names to locate them.
- Name: .foo
Type: SHT_SYMTAB_SHNDX
Flags: [ SHF_ALLOC ]
Link: [[SHNDXLINK=.symtab]]
Entries: [ 0, 2, 1 ]
Offset: 0x2000
Address: 0x2000
- Name: .bar
Type: SHT_SYMTAB_SHNDX
Flags: [ SHF_ALLOC ]
Link: .dynsym
Entries: [ 0, 3, 2 ]
Offset: 0x2100
Address: 0x2100
Symbols:
- Name: sym1
Index: SHN_XINDEX
- Name: sym2
Index: SHN_XINDEX
DynamicSymbols:
- Name: dynsym1
Index: SHN_XINDEX
- Name: dynsym2
Index: SHN_XINDEX
ProgramHeaders:
- Type: PT_LOAD
VAddr: 0x1000
FirstSec: .dynamic
LastSec: .bar
- Type: PT_DYNAMIC
VAddr: 0x1000
FirstSec: .dynamic
LastSec: .dynamic
## Check that we locate the SHT_SYMTAB_SHNDX section using the DT_SYMTAB_SHNDX
## dynamic tag when dumping dynamic symbols. In this case we make the value of
## DT_SYMTAB_SHNDX point to the SHT_SYMTAB_SHNDX section that is
## linked with the static symbol table and check that we use it.
# RUN: yaml2obj --docnum=1 -DSYMTABSHNDX=0x2000 %s -o %t2
# RUN: llvm-readelf --dyn-syms %t2 2>&1 | FileCheck %s --check-prefix=DYNTAG-GNU
# RUN: llvm-readobj --dyn-syms %t2 2>&1 | FileCheck %s --check-prefix=DYNTAG-LLVM
# DYNTAG-GNU: Symbol table '.dynsym' contains 3 entries:
# DYNTAG-GNU-NEXT: Num: Value Size Type Bind Vis Ndx Name
# DYNTAG-GNU-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
# DYNTAG-GNU-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT 2 dynsym1
# DYNTAG-GNU-NEXT: 2: 00000000 0 NOTYPE LOCAL DEFAULT 1 dynsym2
# DYNTAG-LLVM: Name: dynsym1 (9)
# DYNTAG-LLVM: Section: .section2 (0x2)
# DYNTAG-LLVM-NEXT: }
# DYNTAG-LLVM-NEXT: Symbol {
# DYNTAG-LLVM-NEXT: Name: dynsym2 (1)
# DYNTAG-LLVM: Section: .section1 (0x1)
# DYNTAG-LLVM-NEXT: }
# DYNTAG-LLVM-NEXT: ]
## Check that we report a warning when we dump a dynamic symbol table that
## contains symbols with extended indices, but we don't have a DT_SYMTAB_SHNDX tag to locate
## the corresponding extended indexes table.
# RUN: yaml2obj --docnum=1 -DTAGNAME=0x0 -DSYMTABSHNDX=0x0 %s -o %t3
# RUN: llvm-readelf --symbols --dyn-syms %t3 2>&1 | FileCheck %s -DFILE=%t3 --check-prefix=NOTAG-GNU
# RUN: llvm-readobj --symbols --dyn-syms %t3 2>&1 | FileCheck %s -DFILE=%t3 --check-prefix=NOTAG-LLVM
# NOTAG-GNU: Symbol table '.dynsym' contains 3 entries:
# NOTAG-GNU-NEXT: Num: Value Size Type Bind Vis Ndx Name
# NOTAG-GNU-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
# NOTAG-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table
# NOTAG-GNU-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT RSV[0xffff] dynsym1
# NOTAG-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table
# NOTAG-GNU-NEXT: 2: 00000000 0 NOTYPE LOCAL DEFAULT RSV[0xffff] dynsym2
# NOTAG-LLVM: Symbol {
# NOTAG-LLVM: Name: dynsym1 (9)
# NOTAG-LLVM-NEXT: Value: 0x0
# NOTAG-LLVM-NEXT: Size: 0
# NOTAG-LLVM-NEXT: Binding: Local (0x0)
# NOTAG-LLVM-NEXT: Type: None (0x0)
# NOTAG-LLVM-NEXT: Other: 0
# NOTAG-LLVM-NEXT: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table
# NOTAG-LLVM-NEXT: Section: Reserved (0xFFFF)
# NOTAG-LLVM-NEXT: }
# NOTAG-LLVM-NEXT: Symbol {
# NOTAG-LLVM-NEXT: Name: dynsym2 (1)
# NOTAG-LLVM-NEXT: Value: 0x0
# NOTAG-LLVM-NEXT: Size: 0
# NOTAG-LLVM-NEXT: Binding: Local (0x0)
# NOTAG-LLVM-NEXT: Type: None (0x0)
# NOTAG-LLVM-NEXT: Other: 0
# NOTAG-LLVM-NEXT: warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table
# NOTAG-LLVM-NEXT: Section: Reserved (0xFFFF)
# NOTAG-LLVM-NEXT: }
## In this case we have a SHT_SYMTAB_SHNDX section with a sh_link field that has a
## value that is larger than the number of sections. Check we report a warning.
# RUN: yaml2obj --docnum=1 -DSHNDXLINK=0xFF %s -o %t4
# RUN: llvm-readelf --symbols --dyn-syms %t4 2>&1 | \
# RUN: FileCheck %s -DFILE=%t4 --check-prefixes=BROKENLINK,BROKENLINK-GNU --implicit-check-not=warning:
# RUN: llvm-readobj --symbols --dyn-syms %t4 2>&1 | \
# RUN: FileCheck %s -DFILE=%t4 --check-prefixes=BROKENLINK,BROKENLINK-LLVM --implicit-check-not=warning:
# BROKENLINK: warning: '[[FILE]]': unable to get the associated symbol table for SHT_SYMTAB_SHNDX section with index 5: sh_link (255) is greater than or equal to the total number of sections (12)
# BROKENLINK-GNU: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table
# BROKENLINK-GNU-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT RSV[0xffff] sym1
# BROKENLINK-GNU-NEXT: warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table
# BROKENLINK-GNU-NEXT: 2: 00000000 0 NOTYPE LOCAL DEFAULT RSV[0xffff] sym2
# BROKENLINK-LLVM: Symbol {
# BROKENLINK-LLVM: Name: sym1 (6)
# BROKENLINK-LLVM: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table
# BROKENLINK-LLVM-NEXT: Section: Reserved (0xFFFF)
# BROKENLINK-LLVM-NEXT: }
# BROKENLINK-LLVM-NEXT: Symbol {
# BROKENLINK-LLVM-NEXT: Name: sym2 (1)
# BROKENLINK-LLVM: warning: '[[FILE]]': found an extended symbol index (2), but unable to locate the extended symbol index table
# BROKENLINK-LLVM-NEXT: Section: Reserved (0xFFFF)
# BROKENLINK-LLVM-NEXT: }
## Check we report a warning when multiple SHT_SYMTAB_SHNDX sections are linked to a symbol table.
## In this case, 2 sections are linked to the dynamic symbol table. Check it doesn't affect
## anything, because the SHT_SYMTAB_SHNDX section specified by the DT_SYMTAB_SHNDX tag is still used.
# RUN: yaml2obj --docnum=1 -DSHNDXLINK=.dynsym %s -o %t.multiple
# RUN: llvm-readelf --symbols --dyn-syms %t.multiple 2>&1 | \
# RUN: FileCheck %s -DFILE=%t.multiple --check-prefix=MULTIPLE-GNU
# RUN: llvm-readobj --symbols --dyn-syms %t.multiple 2>&1 | \
# RUN: FileCheck %s -DFILE=%t.multiple --check-prefix=MULTIPLE-LLVM
# MULTIPLE-GNU: warning: '[[FILE]]': multiple SHT_SYMTAB_SHNDX sections are linked to SHT_SYMTAB_SHNDX section with index 6
# MULTIPLE-GNU: Symbol table '.dynsym' contains 3 entries:
# MULTIPLE-GNU-NEXT: Num: Value Size Type Bind Vis Ndx Name
# MULTIPLE-GNU-NEXT: 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
# MULTIPLE-GNU-NEXT: 1: 00000000 0 NOTYPE LOCAL DEFAULT 3 dynsym1
# MULTIPLE-GNU-NEXT: 2: 00000000 0 NOTYPE LOCAL DEFAULT 2 dynsym2
# MULTIPLE-LLVM: Symbol {
# MULTIPLE-LLVM: Name: dynsym1 (9)
# MULTIPLE-LLVM-NEXT: Value: 0x0
# MULTIPLE-LLVM-NEXT: Size: 0
# MULTIPLE-LLVM-NEXT: Binding: Local (0x0)
# MULTIPLE-LLVM-NEXT: Type: None (0x0)
# MULTIPLE-LLVM-NEXT: Other: 0
# MULTIPLE-LLVM-NEXT: Section: .section3 (0x3)
# MULTIPLE-LLVM-NEXT: }
# MULTIPLE-LLVM-NEXT: Symbol {
# MULTIPLE-LLVM-NEXT: Name: dynsym2 (1)
# MULTIPLE-LLVM-NEXT: Value: 0x0
# MULTIPLE-LLVM-NEXT: Size: 0
# MULTIPLE-LLVM-NEXT: Binding: Local (0x0)
# MULTIPLE-LLVM-NEXT: Type: None (0x0)
# MULTIPLE-LLVM-NEXT: Other: 0
# MULTIPLE-LLVM-NEXT: Section: .section2 (0x2)
# MULTIPLE-LLVM-NEXT: }
## In this case we have a SHT_SYMTAB_SHNDX section placed right before
## the end of the file. This table is broken: it contains fewer entries than
## the number of dynamic symbols.
## Check we report a warning when trying to read an extended symbol index past
## the end of the file.
# RUN: yaml2obj --docnum=2 %s -o %t.pastend
# RUN: llvm-readelf --dyn-syms %t.pastend 2>&1 | \
# RUN: FileCheck %s -DFILE=%t.pastend --check-prefix=PASTEND-GNU --implicit-check-not=warning:
# RUN: llvm-readobj --dyn-syms %t.pastend 2>&1 | \
# RUN: FileCheck %s -DFILE=%t.pastend --check-prefix=PASTEND-LLVM --implicit-check-not=warning:
# PASTEND-GNU: 1: 00000000 0 NOTYPE LOCAL DEFAULT 1 dynsym1
# PASTEND-GNU-NEXT: warning: '[[FILE]]': unable to read an extended symbol table at index 2: can't read past the end of the file
# PASTEND-GNU-NEXT: 2: 00000000 0 NOTYPE LOCAL DEFAULT RSV[0xffff] dynsym2
# PASTEND-LLVM: Symbol {
# PASTEND-LLVM: Name: dynsym2 (1)
# PASTEND-LLVM-NEXT: Value: 0x0
# PASTEND-LLVM-NEXT: Size: 0
# PASTEND-LLVM-NEXT: Binding: Local (0x0)
# PASTEND-LLVM-NEXT: Type: None (0x0)
# PASTEND-LLVM-NEXT: Other: 0
# PASTEND-LLVM-NEXT: warning: '[[FILE]]': unable to read an extended symbol table at index 2: can't read past the end of the file
# PASTEND-LLVM-NEXT: Section: Reserved (0xFFFF)
# PASTEND-LLVM-NEXT: }
--- !ELF
FileHeader:
Class: ELFCLASS32
Data: ELFDATA2LSB
Type: ET_REL
Sections:
- Name: .section1
Type: SHT_PROGBITS
- Name: .section2
Type: SHT_PROGBITS
- Name: .dynamic
Type: SHT_DYNAMIC
Flags: [ SHF_ALLOC ]
Address: 0x1000
Offset: 0x1000
Entries:
- Tag: DT_SYMTAB
Value: 0x1500
- Tag: DT_HASH
Value: 0x1600
- Tag: DT_STRTAB
Value: 0x1700
- Tag: DT_STRSZ
Value: 17 ## ".dynsym1.dynsym2."
- Tag: DT_SYMTAB_SHNDX
Value: 0x2000
- Tag: DT_NULL
Value: 0
- Name: .dynsym
Type: SHT_DYNSYM
Flags: [ SHF_ALLOC ]
Offset: 0x1500
Address: 0x1500
## We need the .hash table to infer the number
## of dynamic symbols.
- Name: .hash
Type: SHT_HASH
Flags: [ SHF_ALLOC ]
Offset: 0x1600
Address: 0x1600
Bucket: [ 1 ]
Chain: [ 1, 2, 3 ]
- Name: .dynstr
Type: SHT_STRTAB
Flags: [ SHF_ALLOC ]
Offset: 0x1700
Address: 0x1700
- Name: .strtab
Type: SHT_STRTAB
- Name: .symtab_shndx
Type: SHT_SYMTAB_SHNDX
Flags: [ SHF_ALLOC ]
Entries: [ 0, 1 ]
Offset: 0x2000
Address: 0x2000
DynamicSymbols:
- Name: dynsym1
Index: SHN_XINDEX
- Name: dynsym2
Index: SHN_XINDEX
ProgramHeaders:
- Type: PT_LOAD
VAddr: 0x1000
FirstSec: .dynamic
LastSec: .symtab_shndx
- Type: PT_DYNAMIC
VAddr: 0x1000
FirstSec: .dynamic
LastSec: .dynamic
SectionHeaderTable:
NoHeaders: true

View File

@ -51,7 +51,7 @@ Symbols:
# RUN: yaml2obj --docnum=2 %s -o %t2
# RUN: not obj2yaml %t2 2>&1 | FileCheck %s -DFILE=%t2 --check-prefix=CASE2
# CASE2: Error reading file: [[FILE]]: extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0
# CASE2: Error reading file: [[FILE]]: found an extended symbol index (1), but unable to locate the extended symbol index table
--- !ELF
FileHeader:

View File

@ -5,7 +5,7 @@
# RUN: yaml2obj --docnum=1 %s -o %t1
# RUN: llvm-readobj --symbols 2>&1 %t1 | FileCheck -DFILE=%t1 %s --check-prefix=CASE1
# CASE1: warning: '[[FILE]]': extended symbol index (1) is past the end of the SHT_SYMTAB_SHNDX section of size 0
# CASE1: warning: '[[FILE]]': found an extended symbol index (1), but unable to locate the extended symbol index table
--- !ELF
FileHeader:

View File

@ -314,6 +314,7 @@ protected:
virtual void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset,
bool NonVisibilityBitsUsed) const {};
virtual void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
Optional<StringRef> StrTable, bool IsDynamic,
bool NonVisibilityBitsUsed) const = 0;
@ -321,9 +322,9 @@ protected:
virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0;
virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0;
Expected<ArrayRef<Elf_Versym>> getVersionTable(const Elf_Shdr &Sec,
ArrayRef<Elf_Sym> *SymTab,
StringRef *StrTab) const;
Expected<ArrayRef<Elf_Versym>>
getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab,
StringRef *StrTab, const Elf_Shdr **SymTabSec) const;
StringRef getPrintableSectionName(const Elf_Shdr &Sec) const;
std::vector<GroupSection> getGroups();
@ -372,6 +373,7 @@ protected:
DynRegionInfo DynRelrRegion;
DynRegionInfo DynPLTRelRegion;
Optional<DynRegionInfo> DynSymRegion;
DynRegionInfo DynSymTabShndxRegion;
DynRegionInfo DynamicTable;
StringRef DynamicStringTable;
const Elf_Hash *HashTable = nullptr;
@ -380,7 +382,7 @@ protected:
const Elf_Shdr *DotDynsymSec = nullptr;
const Elf_Shdr *DotCGProfileSec = nullptr;
const Elf_Shdr *DotAddrsigSec = nullptr;
ArrayRef<Elf_Word> ShndxTable;
DenseMap<const Elf_Shdr *, ArrayRef<Elf_Word>> ShndxTables;
Optional<uint64_t> SONameOffset;
const Elf_Shdr *SymbolVersionSection = nullptr; // .gnu.version
@ -394,10 +396,12 @@ protected:
mutable SmallVector<Optional<VersionEntry>, 16> VersionMap;
std::string getFullSymbolName(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
Optional<StringRef> StrTable,
bool IsDynamic) const;
Expected<unsigned> getSymbolSectionIndex(const Elf_Sym &Symbol,
unsigned SymIndex) const;
Expected<unsigned>
getSymbolSectionIndex(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable) const;
Expected<StringRef> getSymbolSectionName(const Elf_Sym &Symbol,
unsigned SectionIndex) const;
std::string getStaticSymbolName(uint32_t Index) const;
@ -415,6 +419,8 @@ protected:
Expected<RelSymbol<ELFT>> getRelocationTarget(const Relocation<ELFT> &R,
const Elf_Shdr *SymTab) const;
ArrayRef<Elf_Word> getShndxTable(const Elf_Shdr *Symtab) const;
};
template <class ELFT>
@ -432,9 +438,11 @@ std::string ELFDumper<ELFT>::describe(const Elf_Shdr &Sec) const {
return ::describe(Obj, Sec);
}
namespace {
template <class ELFT>
static Expected<StringRef> getLinkAsStrtab(const ELFFile<ELFT> &Obj,
const typename ELFT::Shdr &Sec) {
Expected<StringRef> getLinkAsStrtab(const ELFFile<ELFT> &Obj,
const typename ELFT::Shdr &Sec) {
Expected<const typename ELFT::Shdr *> StrTabSecOrErr =
Obj.getSection(Sec.sh_link);
if (!StrTabSecOrErr)
@ -448,11 +456,18 @@ static Expected<StringRef> getLinkAsStrtab(const ELFFile<ELFT> &Obj,
return *StrTabOrErr;
}
// Returns the linked symbol table and associated string table for a given section.
template <class ELFT> struct SymtabLink {
typename ELFT::SymRange Symbols;
StringRef StringTable;
const typename ELFT::Shdr *SymTab;
};
// Returns the linked symbol table, symbols and associated string table for a
// given section.
template <class ELFT>
static Expected<std::pair<typename ELFT::SymRange, StringRef>>
getLinkAsSymtab(const ELFFile<ELFT> &Obj, const typename ELFT::Shdr &Sec,
unsigned ExpectedType) {
Expected<SymtabLink<ELFT>> getLinkAsSymtab(const ELFFile<ELFT> &Obj,
const typename ELFT::Shdr &Sec,
unsigned ExpectedType) {
Expected<const typename ELFT::Shdr *> SymtabOrErr =
Obj.getSection(Sec.sh_link);
if (!SymtabOrErr)
@ -478,14 +493,17 @@ getLinkAsSymtab(const ELFFile<ELFT> &Obj, const typename ELFT::Shdr &Sec,
return createError("unable to read symbols from the " + describe(Obj, Sec) +
": " + toString(SymsOrErr.takeError()));
return std::make_pair(*SymsOrErr, *StrTabOrErr);
return SymtabLink<ELFT>{*SymsOrErr, *StrTabOrErr, *SymtabOrErr};
}
} // namespace
template <class ELFT>
Expected<ArrayRef<typename ELFT::Versym>>
ELFDumper<ELFT>::getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab,
StringRef *StrTab) const {
assert((!SymTab && !StrTab) || (SymTab && StrTab));
StringRef *StrTab,
const Elf_Shdr **SymTabSec) const {
assert((!SymTab && !StrTab && !SymTabSec) || (SymTab && StrTab && SymTabSec));
if (reinterpret_cast<uintptr_t>(Obj.base() + Sec.sh_offset) %
sizeof(uint16_t) !=
0)
@ -497,23 +515,26 @@ ELFDumper<ELFT>::getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab,
return createError("cannot read content of " + describe(Sec) + ": " +
toString(VersionsOrErr.takeError()));
Expected<std::pair<ArrayRef<Elf_Sym>, StringRef>> SymTabOrErr =
Expected<SymtabLink<ELFT>> SymTabOrErr =
getLinkAsSymtab(Obj, Sec, SHT_DYNSYM);
if (!SymTabOrErr) {
reportUniqueWarning(SymTabOrErr.takeError());
return *VersionsOrErr;
}
if (SymTabOrErr->first.size() != VersionsOrErr->size())
if (SymTabOrErr->Symbols.size() != VersionsOrErr->size())
reportUniqueWarning(describe(Sec) + ": the number of entries (" +
Twine(VersionsOrErr->size()) +
") does not match the number of symbols (" +
Twine(SymTabOrErr->first.size()) +
Twine(SymTabOrErr->Symbols.size()) +
") in the symbol table with index " +
Twine(Sec.sh_link));
if (SymTab)
std::tie(*SymTab, *StrTab) = *SymTabOrErr;
if (SymTab) {
*SymTab = SymTabOrErr->Symbols;
*StrTab = SymTabOrErr->StringTable;
*SymTabSec = SymTabOrErr->SymTab;
}
return *VersionsOrErr;
}
@ -720,9 +741,15 @@ void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
bool NonVisibilityBitsUsed =
llvm::any_of(Syms, [](const Elf_Sym &S) { return S.st_other & ~0x3; });
DataRegion<Elf_Word> ShndxTable =
IsDynamic ? DataRegion<Elf_Word>(
(const Elf_Word *)this->DynSymTabShndxRegion.Addr,
this->getElfObject().getELFFile().end())
: DataRegion<Elf_Word>(this->getShndxTable(SymtabSec));
printSymtabMessage(SymtabSec, Entries, NonVisibilityBitsUsed);
for (const Elf_Sym &Sym : Syms)
printSymbol(Sym, &Sym - Syms.begin(), StrTable, IsDynamic,
printSymbol(Sym, &Sym - Syms.begin(), ShndxTable, StrTable, IsDynamic,
NonVisibilityBitsUsed);
}
@ -819,18 +846,20 @@ private:
return OS;
}
void printHashedSymbol(const Elf_Sym *Sym, unsigned SymIndex,
StringRef StrTable, uint32_t Bucket);
DataRegion<Elf_Word> ShndxTable, StringRef StrTable,
uint32_t Bucket);
void printRelrReloc(const Elf_Relr &R) override;
void printRelRelaReloc(const Relocation<ELFT> &R,
const RelSymbol<ELFT> &RelSym) override;
void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
Optional<StringRef> StrTable, bool IsDynamic,
bool NonVisibilityBitsUsed) const override;
void printDynamicRelocHeader(unsigned Type, StringRef Name,
const DynRegionInfo &Reg) override;
std::string getSymbolSectionNdx(const Elf_Sym &Symbol,
unsigned SymIndex) const;
std::string getSymbolSectionNdx(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable) const;
void printProgramHeaders() override;
void printSectionMapping() override;
void printGNUVersionSectionProlog(const typename ELFT::Shdr &Sec,
@ -875,8 +904,10 @@ private:
void printRelRelaReloc(const Relocation<ELFT> &R,
const RelSymbol<ELFT> &RelSym) override;
void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex) const;
void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable) const;
void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
Optional<StringRef> StrTable, bool IsDynamic,
bool /*NonVisibilityBitsUsed*/) const override;
void printProgramHeaders() override;
@ -1011,11 +1042,23 @@ ELFDumper<ELFT>::getRelocationTarget(const Relocation<ELFT> &R,
const Elf_Sym *FirstSym =
cantFail(Obj.template getEntry<Elf_Sym>(*SymTab, 0));
std::string SymbolName = getFullSymbolName(
*Sym, Sym - FirstSym, *StrTableOrErr, SymTab->sh_type == SHT_DYNSYM);
std::string SymbolName =
getFullSymbolName(*Sym, Sym - FirstSym, getShndxTable(SymTab),
*StrTableOrErr, SymTab->sh_type == SHT_DYNSYM);
return RelSymbol<ELFT>(Sym, SymbolName);
}
template <typename ELFT>
ArrayRef<typename ELFT::Word>
ELFDumper<ELFT>::getShndxTable(const Elf_Shdr *Symtab) const {
if (Symtab) {
auto It = ShndxTables.find(Symtab);
if (It != ShndxTables.end())
return It->second;
}
return {};
}
static std::string maybeDemangle(StringRef Name) {
return opts::Demangle ? demangle(std::string(Name)) : Name.str();
}
@ -1073,6 +1116,7 @@ ELFDumper<ELFT>::getSymbolVersionByIndex(uint32_t SymbolVersionIndex,
template <typename ELFT>
std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym &Symbol,
unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
Optional<StringRef> StrTable,
bool IsDynamic) const {
if (!StrTable)
@ -1087,7 +1131,8 @@ std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym &Symbol,
}
if (SymbolName.empty() && Symbol.getType() == ELF::STT_SECTION) {
Expected<unsigned> SectionIndex = getSymbolSectionIndex(Symbol, SymIndex);
Expected<unsigned> SectionIndex =
getSymbolSectionIndex(Symbol, SymIndex, ShndxTable);
if (!SectionIndex) {
reportUniqueWarning(SectionIndex.takeError());
return "<?>";
@ -1119,8 +1164,8 @@ std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym &Symbol,
template <typename ELFT>
Expected<unsigned>
ELFDumper<ELFT>::getSymbolSectionIndex(const Elf_Sym &Symbol,
unsigned SymIndex) const {
ELFDumper<ELFT>::getSymbolSectionIndex(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable) const {
unsigned Ndx = Symbol.st_shndx;
if (Ndx == SHN_XINDEX)
return object::getExtendedSymbolTableIndex<ELFT>(Symbol, SymIndex,
@ -1900,7 +1945,8 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> &O,
: ObjDumper(Writer, O.getFileName()), ObjF(O), Obj(O.getELFFile()),
FileName(O.getFileName()), DynRelRegion(O, *this),
DynRelaRegion(O, *this), DynRelrRegion(O, *this),
DynPLTRelRegion(O, *this), DynamicTable(O, *this) {
DynPLTRelRegion(O, *this), DynSymTabShndxRegion(O, *this),
DynamicTable(O, *this) {
if (!O.IsContentValid())
return;
@ -1934,12 +1980,29 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> &O,
}
}
break;
case ELF::SHT_SYMTAB_SHNDX:
if (Expected<ArrayRef<Elf_Word>> ShndxTableOrErr = Obj.getSHNDXTable(Sec))
ShndxTable = *ShndxTableOrErr;
else
this->reportUniqueWarning(ShndxTableOrErr.takeError());
case ELF::SHT_SYMTAB_SHNDX: {
uint32_t SymtabNdx = Sec.sh_link;
if (SymtabNdx >= Sections.size()) {
reportUniqueWarning(
"unable to get the associated symbol table for " + describe(Sec) +
": sh_link (" + Twine(SymtabNdx) +
") is greater than or equal to the total number of sections (" +
Twine(Sections.size()) + ")");
continue;
}
if (Expected<ArrayRef<Elf_Word>> ShndxTableOrErr =
Obj.getSHNDXTable(Sec)) {
if (!ShndxTables.insert({&Sections[SymtabNdx], *ShndxTableOrErr})
.second)
reportUniqueWarning(
"multiple SHT_SYMTAB_SHNDX sections are linked to " +
describe(Sec));
} else {
reportUniqueWarning(ShndxTableOrErr.takeError());
}
break;
}
case ELF::SHT_GNU_versym:
if (!SymbolVersionSection)
SymbolVersionSection = &Sec;
@ -2081,6 +2144,10 @@ template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() {
DynPLTRelRegion.Size = Dyn.getVal();
DynPLTRelRegion.SizePrintName = "DT_PLTRELSZ value";
break;
case ELF::DT_SYMTAB_SHNDX:
DynSymTabShndxRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
DynSymTabShndxRegion.EntSize = sizeof(Elf_Word);
break;
}
}
@ -3781,8 +3848,10 @@ void GNUELFDumper<ELFT>::printSymtabMessage(const Elf_Shdr *Symtab,
}
template <class ELFT>
std::string GNUELFDumper<ELFT>::getSymbolSectionNdx(const Elf_Sym &Symbol,
unsigned SymIndex) const {
std::string
GNUELFDumper<ELFT>::getSymbolSectionNdx(const Elf_Sym &Symbol,
unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable) const {
unsigned SectionIndex = Symbol.st_shndx;
switch (SectionIndex) {
case ELF::SHN_UNDEF:
@ -3792,8 +3861,8 @@ std::string GNUELFDumper<ELFT>::getSymbolSectionNdx(const Elf_Sym &Symbol,
case ELF::SHN_COMMON:
return "COM";
case ELF::SHN_XINDEX: {
Expected<uint32_t> IndexOrErr = object::getExtendedSymbolTableIndex<ELFT>(
Symbol, SymIndex, this->ShndxTable);
Expected<uint32_t> IndexOrErr =
object::getExtendedSymbolTableIndex<ELFT>(Symbol, SymIndex, ShndxTable);
if (!IndexOrErr) {
assert(Symbol.st_shndx == SHN_XINDEX &&
"getExtendedSymbolTableIndex should only fail due to an invalid "
@ -3825,6 +3894,7 @@ std::string GNUELFDumper<ELFT>::getSymbolSectionNdx(const Elf_Sym &Symbol,
template <class ELFT>
void GNUELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
Optional<StringRef> StrTable,
bool IsDynamic,
bool NonVisibilityBitsUsed) const {
@ -3865,10 +3935,10 @@ void GNUELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
}
Fields[6].Column += NonVisibilityBitsUsed ? 13 : 0;
Fields[6].Str = getSymbolSectionNdx(Symbol, SymIndex);
Fields[6].Str = getSymbolSectionNdx(Symbol, SymIndex, ShndxTable);
Fields[7].Str =
this->getFullSymbolName(Symbol, SymIndex, StrTable, IsDynamic);
Fields[7].Str = this->getFullSymbolName(Symbol, SymIndex, ShndxTable,
StrTable, IsDynamic);
for (const Field &Entry : Fields)
printField(Entry);
OS << "\n";
@ -3877,6 +3947,7 @@ void GNUELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
template <class ELFT>
void GNUELFDumper<ELFT>::printHashedSymbol(const Elf_Sym *Symbol,
unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
StringRef StrTable,
uint32_t Bucket) {
unsigned Bias = ELFT::Is64Bits ? 8 : 0;
@ -3900,8 +3971,9 @@ void GNUELFDumper<ELFT>::printHashedSymbol(const Elf_Sym *Symbol,
printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));
Fields[6].Str =
printEnum(Symbol->getVisibility(), makeArrayRef(ElfSymbolVisibilities));
Fields[7].Str = getSymbolSectionNdx(*Symbol, SymIndex);
Fields[8].Str = this->getFullSymbolName(*Symbol, SymIndex, StrTable, true);
Fields[7].Str = getSymbolSectionNdx(*Symbol, SymIndex, ShndxTable);
Fields[8].Str =
this->getFullSymbolName(*Symbol, SymIndex, ShndxTable, StrTable, true);
for (const Field &Entry : Fields)
printField(Entry);
@ -3940,6 +4012,8 @@ void GNUELFDumper<ELFT>::printHashTableSymbols(const Elf_Hash &SysVHash) {
return;
}
DataRegion<Elf_Word> ShndxTable(
(const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end());
auto Buckets = SysVHash.buckets();
auto Chains = SysVHash.chains();
for (uint32_t Buc = 0; Buc < SysVHash.nbucket; Buc++) {
@ -3957,7 +4031,8 @@ void GNUELFDumper<ELFT>::printHashTableSymbols(const Elf_Hash &SysVHash) {
break;
}
printHashedSymbol(FirstSym + Ch, Ch, this->DynamicStringTable, Buc);
printHashedSymbol(FirstSym + Ch, Ch, ShndxTable, this->DynamicStringTable,
Buc);
Visited[Ch] = true;
}
}
@ -4001,6 +4076,8 @@ void GNUELFDumper<ELFT>::printGnuHashTableSymbols(const Elf_GnuHash &GnuHash) {
else
Values = *ValuesOrErr;
DataRegion<Elf_Word> ShndxTable(
(const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end());
ArrayRef<Elf_Word> Buckets = GnuHash.buckets();
for (uint32_t Buc = 0; Buc < GnuHash.nbuckets; Buc++) {
if (Buckets[Buc] == ELF::STN_UNDEF)
@ -4010,7 +4087,8 @@ void GNUELFDumper<ELFT>::printGnuHashTableSymbols(const Elf_GnuHash &GnuHash) {
while (true) {
uint32_t SymIndex = Index++;
if (const Elf_Sym *Sym = GetSymbol(SymIndex, DynSyms.size()))
printHashedSymbol(Sym, SymIndex, this->DynamicStringTable, Buc);
printHashedSymbol(Sym, SymIndex, ShndxTable, this->DynamicStringTable,
Buc);
else
break;
@ -4549,7 +4627,7 @@ void GNUELFDumper<ELFT>::printVersionSymbolSection(const Elf_Shdr *Sec) {
Sec->sh_size / sizeof(Elf_Versym));
Expected<ArrayRef<Elf_Versym>> VerTableOrErr =
this->getVersionTable(*Sec, /*SymTab=*/nullptr,
/*StrTab=*/nullptr);
/*StrTab=*/nullptr, /*SymTabSec=*/nullptr);
if (!VerTableOrErr) {
this->reportUniqueWarning(VerTableOrErr.takeError());
return;
@ -5667,7 +5745,8 @@ bool ELFDumper<ELFT>::printFunctionStackSize(
// means "any section".
if (FunctionSec) {
if (Expected<const Elf_Shdr *> SecOrErr =
Obj.getSection(Sym, this->DotSymtabSec, this->ShndxTable)) {
Obj.getSection(Sym, this->DotSymtabSec,
this->getShndxTable(this->DotSymtabSec))) {
if (*FunctionSec != *SecOrErr)
continue;
} else {
@ -5742,7 +5821,7 @@ void ELFDumper<ELFT>::printStackSize(const Relocation<ELFT> &R,
uint64_t RelocSymValue = 0;
if (Sym) {
Expected<const Elf_Shdr *> SectionOrErr =
this->Obj.getSection(*Sym, SymTab, this->ShndxTable);
this->Obj.getSection(*Sym, SymTab, this->getShndxTable(SymTab));
if (!SectionOrErr) {
reportUniqueWarning(
"cannot identify the section for relocation symbol '" +
@ -5966,11 +6045,14 @@ void GNUELFDumper<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
<< " Type Ndx Name\n";
else
OS << " Address Access Initial Sym.Val. Type Ndx Name\n";
DataRegion<Elf_Word> ShndxTable(
(const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end());
for (auto &E : Parser.getGlobalEntries()) {
const Elf_Sym &Sym = *Parser.getGotSym(&E);
const Elf_Sym &FirstSym = this->dynamic_symbols()[0];
std::string SymName = this->getFullSymbolName(
Sym, &Sym - &FirstSym, this->DynamicStringTable, false);
Sym, &Sym - &FirstSym, ShndxTable, this->DynamicStringTable, false);
OS.PadToColumn(2);
OS << to_string(format_hex_no_prefix(Parser.getGotAddress(&E), 8 + Bias));
@ -5983,7 +6065,8 @@ void GNUELFDumper<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
OS.PadToColumn(40 + 3 * Bias);
OS << printEnum(Sym.getType(), makeArrayRef(ElfSymbolTypes));
OS.PadToColumn(48 + 3 * Bias);
OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin());
OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin(),
ShndxTable);
OS.PadToColumn(52 + 3 * Bias);
OS << SymName << "\n";
}
@ -6018,12 +6101,14 @@ void GNUELFDumper<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
OS << "\n";
OS << " Entries:\n";
OS << " Address Initial Sym.Val. Type Ndx Name\n";
DataRegion<Elf_Word> ShndxTable(
(const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end());
for (auto &E : Parser.getPltEntries()) {
const Elf_Sym &Sym = *Parser.getPltSym(&E);
const Elf_Sym &FirstSym = *cantFail(
this->Obj.template getEntry<Elf_Sym>(*Parser.getPltSymTable(), 0));
std::string SymName = this->getFullSymbolName(
Sym, &Sym - &FirstSym, this->DynamicStringTable, false);
Sym, &Sym - &FirstSym, ShndxTable, this->DynamicStringTable, false);
OS.PadToColumn(2);
OS << to_string(format_hex_no_prefix(Parser.getPltAddress(&E), 8 + Bias));
@ -6034,7 +6119,8 @@ void GNUELFDumper<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
OS.PadToColumn(29 + 3 * Bias);
OS << printEnum(Sym.getType(), makeArrayRef(ElfSymbolTypes));
OS.PadToColumn(37 + 3 * Bias);
OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin());
OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin(),
ShndxTable);
OS.PadToColumn(41 + 3 * Bias);
OS << SymName << "\n";
}
@ -6276,15 +6362,17 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printSectionHeaders() {
StringRef StrTable = unwrapOrError(
this->FileName,
this->Obj.getStringTableForSymtab(*this->DotSymtabSec));
ArrayRef<Elf_Word> ShndxTable = this->getShndxTable(this->DotSymtabSec);
typename ELFT::SymRange Symbols = unwrapOrError(
this->FileName, this->Obj.symbols(this->DotSymtabSec));
for (const Elf_Sym &Sym : Symbols) {
const Elf_Shdr *SymSec = unwrapOrError(
this->FileName,
this->Obj.getSection(Sym, this->DotSymtabSec, this->ShndxTable));
this->Obj.getSection(Sym, this->DotSymtabSec, ShndxTable));
if (SymSec == &Sec)
printSymbol(Sym, &Sym - &Symbols[0], StrTable, false, false);
printSymbol(Sym, &Sym - &Symbols[0], ShndxTable, StrTable, false,
false);
}
}
}
@ -6300,8 +6388,9 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printSectionHeaders() {
}
template <class ELFT>
void LLVMELFDumper<ELFT>::printSymbolSection(const Elf_Sym &Symbol,
unsigned SymIndex) const {
void LLVMELFDumper<ELFT>::printSymbolSection(
const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable) const {
auto GetSectionSpecialType = [&]() -> Optional<StringRef> {
if (Symbol.isUndefined())
return StringRef("Undefined");
@ -6324,7 +6413,7 @@ void LLVMELFDumper<ELFT>::printSymbolSection(const Elf_Sym &Symbol,
}
Expected<unsigned> SectionIndex =
this->getSymbolSectionIndex(Symbol, SymIndex);
this->getSymbolSectionIndex(Symbol, SymIndex, ShndxTable);
if (!SectionIndex) {
assert(Symbol.st_shndx == SHN_XINDEX &&
"getSymbolSectionIndex should only fail due to an invalid "
@ -6351,11 +6440,12 @@ void LLVMELFDumper<ELFT>::printSymbolSection(const Elf_Sym &Symbol,
template <class ELFT>
void LLVMELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
DataRegion<Elf_Word> ShndxTable,
Optional<StringRef> StrTable,
bool IsDynamic,
bool /*NonVisibilityBitsUsed*/) const {
std::string FullSymbolName =
this->getFullSymbolName(Symbol, SymIndex, StrTable, IsDynamic);
std::string FullSymbolName = this->getFullSymbolName(
Symbol, SymIndex, ShndxTable, StrTable, IsDynamic);
unsigned char SymbolType = Symbol.getType();
DictScope D(W, "Symbol");
@ -6394,7 +6484,7 @@ void LLVMELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex,
}
W.printFlags("Other", Symbol.st_other, makeArrayRef(SymOtherFlags), 0x3u);
}
printSymbolSection(Symbol, SymIndex);
printSymbolSection(Symbol, SymIndex, ShndxTable);
}
template <class ELFT>
@ -6488,8 +6578,9 @@ void LLVMELFDumper<ELFT>::printVersionSymbolSection(const Elf_Shdr *Sec) {
StringRef StrTable;
ArrayRef<Elf_Sym> Syms;
const Elf_Shdr *SymTabSec;
Expected<ArrayRef<Elf_Versym>> VerTableOrErr =
this->getVersionTable(*Sec, &Syms, &StrTable);
this->getVersionTable(*Sec, &Syms, &StrTable, &SymTabSec);
if (!VerTableOrErr) {
this->reportUniqueWarning(VerTableOrErr.takeError());
return;
@ -6498,11 +6589,13 @@ void LLVMELFDumper<ELFT>::printVersionSymbolSection(const Elf_Shdr *Sec) {
if (StrTable.empty() || Syms.empty() || Syms.size() != VerTableOrErr->size())
return;
ArrayRef<Elf_Word> ShNdxTable = this->getShndxTable(SymTabSec);
for (size_t I = 0, E = Syms.size(); I < E; ++I) {
DictScope S(W, "Symbol");
W.printNumber("Version", (*VerTableOrErr)[I].vs_index & VERSYM_VERSION);
W.printString("Name", this->getFullSymbolName(Syms[I], I, StrTable,
/*IsDynamic=*/true));
W.printString("Name",
this->getFullSymbolName(Syms[I], I, ShNdxTable, StrTable,
/*IsDynamic=*/true));
}
}
@ -6830,10 +6923,12 @@ void LLVMELFDumper<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
W.printEnum("Type", Sym.getType(), makeArrayRef(ElfSymbolTypes));
const unsigned SymIndex = &Sym - this->dynamic_symbols().begin();
printSymbolSection(Sym, SymIndex);
DataRegion<Elf_Word> ShndxTable(
(const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end());
printSymbolSection(Sym, SymIndex, ShndxTable);
std::string SymName = this->getFullSymbolName(
Sym, SymIndex, this->DynamicStringTable, true);
Sym, SymIndex, ShndxTable, this->DynamicStringTable, true);
W.printNumber("Name", SymName, Sym.st_name);
}
}
@ -6867,6 +6962,8 @@ void LLVMELFDumper<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
}
{
ListScope LS(W, "Entries");
DataRegion<Elf_Word> ShndxTable(
(const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end());
for (auto &E : Parser.getPltEntries()) {
DictScope D(W, "Entry");
PrintEntry(&E);
@ -6874,12 +6971,13 @@ void LLVMELFDumper<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
const Elf_Sym &Sym = *Parser.getPltSym(&E);
W.printHex("Value", Sym.st_value);
W.printEnum("Type", Sym.getType(), makeArrayRef(ElfSymbolTypes));
printSymbolSection(Sym, &Sym - this->dynamic_symbols().begin());
printSymbolSection(Sym, &Sym - this->dynamic_symbols().begin(),
ShndxTable);
const Elf_Sym *FirstSym = cantFail(
this->Obj.template getEntry<Elf_Sym>(*Parser.getPltSymTable(), 0));
std::string SymName = this->getFullSymbolName(
Sym, &Sym - FirstSym, Parser.getPltStrTable(), true);
Sym, &Sym - FirstSym, ShndxTable, Parser.getPltStrTable(), true);
W.printNumber("Name", SymName, Sym.st_name);
}
}

View File

@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Object/ELF.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
using namespace llvm;
@ -54,3 +55,35 @@ TEST(ELFTest, getELFRelocationTypeNameForVE) {
TEST(ELFTest, getELFRelativeRelocationType) {
EXPECT_EQ(0U, getELFRelativeRelocationType(EM_VE));
}
// This is a test for the DataRegion helper struct, defined in ELF.h header.
TEST(ELFTest, DataRegionTest) {
std::vector<uint8_t> Data = {0, 1, 2};
// Used to check that the operator[] works properly.
auto CheckOperator = [&](DataRegion<uint8_t> &R) {
for (size_t I = 0, E = Data.size(); I != E; ++I) {
Expected<uint8_t> ValOrErr = R[I];
ASSERT_THAT_EXPECTED(ValOrErr, Succeeded());
EXPECT_EQ(*ValOrErr, I);
}
};
// Check we can use the constructor that takes an ArrayRef<T>.
DataRegion<uint8_t> Region(Data);
CheckOperator(Region);
const char *ErrMsg1 =
"the index is greater than or equal to the number of entries (3)";
EXPECT_THAT_ERROR(Region[3].takeError(), FailedWithMessage(ErrMsg1));
EXPECT_THAT_ERROR(Region[4].takeError(), FailedWithMessage(ErrMsg1));
// Check we can use the constructor that takes the data begin and the
// data end pointers.
Region = {Data.data(), Data.data() + Data.size()};
CheckOperator(Region);
const char *ErrMsg2 = "can't read past the end of the file";
EXPECT_THAT_ERROR(Region[3].takeError(), FailedWithMessage(ErrMsg2));
EXPECT_THAT_ERROR(Region[4].takeError(), FailedWithMessage(ErrMsg2));
}