diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -230,7 +230,7 @@ void printStackMap() const override; - void printHashHistogram() override; + void printHashHistograms() override; void printCGProfile() override; void printAddrsig() override; @@ -742,7 +742,7 @@ const Elf_Shdr *Sec) = 0; virtual void printVersionDependencySection(const ELFFile *Obj, const Elf_Shdr *Sec) = 0; - virtual void printHashHistogram(const ELFFile *Obj) = 0; + virtual void printHashHistograms(const ELFFile *Obj) = 0; virtual void printCGProfile(const ELFFile *Obj) = 0; virtual void printAddrsig(const ELFFile *Obj) = 0; virtual void printNotes(const ELFFile *Obj) = 0; @@ -811,7 +811,7 @@ const Elf_Shdr *Sec) override; void printVersionDependencySection(const ELFFile *Obj, const Elf_Shdr *Sec) override; - void printHashHistogram(const ELFFile *Obj) override; + void printHashHistograms(const ELFFile *Obj) override; void printCGProfile(const ELFFile *Obj) override; void printAddrsig(const ELFFile *Obj) override; void printNotes(const ELFFile *Obj) override; @@ -823,6 +823,9 @@ void printMipsABIFlags(const ELFObjectFile *Obj) override; private: + void printHashHistogram(const Elf_Hash &HashTable); + void printGnuHashHistogram(const Elf_GnuHash &GnuHashTable); + struct Field { std::string Str; unsigned Column; @@ -932,7 +935,7 @@ const Elf_Shdr *Sec) override; void printVersionDependencySection(const ELFFile *Obj, const Elf_Shdr *Sec) override; - void printHashHistogram(const ELFFile *Obj) override; + void printHashHistograms(const ELFFile *Obj) override; void printCGProfile(const ELFFile *Obj) override; void printAddrsig(const ELFFile *Obj) override; void printNotes(const ELFFile *Obj) override; @@ -2287,8 +2290,8 @@ ELFDumperStyle->printHashSymbols(ObjF->getELFFile()); } -template void ELFDumper::printHashHistogram() { - ELFDumperStyle->printHashHistogram(ObjF->getELFFile()); +template void ELFDumper::printHashHistograms() { + ELFDumperStyle->printHashHistograms(ObjF->getELFFile()); } template void ELFDumper::printCGProfile() { @@ -4556,124 +4559,125 @@ OS << '\n'; } -// 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 -void GNUStyle::printHashHistogram(const ELFFile *Obj) { - auto PrintHashHist = [&](const Elf_Hash &HashTable) { - size_t NBucket = HashTable.nbucket; - size_t NChain = HashTable.nchain; - ArrayRef Buckets = HashTable.buckets(); - ArrayRef 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; +void GNUStyle::printHashHistogram(const Elf_Hash &HashTable) { + size_t NBucket = HashTable.nbucket; + size_t NChain = HashTable.nchain; + ArrayRef Buckets = HashTable.buckets(); + ArrayRef 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 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++) { - std::vector Visited(NChain); - for (size_t C = Buckets[B]; C < NChain; C = Chains[C]) { - if (C == ELF::STN_UNDEF) - break; - if (Visited[C]) { - reportWarning( - createError(".hash section is invalid: bucket " + Twine(C) + - ": a cycle was detected in the linked chain"), - this->FileName); - break; - } - Visited[C] = true; - if (MaxChain <= ++ChainLen[B]) - MaxChain++; + std::vector 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++) { + std::vector Visited(NChain); + for (size_t C = Buckets[B]; C < NChain; C = Chains[C]) { + if (C == ELF::STN_UNDEF) + break; + if (Visited[C]) { + reportWarning(createError(".hash section is invalid: bucket " + + Twine(C) + + ": a cycle was detected in the linked chain"), + this->FileName); + break; } - TotalSyms += ChainLen[B]; - } - - if (!TotalSyms) - return; - - std::vector 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); + Visited[C] = true; + if (MaxChain <= ++ChainLen[B]) + MaxChain++; } - }; + TotalSyms += ChainLen[B]; + } - auto PrintGnuHashHist = [&](const Elf_GnuHash &GnuHashTable) { - size_t NBucket = GnuHashTable.nbuckets; - ArrayRef Buckets = GnuHashTable.buckets(); - unsigned NumSyms = this->dumper()->dynamic_symbols().size(); - if (!NumSyms) - return; - ArrayRef Chains = GnuHashTable.values(NumSyms); - size_t Symndx = GnuHashTable.symndx; - size_t TotalSyms = 0; - size_t MaxChain = 1; - size_t CumulativeNonZero = 0; + if (!TotalSyms) + return; - if (Chains.empty() || NBucket == 0) - return; + std::vector 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); + } +} - std::vector ChainLen(NBucket, 0); +template +void GNUStyle::printGnuHashHistogram(const Elf_GnuHash &GnuHashTable) { + size_t NBucket = GnuHashTable.nbuckets; + ArrayRef Buckets = GnuHashTable.buckets(); + unsigned NumSyms = this->dumper()->dynamic_symbols().size(); + if (!NumSyms) + return; + ArrayRef Chains = GnuHashTable.values(NumSyms); + size_t Symndx = GnuHashTable.symndx; + size_t TotalSyms = 0; + size_t MaxChain = 1; + size_t CumulativeNonZero = 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 (Chains.empty() || NBucket == 0) + return; - if (!TotalSyms) - return; + std::vector 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++; - std::vector 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); - } - }; + if (!TotalSyms) + return; + std::vector 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); + } +} + +// Hash histogram shows statistics of how efficient the hash was for the +// dynamic symbol table. The table shows the number of hash buckets for +// different lengths of chains as an absolute number and percentage of the total +// buckets, and the cumulative coverage of symbols for each set of buckets. +template +void GNUStyle::printHashHistograms(const ELFFile *Obj) { // Print histogram for the .hash section. if (const Elf_Hash *HashTable = this->dumper()->getHashTable()) if (checkHashTable(Obj, HashTable, this->FileName)) - PrintHashHist(*HashTable); + printHashHistogram(*HashTable); // Print histogram for the .gnu.hash section. if (const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable()) - PrintGnuHashHist(*GnuHashTable); + printGnuHashHistogram(*GnuHashTable); } template @@ -6417,7 +6421,7 @@ } template -void LLVMStyle::printHashHistogram(const ELFFile *Obj) { +void LLVMStyle::printHashHistograms(const ELFFile *Obj) { W.startLine() << "Hash Histogram not implemented!\n"; } diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -64,7 +64,7 @@ virtual void printLoadName() {} virtual void printVersionInfo() {} virtual void printGroupSections() {} - virtual void printHashHistogram() {} + virtual void printHashHistograms() {} virtual void printCGProfile() {} virtual void printAddrsig() {} virtual void printNotes() {} diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -502,7 +502,7 @@ if (opts::SectionGroups) Dumper->printGroupSections(); if (opts::HashHistogram) - Dumper->printHashHistogram(); + Dumper->printHashHistograms(); if (opts::CGProfile) Dumper->printCGProfile(); if (opts::Addrsig)