[llvm] fc98447 - [llvm-readobj] - Do not skip building of the GNU hash table histogram.
Georgii Rymar via llvm-commits
llvm-commits at lists.llvm.org
Wed May 27 03:46:58 PDT 2020
Author: Georgii Rymar
Date: 2020-05-27T13:46:41+03:00
New Revision: fc98447af65f5a51d3b62a7e76a056d2556be59d
URL: https://github.com/llvm/llvm-project/commit/fc98447af65f5a51d3b62a7e76a056d2556be59d
DIFF: https://github.com/llvm/llvm-project/commit/fc98447af65f5a51d3b62a7e76a056d2556be59d.diff
LOG: [llvm-readobj] - Do not skip building of the GNU hash table histogram.
When the `--elf-hash-histogram` is used, the code first tries to build
a histogram for the .hash table and then for the .gnu.hash table.
The problem is that dumper might return early when unable or do not need to
build a histogram for the .hash.
This patch reorders the code slightly to fix the issue and adds a test case.
Differential revision: https://reviews.llvm.org/D80204
Added:
Modified:
llvm/test/tools/llvm-readobj/ELF/hash-histogram.test
llvm/tools/llvm-readobj/ELFDumper.cpp
Removed:
################################################################################
diff --git a/llvm/test/tools/llvm-readobj/ELF/hash-histogram.test b/llvm/test/tools/llvm-readobj/ELF/hash-histogram.test
index f7551b481a86..5447bffceec3 100644
--- a/llvm/test/tools/llvm-readobj/ELF/hash-histogram.test
+++ b/llvm/test/tools/llvm-readobj/ELF/hash-histogram.test
@@ -207,3 +207,62 @@ ProgramHeaders:
Sections:
- Section: .hash
- Section: .dynamic
+
+## Check we dump a histogram for the .gnu.hash table even when the .hash table is skipped.
+
+## Case A: the .hash table has no data to build histogram and it is skipped.
+## (NBUCKET == 0x1 is a no-op: it does not change the number of buckets described with the "Bucket" key).
+# RUN: yaml2obj --docnum=5 -DNBUCKET=0x1 %s -o %t5.o
+# RUN: llvm-readelf --elf-hash-histogram %t5.o 2>&1 | \
+# RUN: FileCheck %s --check-prefix=GNU-HASH --implicit-check-not="Histogram"
+
+## Case B: the .hash table has a broken nbucket field. We report a warning
+## and skip dumping of the .hash table.
+# RUN: yaml2obj --docnum=5 -DNBUCKET=0xffffffff %s -o %t6.o
+# RUN: llvm-readelf --elf-hash-histogram %t6.o 2>&1 | \
+# RUN: FileCheck %s -DFILE=%t6.o --check-prefixes=WARN,GNU-HASH
+
+# WARN: warning: '[[FILE]]': the hash table at offset 0x78 goes past the end of the file (0x350), nbucket = 4294967295, nchain = 1
+# GNU-HASH: Histogram for `.gnu.hash' bucket list length (total of 1 buckets)
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+ Machine: EM_X86_64
+Sections:
+ - Name: .hash
+ Type: SHT_HASH
+ Flags: [ SHF_ALLOC ]
+ Bucket: [ 0 ]
+ NBucket: [[NBUCKET]]
+ Chain: [ 0 ]
+ - Name: .gnu.hash
+ Type: SHT_GNU_HASH
+ Flags: [ SHF_ALLOC ]
+ Header:
+ SymNdx: 0x1
+ Shift2: 0x0
+ BloomFilter: [ 0x0 ]
+ HashBuckets: [ 0x00000001, 0x00000004, 0x00000000 ]
+ HashValues: [ 0x0B887388 ]
+ - Name: .dynamic
+ Type: SHT_DYNAMIC
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ Entries:
+ - Tag: DT_HASH
+ Value: 0x0
+ - Tag: DT_GNU_HASH
+## sizeof(.hash) == 0x28.
+ Value: 0x28
+ - Tag: DT_NULL
+ Value: 0x0
+DynamicSymbols:
+ - Name: foo
+ProgramHeaders:
+ - Type: PT_LOAD
+ Sections:
+ - Section: .hash
+ - Section: .gnu.hash
+ - Section: .dynamic
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 1bcf488c15f8..c9d45061320d 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -4562,15 +4562,11 @@ void GNUStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
// Additionally cumulative coverage of symbols for each set of buckets.
template <class ELFT>
void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
- // Print histogram for .hash section
- if (const Elf_Hash *HashTable = this->dumper()->getHashTable()) {
- if (!checkHashTable(Obj, HashTable, this->FileName))
- return;
-
- size_t NBucket = HashTable->nbucket;
- size_t NChain = HashTable->nchain;
- ArrayRef<Elf_Word> Buckets = HashTable->buckets();
- ArrayRef<Elf_Word> Chains = HashTable->chains();
+ auto PrintHashHist = [&](const Elf_Hash &HashTable) {
+ size_t NBucket = HashTable.nbucket;
+ size_t NChain = HashTable.nchain;
+ ArrayRef<Elf_Word> Buckets = HashTable.buckets();
+ ArrayRef<Elf_Word> Chains = HashTable.chains();
size_t TotalSyms = 0;
// If hash table is correct, we have at least chains with 0 length
size_t MaxChain = 1;
@@ -4604,7 +4600,7 @@ void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
if (!TotalSyms)
return;
- std::vector<size_t> Count(MaxChain, 0) ;
+ std::vector<size_t> Count(MaxChain, 0);
// Count how long is the chain for each bucket
for (size_t B = 0; B < NBucket; B++)
++Count[ChainLen[B]];
@@ -4619,17 +4615,16 @@ void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
(Count[I] * 100.0) / NBucket,
(CumulativeNonZero * 100.0) / TotalSyms);
}
- }
+ };
- // Print histogram for .gnu.hash section
- if (const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable()) {
- size_t NBucket = GnuHashTable->nbuckets;
- ArrayRef<Elf_Word> Buckets = GnuHashTable->buckets();
+ auto PrintGnuHashHist = [&](const Elf_GnuHash &GnuHashTable) {
+ size_t NBucket = GnuHashTable.nbuckets;
+ ArrayRef<Elf_Word> Buckets = GnuHashTable.buckets();
unsigned NumSyms = this->dumper()->dynamic_symbols().size();
if (!NumSyms)
return;
- ArrayRef<Elf_Word> Chains = GnuHashTable->values(NumSyms);
- size_t Symndx = GnuHashTable->symndx;
+ ArrayRef<Elf_Word> Chains = GnuHashTable.values(NumSyms);
+ size_t Symndx = GnuHashTable.symndx;
size_t TotalSyms = 0;
size_t MaxChain = 1;
size_t CumulativeNonZero = 0;
@@ -4655,7 +4650,7 @@ void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
if (!TotalSyms)
return;
- std::vector<size_t> Count(MaxChain, 0) ;
+ std::vector<size_t> Count(MaxChain, 0);
for (size_t B = 0; B < NBucket; B++)
++Count[ChainLen[B]];
// Print Number of buckets with each chain lengths and their cumulative
@@ -4663,13 +4658,22 @@ void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
OS << "Histogram for `.gnu.hash' bucket list length (total of " << NBucket
<< " buckets)\n"
<< " Length Number % of total Coverage\n";
- for (size_t I = 0; I <MaxChain; I++) {
+ for (size_t I = 0; I < MaxChain; I++) {
CumulativeNonZero += Count[I] * I;
OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I],
(Count[I] * 100.0) / NBucket,
(CumulativeNonZero * 100.0) / TotalSyms);
}
- }
+ };
+
+ // Print histogram for the .hash section.
+ if (const Elf_Hash *HashTable = this->dumper()->getHashTable())
+ if (checkHashTable(Obj, HashTable, this->FileName))
+ PrintHashHist(*HashTable);
+
+ // Print histogram for the .gnu.hash section.
+ if (const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable())
+ PrintGnuHashHist(*GnuHashTable);
}
template <class ELFT>
More information about the llvm-commits
mailing list