[llvm] r265967 - [llvm-readobj] Add ELF hash histogram printing
Hemant Kulkarni via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 11 10:15:30 PDT 2016
Author: khemant
Date: Mon Apr 11 12:15:30 2016
New Revision: 265967
URL: http://llvm.org/viewvc/llvm-project?rev=265967&view=rev
Log:
[llvm-readobj] Add ELF hash histogram printing
Differential Revision: http://reviews.llvm.org/D18907
Added:
llvm/trunk/test/tools/llvm-readobj/elf-hash-histogram.test
Modified:
llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
llvm/trunk/tools/llvm-readobj/ObjDumper.h
llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp
Added: llvm/trunk/test/tools/llvm-readobj/elf-hash-histogram.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-readobj/elf-hash-histogram.test?rev=265967&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-readobj/elf-hash-histogram.test (added)
+++ llvm/trunk/test/tools/llvm-readobj/elf-hash-histogram.test Mon Apr 11 12:15:30 2016
@@ -0,0 +1,27 @@
+RUN: llvm-readobj -elf-hash-histogram %p/Inputs/gnuhash.so.elf-ppc64 \
+RUN: --elf-output-style=GNU | FileCheck %s -check-prefix PPC64GNU
+RUN: llvm-readobj -elf-hash-histogram %p/Inputs/gnuhash.so.elf-x86_64 --elf-output-style=GNU \
+RUN: | FileCheck %s -check-prefix X86GNU
+RUN: llvm-readobj -elf-hash-histogram %p/Inputs/got-plt.exe.elf-mipsel --elf-output-style=GNU \
+RUN: | FileCheck %s -check-prefix SYSV
+
+PPC64GNU: Histogram for `.gnu.hash' bucket list length (total of 3 buckets)
+PPC64GNU-NEXT: Length Number % of total Coverage
+PPC64GNU-NEXT: 0 1 ( 33.3%) 0.0%
+PPC64GNU-NEXT: 1 1 ( 33.3%) 25.0%
+PPC64GNU-NEXT: 2 0 ( 0.0%) 25.0%
+PPC64GNU-NEXT: 3 1 ( 33.3%) 100.0%
+
+X86GNU: Histogram for `.gnu.hash' bucket list length (total of 3 buckets)
+X86GNU-NEXT: Length Number % of total Coverage
+X86GNU-NEXT: 0 1 ( 33.3%) 0.0%
+X86GNU-NEXT: 1 1 ( 33.3%) 25.0%
+X86GNU-NEXT: 2 0 ( 0.0%) 25.0%
+X86GNU-NEXT: 3 1 ( 33.3%) 100.0%
+
+SYSV: Histogram for bucket list length (total of 3 buckets)
+SYSV-NEXT: Length Number % of total Coverage
+SYSV-NEXT: 0 0 ( 0.0%) 0.0%
+SYSV-NEXT: 1 0 ( 0.0%) 0.0%
+SYSV-NEXT: 2 2 ( 66.7%) 57.1%
+SYSV-NEXT: 3 1 ( 33.3%) 100.0%
Modified: llvm/trunk/tools/llvm-readobj/ELFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ELFDumper.cpp?rev=265967&r1=265966&r2=265967&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/ELFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/ELFDumper.cpp Mon Apr 11 12:15:30 2016
@@ -61,6 +61,8 @@ using namespace ELF;
typedef typename ELFO::Elf_Half Elf_Half; \
typedef typename ELFO::Elf_Ehdr Elf_Ehdr; \
typedef typename ELFO::Elf_Word Elf_Word; \
+ typedef typename ELFO::Elf_Hash Elf_Hash; \
+ typedef typename ELFO::Elf_GnuHash Elf_GnuHash; \
typedef typename ELFO::uintX_t uintX_t;
namespace {
@@ -121,6 +123,8 @@ public:
void printStackMap() const override;
+ void printHashHistogram() override;
+
private:
std::unique_ptr<DumpStyle<ELFT>> ELFDumperStyle;
typedef ELFFile<ELFT> ELFO;
@@ -234,6 +238,8 @@ public:
const DynRegionInfo &getDynRelRegion() const { return DynRelRegion; }
const DynRegionInfo &getDynRelaRegion() const { return DynRelaRegion; }
const DynRegionInfo &getDynPLTRelRegion() const { return DynPLTRelRegion; }
+ const Elf_Hash *getHashTable() const { return HashTable; }
+ const Elf_GnuHash *getGnuHashTable() const { return GnuHashTable; }
};
template <class ELFT>
@@ -284,6 +290,7 @@ public:
const Elf_Sym *FirstSym, StringRef StrTable,
bool IsDynamic) = 0;
virtual void printProgramHeaders(const ELFFile<ELFT> *Obj) = 0;
+ virtual void printHashHistogram(const ELFFile<ELFT> *Obj) = 0;
const ELFDumper<ELFT> *dumper() const { return Dumper; }
private:
const ELFDumper<ELFT> *Dumper;
@@ -305,6 +312,7 @@ public:
virtual void printSymtabMessage(const ELFO *Obj, StringRef Name,
size_t Offset) override;
void printProgramHeaders(const ELFO *Obj) override;
+ void printHashHistogram(const ELFFile<ELFT> *Obj) override;
private:
struct Field {
@@ -357,6 +365,7 @@ public:
void printDynamicSymbols(const ELFO *Obj) override;
void printDynamicRelocations(const ELFO *Obj) override;
void printProgramHeaders(const ELFO *Obj) override;
+ void printHashHistogram(const ELFFile<ELFT> *Obj) override;
private:
void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab);
@@ -1390,6 +1399,9 @@ void ELFDumper<ELFT>::printDynamicSymbol
ELFDumperStyle->printDynamicSymbols(Obj);
}
+template <class ELFT> void ELFDumper<ELFT>::printHashHistogram() {
+ ELFDumperStyle->printHashHistogram(Obj);
+}
#define LLVM_READOBJ_TYPE_CASE(name) \
case DT_##name: return #name
@@ -2920,6 +2932,111 @@ void GNUStyle<ELFT>::printDynamicRelocat
}
}
+// Hash histogram shows statistics of how efficient the hash was for the
+// dynamic symbol table. The table shows number of hash buckets for different
+// lengths of chains as absolute number and percentage of the total buckets.
+// Additionally cumulative coverage of symbols for each set of buckets.
+template <class ELFT>
+void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
+
+ const Elf_Hash *HashTable = this->dumper()->getHashTable();
+ const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable();
+
+ // Print histogram for .hash section
+ if (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;
+ size_t CumulativeNonZero = 0;
+
+ if (NChain == 0 || NBucket == 0)
+ return;
+
+ std::vector<size_t> ChainLen(NBucket, 0);
+ // Go over all buckets and and note chain lengths of each bucket (total
+ // unique chain lengths).
+ for (size_t B = 0; B < NBucket; B++) {
+ for (size_t C = Buckets[B]; C > 0 && C < NChain; C = Chains[C])
+ if (MaxChain <= ++ChainLen[B])
+ MaxChain++;
+ TotalSyms += ChainLen[B];
+ }
+
+ if (!TotalSyms)
+ return;
+
+ 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]];
+ // Print Number of buckets with each chain lengths and their cumulative
+ // coverage of the symbols
+ OS << "Histogram for bucket list length (total of " << NBucket
+ << " buckets)\n"
+ << " Length Number % of total Coverage\n";
+ 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 .gnu.hash section
+ if (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;
+ size_t TotalSyms = 0;
+ size_t MaxChain = 1;
+ size_t CumulativeNonZero = 0;
+
+ if (Chains.size() == 0 || NBucket == 0)
+ return;
+
+ std::vector<size_t> ChainLen(NBucket, 0);
+
+ for (size_t B = 0; B < NBucket; B++) {
+ if (!Buckets[B])
+ continue;
+ size_t Len = 1;
+ for (size_t C = Buckets[B] - Symndx;
+ C < Chains.size() && (Chains[C] & 1) == 0; C++)
+ if (MaxChain < ++Len)
+ MaxChain++;
+ ChainLen[B] = Len;
+ TotalSyms += Len;
+ }
+ MaxChain++;
+
+ if (!TotalSyms)
+ return;
+
+ 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
+ // coverage of the symbols
+ 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++) {
+ 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);
+ }
+ }
+}
+
template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) {
const Elf_Ehdr *e = Obj->getHeader();
{
@@ -3281,3 +3398,7 @@ void LLVMStyle<ELFT>::printProgramHeader
W.printNumber("Alignment", Phdr.p_align);
}
}
+template <class ELFT>
+void LLVMStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
+ W.startLine() << "Hash Histogram not implemented!\n";
+}
Modified: llvm/trunk/tools/llvm-readobj/ObjDumper.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/ObjDumper.h?rev=265967&r1=265966&r2=265967&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/ObjDumper.h (original)
+++ llvm/trunk/tools/llvm-readobj/ObjDumper.h Mon Apr 11 12:15:30 2016
@@ -43,6 +43,7 @@ public:
virtual void printLoadName() {}
virtual void printVersionInfo() {}
virtual void printGroupSections() {}
+ virtual void printHashHistogram() {}
// Only implemented for ARM ELF at this time.
virtual void printAttributes() { }
Modified: llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp?rev=265967&r1=265966&r2=265967&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/llvm-readobj.cpp Mon Apr 11 12:15:30 2016
@@ -232,6 +232,11 @@ namespace opts {
cl::desc("Display ELF section group contents"));
cl::alias SectionGroupsShort("g", cl::desc("Alias for -elf-sections-groups"),
cl::aliasopt(SectionGroups));
+ cl::opt<bool> HashHistogram(
+ "elf-hash-histogram",
+ cl::desc("Display bucket list histogram for hash sections"));
+ cl::alias HashHistogramShort("I", cl::desc("Alias for -elf-hash-histogram"),
+ cl::aliasopt(HashHistogram));
cl::opt<OutputStyleTy>
Output("elf-output-style", cl::desc("Specify ELF dump style"),
@@ -360,6 +365,8 @@ static void dumpObject(const ObjectFile
}
if (opts::SectionGroups)
Dumper->printGroupSections();
+ if (opts::HashHistogram)
+ Dumper->printHashHistogram();
}
if (Obj->isCOFF()) {
if (opts::COFFImports)
More information about the llvm-commits
mailing list