[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