mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-19 02:52:53 +02:00
[llvm-readobj] - Add a validation of the GNU hash table to printGnuHashHistogram().
Similar to D81937, we might crash when printing a histogram for a GNU hash table with a 'symndx' index that is larger than the number of dynamic symbols. This patch adopts and reuses the `getGnuHashTableChains()` helper which performs a validation of the table. As a side effect the warning reported for the --gnu-hash-table was improved. Also with this change we start to report a warning when the histogram is requested for the GNU hash table, but the dynamic symbols table is empty (size == 0). Differential revision: https://reviews.llvm.org/D82010
This commit is contained in:
parent
21433e6c3f
commit
40767ae0bd
@ -127,7 +127,7 @@ ProgramHeaders:
|
||||
# SYMNDX-NEXT: Shift Count: 0
|
||||
# SYMNDX-NEXT: Bloom Filter: [0x1]
|
||||
# SYMNDX-NEXT: Buckets: [2]
|
||||
# SYMNDX-NEXT: warning: '[[FILE]]': the first hashed symbol index (2) is larger than the number of dynamic symbols (2)
|
||||
# SYMNDX-NEXT: warning: '[[FILE]]': unable to dump 'Values' for the SHT_GNU_HASH section: the first hashed symbol index (2) is larger than the number of dynamic symbols (2)
|
||||
# SYMNDX-NEXT: }
|
||||
|
||||
--- !ELF
|
||||
|
@ -318,3 +318,112 @@ ProgramHeaders:
|
||||
Sections:
|
||||
- Section: .gnu.hash
|
||||
- Section: .dynamic
|
||||
|
||||
## Linkers might produce an empty no-op SHT_GNU_HASH section when
|
||||
## there are no dynamic symbols or when all dynamic symbols are undefined.
|
||||
## Such sections normally have a single zero entry in the bloom
|
||||
## filter, a single zero entry in the hash bucket and no values.
|
||||
##
|
||||
## The index of the first symbol in the dynamic symbol table
|
||||
## included in the hash table can be set to the number of dynamic symbols,
|
||||
## which is one larger than the index of the last dynamic symbol.
|
||||
## For empty tables however, this value is unimportant and can be ignored.
|
||||
|
||||
## Check the case when a 'symndx' index of the first symbol in the dynamic symbol
|
||||
## table is larger than the number of dynamic symbols.
|
||||
|
||||
## Case A: when the buckets array is not empty and has a non-zero value we report a warning.
|
||||
# RUN: yaml2obj --docnum=7 -DVAL=0x1 %s -o %t9
|
||||
# RUN: llvm-readelf --elf-hash-histogram %t9 2>&1 | \
|
||||
# RUN: FileCheck %s -DFILE=%t9 --check-prefix=ERR6
|
||||
|
||||
# ERR6: warning: '[[FILE]]': unable to print the GNU hash table histogram: the first hashed symbol index (16) is larger than the number of dynamic symbols (1)
|
||||
|
||||
## Case B: we do not report a warning when the buckets array contains only zero values.
|
||||
# RUN: yaml2obj --docnum=7 -DVAL=0x0 %s -o %t10
|
||||
# RUN: llvm-readelf --elf-hash-histogram %t10 2>&1 | \
|
||||
# RUN: FileCheck %s --allow-empty --implicit-check-not="Histogram"
|
||||
|
||||
## Case C: we do not report a warning when the buckets array is empty.
|
||||
# RUN: yaml2obj --docnum=7 -DVAL="" %s -o %t11
|
||||
# RUN: llvm-readelf --elf-hash-histogram %t11 2>&1 | \
|
||||
# RUN: FileCheck %s --allow-empty --implicit-check-not="Histogram"
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .gnu.hash
|
||||
Type: SHT_GNU_HASH
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Header:
|
||||
SymNdx: 0x10
|
||||
Shift2: 0x0
|
||||
BloomFilter: [ 0x0 ]
|
||||
HashBuckets: [ [[VAL]] ]
|
||||
HashValues: [ 0x0 ]
|
||||
- Name: .dynamic
|
||||
Type: SHT_DYNAMIC
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Link: .dynstr
|
||||
Entries:
|
||||
- Tag: DT_GNU_HASH
|
||||
Value: 0x0
|
||||
- Tag: DT_NULL
|
||||
Value: 0x0
|
||||
DynamicSymbols: []
|
||||
ProgramHeaders:
|
||||
- Type: PT_LOAD
|
||||
Sections:
|
||||
- Section: .gnu.hash
|
||||
- Section: .dynamic
|
||||
|
||||
## Check we report warnings when the dynamic symbol table is absent or empty.
|
||||
|
||||
## The code locates the dynamic symbol table by the section type. Use SHT_PROGBITS to hide it.
|
||||
# RUN: yaml2obj --docnum=8 -DTYPE=SHT_PROGBITS %s -o %t12
|
||||
# RUN: llvm-readelf --elf-hash-histogram %t12 2>&1 | \
|
||||
# RUN: FileCheck %s -DFILE=%t12 --check-prefix=ERR7
|
||||
|
||||
# ERR7: warning: '[[FILE]]': unable to print the GNU hash table histogram: no dynamic symbol table found
|
||||
|
||||
# RUN: yaml2obj --docnum=8 -DTYPE=SHT_DYNSYM %s -o %t13
|
||||
# RUN: llvm-readelf --elf-hash-histogram %t13 2>&1 | \
|
||||
# RUN: FileCheck %s -DFILE=%t13 --check-prefix=ERR8
|
||||
|
||||
# ERR8: warning: '[[FILE]]': unable to print the GNU hash table histogram: the dynamic symbol table is empty
|
||||
|
||||
--- !ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_DYN
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .gnu.hash
|
||||
Type: SHT_GNU_HASH
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Header:
|
||||
SymNdx: 0x0
|
||||
Shift2: 0x0
|
||||
BloomFilter: [ 0x0 ]
|
||||
HashBuckets: [ 0x0 ]
|
||||
HashValues: [ 0x0 ]
|
||||
- Name: .dynamic
|
||||
Type: SHT_DYNAMIC
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Entries:
|
||||
- Tag: DT_GNU_HASH
|
||||
Value: 0x0
|
||||
- Tag: DT_NULL
|
||||
Value: 0x0
|
||||
- Name: .dynsym
|
||||
Type: [[TYPE]]
|
||||
Size: 0
|
||||
ProgramHeaders:
|
||||
- Type: PT_LOAD
|
||||
Sections:
|
||||
- Section: .gnu.hash
|
||||
|
@ -325,6 +325,8 @@ public:
|
||||
return Table.slice(0, Size);
|
||||
}
|
||||
|
||||
Optional<DynRegionInfo> getDynSymRegion() const { return DynSymRegion; }
|
||||
|
||||
Elf_Sym_Range dynamic_symbols() const {
|
||||
if (!DynSymRegion)
|
||||
return Elf_Sym_Range();
|
||||
@ -2718,12 +2720,16 @@ template <typename ELFT> void ELFDumper<ELFT>::printHashTable() {
|
||||
|
||||
template <class ELFT>
|
||||
static Expected<ArrayRef<typename ELFT::Word>>
|
||||
getGnuHashTableChains(const typename ELFT::SymRange DynSymTable,
|
||||
getGnuHashTableChains(Optional<DynRegionInfo> DynSymRegion,
|
||||
const typename ELFT::GnuHash *GnuHashTable) {
|
||||
if (!DynSymRegion)
|
||||
return createError("no dynamic symbol table found");
|
||||
|
||||
ArrayRef<typename ELFT::Sym> DynSymTable =
|
||||
DynSymRegion->getAsArrayRef<typename ELFT::Sym>();
|
||||
size_t NumSyms = DynSymTable.size();
|
||||
if (!NumSyms)
|
||||
return createError("unable to dump 'Values' for the SHT_GNU_HASH "
|
||||
"section: the dynamic symbol table is empty");
|
||||
return createError("the dynamic symbol table is empty");
|
||||
|
||||
if (GnuHashTable->symndx < NumSyms)
|
||||
return GnuHashTable->values(NumSyms);
|
||||
@ -2773,17 +2779,13 @@ void ELFDumper<ELFT>::printGnuHashTable(const object::ObjectFile *Obj) {
|
||||
ArrayRef<Elf_Word> Buckets = GnuHashTable->buckets();
|
||||
W.printList("Buckets", Buckets);
|
||||
|
||||
if (!DynSymRegion) {
|
||||
reportWarning(createError("unable to dump 'Values' for the SHT_GNU_HASH "
|
||||
"section: no dynamic symbol table found"),
|
||||
ObjF->getFileName());
|
||||
return;
|
||||
}
|
||||
|
||||
Expected<ArrayRef<Elf_Word>> Chains =
|
||||
getGnuHashTableChains<ELFT>(dynamic_symbols(), GnuHashTable);
|
||||
getGnuHashTableChains<ELFT>(DynSymRegion, GnuHashTable);
|
||||
if (!Chains) {
|
||||
reportUniqueWarning(Chains.takeError());
|
||||
reportUniqueWarning(
|
||||
createError("unable to dump 'Values' for the SHT_GNU_HASH "
|
||||
"section: " +
|
||||
toString(Chains.takeError())));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -4660,20 +4662,26 @@ void GNUStyle<ELFT>::printHashHistogram(const Elf_Hash &HashTable) {
|
||||
|
||||
template <class ELFT>
|
||||
void GNUStyle<ELFT>::printGnuHashHistogram(const Elf_GnuHash &GnuHashTable) {
|
||||
size_t NBucket = GnuHashTable.nbuckets;
|
||||
ArrayRef<Elf_Word> Buckets = GnuHashTable.buckets();
|
||||
unsigned NumSyms = this->dumper()->dynamic_symbols().size();
|
||||
if (!NumSyms)
|
||||
Expected<ArrayRef<Elf_Word>> ChainsOrErr = getGnuHashTableChains<ELFT>(
|
||||
this->dumper()->getDynSymRegion(), &GnuHashTable);
|
||||
if (!ChainsOrErr) {
|
||||
this->reportUniqueWarning(
|
||||
createError("unable to print the GNU hash table histogram: " +
|
||||
toString(ChainsOrErr.takeError())));
|
||||
return;
|
||||
ArrayRef<Elf_Word> Chains = GnuHashTable.values(NumSyms);
|
||||
}
|
||||
|
||||
ArrayRef<Elf_Word> Chains = *ChainsOrErr;
|
||||
size_t Symndx = GnuHashTable.symndx;
|
||||
size_t TotalSyms = 0;
|
||||
size_t MaxChain = 1;
|
||||
size_t CumulativeNonZero = 0;
|
||||
|
||||
size_t NBucket = GnuHashTable.nbuckets;
|
||||
if (Chains.empty() || NBucket == 0)
|
||||
return;
|
||||
|
||||
ArrayRef<Elf_Word> Buckets = GnuHashTable.buckets();
|
||||
std::vector<size_t> ChainLen(NBucket, 0);
|
||||
for (size_t B = 0; B < NBucket; B++) {
|
||||
if (!Buckets[B])
|
||||
|
Loading…
Reference in New Issue
Block a user