aboutsummaryrefslogtreecommitdiff
path: root/llvm
diff options
context:
space:
mode:
authorGeorgii Rymar <grimar@accesssoftek.com>2020-07-02 13:38:42 +0300
committerGeorgii Rymar <grimar@accesssoftek.com>2020-07-07 11:59:00 +0300
commitd5cbf7ba32527dba53fa673ff7fd7f7fbb0b82fc (patch)
tree632f0d83a9da5abf451e64f0c4433ae5f11fd98f /llvm
parentcd503166fb74baf91c55f5f959ed9cd016cbd9f7 (diff)
downloadllvm-d5cbf7ba32527dba53fa673ff7fd7f7fbb0b82fc.zip
llvm-d5cbf7ba32527dba53fa673ff7fd7f7fbb0b82fc.tar.gz
llvm-d5cbf7ba32527dba53fa673ff7fd7f7fbb0b82fc.tar.bz2
[llvm-readobj] - Fix a crash scenario in GNUStyle<ELFT>::printHashSymbols().
We might crash when the dynamic symbols table is empty (or not found) and --hash-symbols is requested. Both .hash and .gnu.hash logic is affected. The patch fixes this issue. Differential revision: https://reviews.llvm.org/D83037
Diffstat (limited to 'llvm')
-rw-r--r--llvm/test/tools/llvm-readobj/ELF/hash-symbols.test128
-rw-r--r--llvm/tools/llvm-readobj/ELFDumper.cpp26
2 files changed, 151 insertions, 3 deletions
diff --git a/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test b/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test
index b43f3eb..2576fe0 100644
--- a/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test
+++ b/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test
@@ -509,3 +509,131 @@ ProgramHeaders:
Sections:
- Section: .gnu.hash
- Section: .dynamic
+
+## Check the behavior when the dynamic symbol table is empty or not found.
+
+## Case A.1: Check we report a warning when the dynamic symbol table is empty and we attempt to print hash symbols
+## from the .hash table. The number of symbols in the dynamic symbol table can be calculated from its size
+## or derived from the Chain vector of the .hash table. Make both ways to return a zero to do the check.
+# RUN: yaml2obj --docnum=9 %s -o %t9.1.so
+# RUN: llvm-readelf --hash-symbols %t9.1.so 2>&1 | FileCheck %s -DFILE=%t9.1.so --check-prefix=DYNSYM-EMPTY-HASH
+
+# DYNSYM-EMPTY-HASH: Symbol table of .hash for image:
+# DYNSYM-EMPTY-HASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name
+# DYNSYM-EMPTY-HASH-NEXT: warning: '[[FILE]]': unable to print symbols for the .hash table: the dynamic symbol table is empty
+# DYNSYM-EMPTY-HASH-NOT: {{.}}
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+ Machine: EM_386
+Sections:
+ - Name: .hash
+ Type: SHT_HASH
+ Flags: [ SHF_ALLOC ]
+ Bucket: [ 0 ]
+ Chain: [ ]
+ - Name: .dynamic
+ Type: SHT_DYNAMIC
+ Flags: [ SHF_ALLOC ]
+ Entries:
+ - Tag: DT_HASH
+ Value: 0x0
+ - Tag: DT_STRTAB
+## PT_LOAD p_offset == .hash offset == 0x54.
+## 0x54 + 0x2c == 0x80 == .dynstr offset.
+ Value: 0x2c
+ - Tag: DT_STRSZ
+ Value: 0x1
+ - Tag: DT_NULL
+ Value: 0x0
+ - Name: .dynstr
+ Type: SHT_STRTAB
+ Flags: [ SHF_ALLOC ]
+ - Name: .dynsym
+ Type: [[DYNSYMTYPE=SHT_DYNSYM]]
+ Flags: [ SHF_ALLOC ]
+ Size: 0
+ProgramHeaders:
+ - Type: PT_LOAD
+ Flags: [ PF_R, PF_X ]
+ Sections:
+ - Section: .hash
+ - Section: .dynamic
+ - Section: .dynstr
+
+## Case A.2: similar to A.1, but now check that we report a warning when the dynamic symbol table was not found.
+## To do that, set the type of the .dynsym to SHT_PROGBITS to hide it.
+# RUN: yaml2obj --docnum=9 -DDYNSYMTYPE=SHT_PROGBITS %s -o %t9.2.so
+# RUN: llvm-readelf --hash-symbols %t9.2.so 2>&1 | FileCheck %s -DFILE=%t9.2.so --check-prefix=DYNSYM-NOTFOUND-HASH
+
+# DYNSYM-NOTFOUND-HASH: Symbol table of .hash for image:
+# DYNSYM-NOTFOUND-HASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name
+# DYNSYM-NOTFOUND-HASH-NEXT: warning: '[[FILE]]': unable to print symbols for the .hash table: the dynamic symbol table was not found
+# DYNSYM-NOTFOUND-HASH-NOT: {{.}}
+
+## Case B.1: Check we report a warning when the dynamic symbol table is empty and we attempt to print
+## hash symbols from the .gnu.hash table.
+# RUN: yaml2obj --docnum=10 %s -o %t10.1.so
+# RUN: llvm-readelf --hash-symbols %t10.1.so 2>&1 | FileCheck %s -DFILE=%t10.1.so --check-prefix=DYNSYM-EMPTY-GNUHASH
+
+# DYNSYM-EMPTY-GNUHASH: Symbol table of .gnu.hash for image:
+# DYNSYM-EMPTY-GNUHASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name
+# DYNSYM-EMPTY-GNUHASH-NEXT: warning: '[[FILE]]': unable to print symbols for the .gnu.hash table: the dynamic symbol table is empty
+# DYNSYM-EMPTY-GNUHASH-NOT: {{.}}
+
+## Case B.2: similar to B.1, but now check that we report a warning when the dynamic symbol table was not found.
+## To do that, set the type of the .dynsym to SHT_PROGBITS to hide it.
+# RUN: yaml2obj --docnum=10 -DDYNSYMTYPE=SHT_PROGBITS %s -o %t10.2.so
+# RUN: llvm-readelf --hash-symbols %t10.2.so 2>&1 | FileCheck %s -DFILE=%t10.2.so --check-prefix=DYNSYM-NOTFOUND-GNUHASH
+
+# DYNSYM-NOTFOUND-GNUHASH: Symbol table of .gnu.hash for image:
+# DYNSYM-NOTFOUND-GNUHASH-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name
+# DYNSYM-NOTFOUND-GNUHASH-NEXT: warning: '[[FILE]]': unable to print symbols for the .gnu.hash table: the dynamic symbol table was not found
+# DYNSYM-NOTFOUND-GNUHASH-NOT: {{.}}
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+ Machine: EM_386
+Sections:
+ - Name: .gnu.hash
+ Type: SHT_GNU_HASH
+ Flags: [ SHF_ALLOC ]
+ Header:
+ SymNdx: 0x0
+ Shift2: 0x0
+ BloomFilter: [ 0x0 ]
+ HashBuckets: [ 0x1 ]
+ HashValues: [ 0x0 ]
+ - Name: .dynamic
+ Type: SHT_DYNAMIC
+ Flags: [ SHF_ALLOC ]
+ Entries:
+ - Tag: DT_GNU_HASH
+ Value: 0x0
+ - Tag: DT_STRTAB
+## PT_LOAD p_offset == .hash offset == 0x54.
+## 0x54 + 0x3c == 0x80 == .dynstr offset.
+ Value: 0x3c
+ - Tag: DT_STRSZ
+ Value: 0x1
+ - Tag: DT_NULL
+ Value: 0x0
+ - Name: .dynstr
+ Type: SHT_STRTAB
+ - Name: .dynsym
+ Type: [[DYNSYMTYPE=SHT_DYNSYM]]
+ Flags: [ SHF_ALLOC ]
+ Size: 0
+ProgramHeaders:
+ - Type: PT_LOAD
+ Flags: [ PF_R, PF_X ]
+ Sections:
+ - Section: .gnu.hash
+ - Section: .dynamic
+ - Section: .dynstr
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index e2ea2c3..7a29606 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -4066,7 +4066,7 @@ template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) {
if (this->dumper()->getDynamicStringTable().empty())
return;
auto StringTable = this->dumper()->getDynamicStringTable();
- auto DynSyms = this->dumper()->dynamic_symbols();
+ Elf_Sym_Range DynSyms = this->dumper()->dynamic_symbols();
auto PrintHashTable = [&](const Elf_Hash *SysVHash) {
if (ELFT::Is64Bits)
@@ -4075,6 +4075,16 @@ template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) {
OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
OS << "\n";
+ const Elf_Sym *FirstSym = DynSyms.empty() ? nullptr : &DynSyms[0];
+ if (!FirstSym) {
+ Optional<DynRegionInfo> DynSymRegion = this->dumper()->getDynSymRegion();
+ this->reportUniqueWarning(
+ createError(Twine("unable to print symbols for the .hash table: the "
+ "dynamic symbol table ") +
+ (DynSymRegion ? "is empty" : "was not found")));
+ return;
+ }
+
auto Buckets = SysVHash->buckets();
auto Chains = SysVHash->chains();
for (uint32_t Buc = 0; Buc < SysVHash->nbucket; Buc++) {
@@ -4093,7 +4103,7 @@ template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) {
break;
}
- printHashedSymbol(Obj, &DynSyms[0], Ch, StringTable, Buc);
+ printHashedSymbol(Obj, FirstSym, Ch, StringTable, Buc);
Visited[Ch] = true;
}
}
@@ -4124,6 +4134,16 @@ template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) {
return;
}
+ const Elf_Sym *FirstSym = DynSyms.empty() ? nullptr : &DynSyms[0];
+ if (!FirstSym) {
+ Optional<DynRegionInfo> DynSymRegion = this->dumper()->getDynSymRegion();
+ this->reportUniqueWarning(createError(
+ Twine("unable to print symbols for the .gnu.hash table: the "
+ "dynamic symbol table ") +
+ (DynSymRegion ? "is empty" : "was not found")));
+ return;
+ }
+
auto Buckets = GnuHash->buckets();
for (uint32_t Buc = 0; Buc < GnuHash->nbuckets; Buc++) {
if (Buckets[Buc] == ELF::STN_UNDEF)
@@ -4132,7 +4152,7 @@ template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) {
uint32_t GnuHashable = Index - GnuHash->symndx;
// Print whole chain
while (true) {
- printHashedSymbol(Obj, &DynSyms[0], Index++, StringTable, Buc);
+ printHashedSymbol(Obj, FirstSym, Index++, StringTable, Buc);
// Chain ends at symbol with stopper bit
if ((GnuHash->values(DynSyms.size())[GnuHashable++] & 1) == 1)
break;