summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorgii Rymar <grimar@accesssoftek.com>2020-12-08 12:39:04 +0300
committerGeorgii Rymar <grimar@accesssoftek.com>2021-01-13 11:36:43 +0300
commit141906fa149ffaa37bb5b65e9890ab1f0f3effd5 (patch)
tree78d47d3d595f49fa74b4d3c99438b2579e4ab2dc
parent3aeb30d1a68a76616c699587e07a7d8880c29d1c (diff)
downloadllvm-141906fa149ffaa37bb5b65e9890ab1f0f3effd5.tar.gz
[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
-rw-r--r--llvm/include/llvm/Object/ELF.h60
-rw-r--r--llvm/test/Object/invalid.test2
-rw-r--r--llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test4
-rw-r--r--llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test1
-rw-r--r--llvm/test/tools/llvm-readobj/ELF/mips-got.test4
-rw-r--r--llvm/test/tools/llvm-readobj/ELF/mips-plt.test4
-rw-r--r--llvm/test/tools/llvm-readobj/ELF/section-symbols.test2
-rw-r--r--llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test8
-rw-r--r--llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test331
-rw-r--r--llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml2
-rw-r--r--llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml2
-rw-r--r--llvm/tools/llvm-readobj/ELFDumper.cpp236
-rw-r--r--llvm/unittests/Object/ELFTest.cpp33
13 files changed, 593 insertions, 96 deletions
diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h
index bd224ada7783..86359ff44d56 100644
--- a/llvm/include/llvm/Object/ELF.h
+++ b/llvm/include/llvm/Object/ELF.h
@@ -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();
diff --git a/llvm/test/Object/invalid.test b/llvm/test/Object/invalid.test
index 95b677fae293..89bb4b5c5a62 100644
--- a/llvm/test/Object/invalid.test
+++ b/llvm/test/Object/invalid.test
@@ -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
diff --git a/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test b/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test
index 4b4a4bed4c8b..d8ad0200316e 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test
+++ b/llvm/test/tools/llvm-readobj/ELF/dyn-symbols.test
@@ -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:
diff --git a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test b/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test
index 49ea8631a4ba..b83007912914 100644
--- a/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test
+++ b/llvm/test/tools/llvm-readobj/ELF/dynamic-tags.test
@@ -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
diff --git a/llvm/test/tools/llvm-readobj/ELF/mips-got.test b/llvm/test/tools/llvm-readobj/ELF/mips-got.test
index 01bff1b914f8..6e6d80834a08 100644
--- a/llvm/test/tools/llvm-readobj/ELF/mips-got.test
+++ b/llvm/test/tools/llvm-readobj/ELF/mips-got.test
@@ -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
diff --git a/llvm/test/tools/llvm-readobj/ELF/mips-plt.test b/llvm/test/tools/llvm-readobj/ELF/mips-plt.test
index 607388cb852b..90c826346f49 100644
--- a/llvm/test/tools/llvm-readobj/ELF/mips-plt.test
+++ b/llvm/test/tools/llvm-readobj/ELF/mips-plt.test
@@ -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
diff --git a/llvm/test/tools/llvm-readobj/ELF/section-symbols.test b/llvm/test/tools/llvm-readobj/ELF/section-symbols.test
index 61f5991dafcd..1e40746b7303 100644
--- a/llvm/test/tools/llvm-readobj/ELF/section-symbols.test
+++ b/llvm/test/tools/llvm-readobj/ELF/section-symbols.test
@@ -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:
diff --git a/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test b/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test
index 62085b6c1883..97caf60207ff 100644
--- a/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test
+++ b/llvm/test/tools/llvm-readobj/ELF/symbol-shndx.test
@@ -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: ]
diff --git a/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test b/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test
new file mode 100644
index 000000000000..7ee9c2c0296a
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/symtab-shndx.test
@@ -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
diff --git a/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml b/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml
index 1c1e95e5bacb..12fba6c13714 100644
--- a/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml
+++ b/llvm/test/tools/obj2yaml/ELF/sht-symtab-shndx.yaml
@@ -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:
diff --git a/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml b/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml
index ec754de0e40a..3780fba5dd2e 100644
--- a/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml
+++ b/llvm/test/tools/yaml2obj/ELF/sht-symtab-shndx.yaml
@@ -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:
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 5e27a14d0475..e03a3d1edc7e 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -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);
}
}
diff --git a/llvm/unittests/Object/ELFTest.cpp b/llvm/unittests/Object/ELFTest.cpp
index b815d5cdd839..f85e866deeb5 100644
--- a/llvm/unittests/Object/ELFTest.cpp
+++ b/llvm/unittests/Object/ELFTest.cpp
@@ -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));
+}