llvm.org GIT mirror llvm / 14dddbf
[llvm-readobj] Add ELF hash histogram printing Differential Revision: http://reviews.llvm.org/D18907 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@265967 91177308-0d34-0410-b5e6-96231b3b80d8 Hemant Kulkarni 4 years ago
4 changed file(s) with 156 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 RUN: llvm-readobj -elf-hash-histogram %p/Inputs/gnuhash.so.elf-ppc64 \
1 RUN: --elf-output-style=GNU | FileCheck %s -check-prefix PPC64GNU
2 RUN: llvm-readobj -elf-hash-histogram %p/Inputs/gnuhash.so.elf-x86_64 --elf-output-style=GNU \
3 RUN: | FileCheck %s -check-prefix X86GNU
4 RUN: llvm-readobj -elf-hash-histogram %p/Inputs/got-plt.exe.elf-mipsel --elf-output-style=GNU \
5 RUN: | FileCheck %s -check-prefix SYSV
6
7 PPC64GNU: Histogram for `.gnu.hash' bucket list length (total of 3 buckets)
8 PPC64GNU-NEXT: Length Number % of total Coverage
9 PPC64GNU-NEXT: 0 1 ( 33.3%) 0.0%
10 PPC64GNU-NEXT: 1 1 ( 33.3%) 25.0%
11 PPC64GNU-NEXT: 2 0 ( 0.0%) 25.0%
12 PPC64GNU-NEXT: 3 1 ( 33.3%) 100.0%
13
14 X86GNU: Histogram for `.gnu.hash' bucket list length (total of 3 buckets)
15 X86GNU-NEXT: Length Number % of total Coverage
16 X86GNU-NEXT: 0 1 ( 33.3%) 0.0%
17 X86GNU-NEXT: 1 1 ( 33.3%) 25.0%
18 X86GNU-NEXT: 2 0 ( 0.0%) 25.0%
19 X86GNU-NEXT: 3 1 ( 33.3%) 100.0%
20
21 SYSV: Histogram for bucket list length (total of 3 buckets)
22 SYSV-NEXT: Length Number % of total Coverage
23 SYSV-NEXT: 0 0 ( 0.0%) 0.0%
24 SYSV-NEXT: 1 0 ( 0.0%) 0.0%
25 SYSV-NEXT: 2 2 ( 66.7%) 57.1%
26 SYSV-NEXT: 3 1 ( 33.3%) 100.0%
6060 typedef typename ELFO::Elf_Half Elf_Half; \
6161 typedef typename ELFO::Elf_Ehdr Elf_Ehdr; \
6262 typedef typename ELFO::Elf_Word Elf_Word; \
63 typedef typename ELFO::Elf_Hash Elf_Hash; \
64 typedef typename ELFO::Elf_GnuHash Elf_GnuHash; \
6365 typedef typename ELFO::uintX_t uintX_t;
6466
6567 namespace {
119121 void printMipsReginfo() override;
120122
121123 void printStackMap() const override;
124
125 void printHashHistogram() override;
122126
123127 private:
124128 std::unique_ptr> ELFDumperStyle;
233237 const DynRegionInfo &getDynRelRegion() const { return DynRelRegion; }
234238 const DynRegionInfo &getDynRelaRegion() const { return DynRelaRegion; }
235239 const DynRegionInfo &getDynPLTRelRegion() const { return DynPLTRelRegion; }
240 const Elf_Hash *getHashTable() const { return HashTable; }
241 const Elf_GnuHash *getGnuHashTable() const { return GnuHashTable; }
236242 };
237243
238244 template
283289 const Elf_Sym *FirstSym, StringRef StrTable,
284290 bool IsDynamic) = 0;
285291 virtual void printProgramHeaders(const ELFFile *Obj) = 0;
292 virtual void printHashHistogram(const ELFFile *Obj) = 0;
286293 const ELFDumper *dumper() const { return Dumper; }
287294 private:
288295 const ELFDumper *Dumper;
304311 virtual void printSymtabMessage(const ELFO *Obj, StringRef Name,
305312 size_t Offset) override;
306313 void printProgramHeaders(const ELFO *Obj) override;
314 void printHashHistogram(const ELFFile *Obj) override;
307315
308316 private:
309317 struct Field {
356364 void printDynamicSymbols(const ELFO *Obj) override;
357365 void printDynamicRelocations(const ELFO *Obj) override;
358366 void printProgramHeaders(const ELFO *Obj) override;
367 void printHashHistogram(const ELFFile *Obj) override;
359368
360369 private:
361370 void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab);
13891398 ELFDumperStyle->printDynamicSymbols(Obj);
13901399 }
13911400
1401 template void ELFDumper::printHashHistogram() {
1402 ELFDumperStyle->printHashHistogram(Obj);
1403 }
13921404 #define LLVM_READOBJ_TYPE_CASE(name) \
13931405 case DT_##name: return #name
13941406
29192931 }
29202932 }
29212933
2934 // Hash histogram shows statistics of how efficient the hash was for the
2935 // dynamic symbol table. The table shows number of hash buckets for different
2936 // lengths of chains as absolute number and percentage of the total buckets.
2937 // Additionally cumulative coverage of symbols for each set of buckets.
2938 template
2939 void GNUStyle::printHashHistogram(const ELFFile *Obj) {
2940
2941 const Elf_Hash *HashTable = this->dumper()->getHashTable();
2942 const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable();
2943
2944 // Print histogram for .hash section
2945 if (HashTable) {
2946 size_t NBucket = HashTable->nbucket;
2947 size_t NChain = HashTable->nchain;
2948 ArrayRef Buckets = HashTable->buckets();
2949 ArrayRef Chains = HashTable->chains();
2950 size_t TotalSyms = 0;
2951 // If hash table is correct, we have at least chains with 0 length
2952 size_t MaxChain = 1;
2953 size_t CumulativeNonZero = 0;
2954
2955 if (NChain == 0 || NBucket == 0)
2956 return;
2957
2958 std::vector ChainLen(NBucket, 0);
2959 // Go over all buckets and and note chain lengths of each bucket (total
2960 // unique chain lengths).
2961 for (size_t B = 0; B < NBucket; B++) {
2962 for (size_t C = Buckets[B]; C > 0 && C < NChain; C = Chains[C])
2963 if (MaxChain <= ++ChainLen[B])
2964 MaxChain++;
2965 TotalSyms += ChainLen[B];
2966 }
2967
2968 if (!TotalSyms)
2969 return;
2970
2971 std::vector Count(MaxChain, 0) ;
2972 // Count how long is the chain for each bucket
2973 for (size_t B = 0; B < NBucket; B++)
2974 ++Count[ChainLen[B]];
2975 // Print Number of buckets with each chain lengths and their cumulative
2976 // coverage of the symbols
2977 OS << "Histogram for bucket list length (total of " << NBucket
2978 << " buckets)\n"
2979 << " Length Number % of total Coverage\n";
2980 for (size_t I = 0; I < MaxChain; I++) {
2981 CumulativeNonZero += Count[I] * I;
2982 OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I],
2983 (Count[I] * 100.0) / NBucket,
2984 (CumulativeNonZero * 100.0) / TotalSyms);
2985 }
2986 }
2987
2988 // Print histogram for .gnu.hash section
2989 if (GnuHashTable) {
2990 size_t NBucket = GnuHashTable->nbuckets;
2991 ArrayRef Buckets = GnuHashTable->buckets();
2992 unsigned NumSyms = this->dumper()->dynamic_symbols().size();
2993 if (!NumSyms)
2994 return;
2995 ArrayRef Chains = GnuHashTable->values(NumSyms);
2996 size_t Symndx = GnuHashTable->symndx;
2997 size_t TotalSyms = 0;
2998 size_t MaxChain = 1;
2999 size_t CumulativeNonZero = 0;
3000
3001 if (Chains.size() == 0 || NBucket == 0)
3002 return;
3003
3004 std::vector ChainLen(NBucket, 0);
3005
3006 for (size_t B = 0; B < NBucket; B++) {
3007 if (!Buckets[B])
3008 continue;
3009 size_t Len = 1;
3010 for (size_t C = Buckets[B] - Symndx;
3011 C < Chains.size() && (Chains[C] & 1) == 0; C++)
3012 if (MaxChain < ++Len)
3013 MaxChain++;
3014 ChainLen[B] = Len;
3015 TotalSyms += Len;
3016 }
3017 MaxChain++;
3018
3019 if (!TotalSyms)
3020 return;
3021
3022 std::vector Count(MaxChain, 0) ;
3023 for (size_t B = 0; B < NBucket; B++)
3024 ++Count[ChainLen[B]];
3025 // Print Number of buckets with each chain lengths and their cumulative
3026 // coverage of the symbols
3027 OS << "Histogram for `.gnu.hash' bucket list length (total of " << NBucket
3028 << " buckets)\n"
3029 << " Length Number % of total Coverage\n";
3030 for (size_t I = 0; I
3031 CumulativeNonZero += Count[I] * I;
3032 OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I],
3033 (Count[I] * 100.0) / NBucket,
3034 (CumulativeNonZero * 100.0) / TotalSyms);
3035 }
3036 }
3037 }
3038
29223039 template void LLVMStyle::printFileHeaders(const ELFO *Obj) {
29233040 const Elf_Ehdr *e = Obj->getHeader();
29243041 {
32803397 W.printNumber("Alignment", Phdr.p_align);
32813398 }
32823399 }
3400 template
3401 void LLVMStyle::printHashHistogram(const ELFFile *Obj) {
3402 W.startLine() << "Hash Histogram not implemented!\n";
3403 }
4242 virtual void printLoadName() {}
4343 virtual void printVersionInfo() {}
4444 virtual void printGroupSections() {}
45 virtual void printHashHistogram() {}
4546
4647 // Only implemented for ARM ELF at this time.
4748 virtual void printAttributes() { }
231231 cl::desc("Display ELF section group contents"));
232232 cl::alias SectionGroupsShort("g", cl::desc("Alias for -elf-sections-groups"),
233233 cl::aliasopt(SectionGroups));
234 cl::opt HashHistogram(
235 "elf-hash-histogram",
236 cl::desc("Display bucket list histogram for hash sections"));
237 cl::alias HashHistogramShort("I", cl::desc("Alias for -elf-hash-histogram"),
238 cl::aliasopt(HashHistogram));
234239
235240 cl::opt
236241 Output("elf-output-style", cl::desc("Specify ELF dump style"),
359364 }
360365 if (opts::SectionGroups)
361366 Dumper->printGroupSections();
367 if (opts::HashHistogram)
368 Dumper->printHashHistogram();
362369 }
363370 if (Obj->isCOFF()) {
364371 if (opts::COFFImports)