Please use GitHub pull requests for new patches. Avoid migrating existing patches. Phabricator shutdown timeline
Changeset View
Standalone View
llvm/tools/llvm-readobj/ELFDumper.cpp
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
Show First 20 Lines • Show All 216 Lines • ▼ Show 20 Lines | public: | ||||||||||
void printHashTable() override; | void printHashTable() override; | ||||||||||
void printGnuHashTable() override; | void printGnuHashTable() override; | ||||||||||
void printLoadName() override; | void printLoadName() override; | ||||||||||
void printVersionInfo() override; | void printVersionInfo() override; | ||||||||||
void printArchSpecificInfo() override; | void printArchSpecificInfo() override; | ||||||||||
void printStackMap() const override; | void printStackMap() const override; | ||||||||||
void printMemtag() override; | void printMemtag() override; | ||||||||||
// 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. | |||||||||||
void printHashHistograms() override; | |||||||||||
const object::ELFObjectFile<ELFT> &getElfObject() const { return ObjF; }; | const object::ELFObjectFile<ELFT> &getElfObject() const { return ObjF; }; | ||||||||||
std::string describe(const Elf_Shdr &Sec) const; | std::string describe(const Elf_Shdr &Sec) const; | ||||||||||
unsigned getHashTableEntSize() const { | unsigned getHashTableEntSize() const { | ||||||||||
// EM_S390 and ELF::EM_ALPHA platforms use 8-bytes entries in SHT_HASH | // EM_S390 and ELF::EM_ALPHA platforms use 8-bytes entries in SHT_HASH | ||||||||||
// sections. This violates the ELF specification. | // sections. This violates the ELF specification. | ||||||||||
if (Obj.getHeader().e_machine == ELF::EM_S390 || | if (Obj.getHeader().e_machine == ELF::EM_S390 || | ||||||||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | protected: | ||||||||||
virtual void printMipsABIFlags() = 0; | virtual void printMipsABIFlags() = 0; | ||||||||||
virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0; | virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0; | ||||||||||
virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0; | virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0; | ||||||||||
virtual void printMemtag( | virtual void printMemtag( | ||||||||||
const ArrayRef<std::pair<std::string, std::string>> DynamicEntries, | const ArrayRef<std::pair<std::string, std::string>> DynamicEntries, | ||||||||||
const ArrayRef<uint8_t> AndroidNoteDesc) = 0; | const ArrayRef<uint8_t> AndroidNoteDesc) = 0; | ||||||||||
virtual void printHashHistogram(const Elf_Hash &HashTable) const; | |||||||||||
virtual void printGnuHashHistogram(const Elf_GnuHash &GnuHashTable) const; | |||||||||||
virtual void printHashHistogramStats(size_t NBucket, size_t MaxChain, | |||||||||||
size_t TotalSyms, ArrayRef<size_t> Count, | |||||||||||
bool IsGnu) const = 0; | |||||||||||
Expected<ArrayRef<Elf_Versym>> | Expected<ArrayRef<Elf_Versym>> | ||||||||||
getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab, | getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab, | ||||||||||
StringRef *StrTab, const Elf_Shdr **SymTabSec) const; | StringRef *StrTab, const Elf_Shdr **SymTabSec) const; | ||||||||||
StringRef getPrintableSectionName(const Elf_Shdr &Sec) const; | StringRef getPrintableSectionName(const Elf_Shdr &Sec) const; | ||||||||||
std::vector<GroupSection> getGroups(); | std::vector<GroupSection> getGroups(); | ||||||||||
// Returns the function symbol index for the given address. Matches the | // Returns the function symbol index for the given address. Matches the | ||||||||||
▲ Show 20 Lines • Show All 258 Lines • ▼ Show 20 Lines | public: | ||||||||||
void printDynamicRelocations() override; | void printDynamicRelocations() override; | ||||||||||
void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset, | void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset, | ||||||||||
bool NonVisibilityBitsUsed) const override; | bool NonVisibilityBitsUsed) const override; | ||||||||||
void printProgramHeaders(bool PrintProgramHeaders, | void printProgramHeaders(bool PrintProgramHeaders, | ||||||||||
cl::boolOrDefault PrintSectionMapping) override; | cl::boolOrDefault PrintSectionMapping) override; | ||||||||||
void printVersionSymbolSection(const Elf_Shdr *Sec) override; | void printVersionSymbolSection(const Elf_Shdr *Sec) override; | ||||||||||
void printVersionDefinitionSection(const Elf_Shdr *Sec) override; | void printVersionDefinitionSection(const Elf_Shdr *Sec) override; | ||||||||||
void printVersionDependencySection(const Elf_Shdr *Sec) override; | void printVersionDependencySection(const Elf_Shdr *Sec) override; | ||||||||||
void printHashHistograms() override; | |||||||||||
void printCGProfile() override; | void printCGProfile() override; | ||||||||||
void printBBAddrMaps() override; | void printBBAddrMaps() override; | ||||||||||
void printAddrsig() override; | void printAddrsig() override; | ||||||||||
void printNotes() override; | void printNotes() override; | ||||||||||
void printELFLinkerOptions() override; | void printELFLinkerOptions() override; | ||||||||||
void printStackSizes() override; | void printStackSizes() override; | ||||||||||
void printMemtag( | void printMemtag( | ||||||||||
const ArrayRef<std::pair<std::string, std::string>> DynamicEntries, | const ArrayRef<std::pair<std::string, std::string>> DynamicEntries, | ||||||||||
const ArrayRef<uint8_t> AndroidNoteDesc) override; | const ArrayRef<uint8_t> AndroidNoteDesc) override; | ||||||||||
void printHashHistogramStats(size_t NBucket, size_t MaxChain, | |||||||||||
size_t TotalSyms, ArrayRef<size_t> Count, | |||||||||||
bool IsGnu) const override; | |||||||||||
private: | private: | ||||||||||
void printHashHistogram(const Elf_Hash &HashTable); | |||||||||||
void printGnuHashHistogram(const Elf_GnuHash &GnuHashTable); | |||||||||||
void printHashTableSymbols(const Elf_Hash &HashTable); | void printHashTableSymbols(const Elf_Hash &HashTable); | ||||||||||
void printGnuHashTableSymbols(const Elf_GnuHash &GnuHashTable); | void printGnuHashTableSymbols(const Elf_GnuHash &GnuHashTable); | ||||||||||
struct Field { | struct Field { | ||||||||||
std::string Str; | std::string Str; | ||||||||||
unsigned Column; | unsigned Column; | ||||||||||
Field(StringRef S, unsigned Col) : Str(std::string(S)), Column(Col) {} | Field(StringRef S, unsigned Col) : Str(std::string(S)), Column(Col) {} | ||||||||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | public: | ||||||||||
void printDependentLibs() override; | void printDependentLibs() override; | ||||||||||
void printDynamicTable() override; | void printDynamicTable() override; | ||||||||||
void printDynamicRelocations() override; | void printDynamicRelocations() override; | ||||||||||
void printProgramHeaders(bool PrintProgramHeaders, | void printProgramHeaders(bool PrintProgramHeaders, | ||||||||||
cl::boolOrDefault PrintSectionMapping) override; | cl::boolOrDefault PrintSectionMapping) override; | ||||||||||
void printVersionSymbolSection(const Elf_Shdr *Sec) override; | void printVersionSymbolSection(const Elf_Shdr *Sec) override; | ||||||||||
void printVersionDefinitionSection(const Elf_Shdr *Sec) override; | void printVersionDefinitionSection(const Elf_Shdr *Sec) override; | ||||||||||
void printVersionDependencySection(const Elf_Shdr *Sec) override; | void printVersionDependencySection(const Elf_Shdr *Sec) override; | ||||||||||
void printHashHistograms() override; | |||||||||||
void printCGProfile() override; | void printCGProfile() override; | ||||||||||
void printBBAddrMaps() override; | void printBBAddrMaps() override; | ||||||||||
void printAddrsig() override; | void printAddrsig() override; | ||||||||||
void printNotes() override; | void printNotes() override; | ||||||||||
void printELFLinkerOptions() override; | void printELFLinkerOptions() override; | ||||||||||
void printStackSizes() override; | void printStackSizes() override; | ||||||||||
void printMemtag( | void printMemtag( | ||||||||||
const ArrayRef<std::pair<std::string, std::string>> DynamicEntries, | const ArrayRef<std::pair<std::string, std::string>> DynamicEntries, | ||||||||||
const ArrayRef<uint8_t> AndroidNoteDesc) override; | const ArrayRef<uint8_t> AndroidNoteDesc) override; | ||||||||||
void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex, | void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex, | ||||||||||
DataRegion<Elf_Word> ShndxTable) const; | DataRegion<Elf_Word> ShndxTable) const; | ||||||||||
void printHashHistogramStats(size_t NBucket, size_t MaxChain, | |||||||||||
size_t TotalSyms, ArrayRef<size_t> Count, | |||||||||||
bool IsGnu) const override; | |||||||||||
private: | private: | ||||||||||
void printRelrReloc(const Elf_Relr &R) override; | void printRelrReloc(const Elf_Relr &R) override; | ||||||||||
void printRelRelaReloc(const Relocation<ELFT> &R, | void printRelRelaReloc(const Relocation<ELFT> &R, | ||||||||||
const RelSymbol<ELFT> &RelSym) override; | const RelSymbol<ELFT> &RelSym) override; | ||||||||||
void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, | void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, | ||||||||||
DataRegion<Elf_Word> ShndxTable, | DataRegion<Elf_Word> ShndxTable, | ||||||||||
▲ Show 20 Lines • Show All 1,978 Lines • ▼ Show 20 Lines | reportUniqueWarning("unable to dump 'Values' for the SHT_GNU_HASH " | ||||||||||
"section: " + | "section: " + | ||||||||||
toString(Chains.takeError())); | toString(Chains.takeError())); | ||||||||||
return; | return; | ||||||||||
} | } | ||||||||||
W.printHexList("Values", *Chains); | W.printHexList("Values", *Chains); | ||||||||||
} | } | ||||||||||
template <typename ELFT> void ELFDumper<ELFT>::printHashHistograms() { | |||||||||||
// Print histogram for the .hash section. | |||||||||||
if (this->HashTable) { | |||||||||||
if (Error E = checkHashTable<ELFT>(*this, this->HashTable)) | |||||||||||
this->reportUniqueWarning(std::move(E)); | |||||||||||
else | |||||||||||
printHashHistogram(*this->HashTable); | |||||||||||
} | |||||||||||
// Print histogram for the .gnu.hash section. | |||||||||||
if (this->GnuHashTable) { | |||||||||||
if (Error E = checkGNUHashTable<ELFT>(this->Obj, this->GnuHashTable)) | |||||||||||
this->reportUniqueWarning(std::move(E)); | |||||||||||
else | |||||||||||
printGnuHashHistogram(*this->GnuHashTable); | |||||||||||
} | |||||||||||
} | |||||||||||
template <typename ELFT> | |||||||||||
void ELFDumper<ELFT>::printHashHistogram(const Elf_Hash &HashTable) const { | |||||||||||
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. | |||||||||||
jhenderson: Whilst moving, please add the missing "." to this comment. | |||||||||||
size_t MaxChain = 1; | |||||||||||
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) { | |||||||||||
BitVector Visited(NChain); | |||||||||||
for (size_t C = Buckets[B]; C < NChain; C = Chains[C]) { | |||||||||||
if (C == ELF::STN_UNDEF) | |||||||||||
break; | |||||||||||
if (Visited[C]) { | |||||||||||
this->reportUniqueWarning( | |||||||||||
".hash section is invalid: bucket " + Twine(C) + | |||||||||||
": a cycle was detected in the linked chain"); | |||||||||||
break; | |||||||||||
} | |||||||||||
Visited[C] = true; | |||||||||||
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. | |||||||||||
Ditto. jhenderson: Ditto. | |||||||||||
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. | |||||||||||
Ditto. jhenderson: Ditto. | |||||||||||
printHashHistogramStats(NBucket, MaxChain, TotalSyms, Count, /*IsGnu*/ false); | |||||||||||
jhendersonUnsubmitted
jhenderson: | |||||||||||
} | |||||||||||
template <class ELFT> | |||||||||||
void ELFDumper<ELFT>::printGnuHashHistogram( | |||||||||||
const Elf_GnuHash &GnuHashTable) const { | |||||||||||
Expected<ArrayRef<Elf_Word>> ChainsOrErr = | |||||||||||
getGnuHashTableChains<ELFT>(this->DynSymRegion, &GnuHashTable); | |||||||||||
if (!ChainsOrErr) { | |||||||||||
this->reportUniqueWarning("unable to print the GNU hash table histogram: " + | |||||||||||
toString(ChainsOrErr.takeError())); | |||||||||||
return; | |||||||||||
} | |||||||||||
ArrayRef<Elf_Word> Chains = *ChainsOrErr; | |||||||||||
size_t Symndx = GnuHashTable.symndx; | |||||||||||
size_t TotalSyms = 0; | |||||||||||
size_t MaxChain = 1; | |||||||||||
size_t NBucket = GnuHashTable.nbuckets; | |||||||||||
if (Chains.empty() || NBucket == 0) | |||||||||||
return; | |||||||||||
ArrayRef<Elf_Word> Buckets = GnuHashTable.buckets(); | |||||||||||
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. | |||||||||||
Ditto. jhenderson: Ditto. | |||||||||||
printHashHistogramStats(NBucket, MaxChain, TotalSyms, Count, /*IsGnu*/ true); | |||||||||||
} | |||||||||||
template <typename ELFT> void ELFDumper<ELFT>::printLoadName() { | template <typename ELFT> void ELFDumper<ELFT>::printLoadName() { | ||||||||||
StringRef SOName = "<Not found>"; | StringRef SOName = "<Not found>"; | ||||||||||
if (SONameOffset) | if (SONameOffset) | ||||||||||
SOName = getDynamicString(*SONameOffset); | SOName = getDynamicString(*SONameOffset); | ||||||||||
W.printString("LoadName", SOName); | W.printString("LoadName", SOName); | ||||||||||
} | } | ||||||||||
template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() { | template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() { | ||||||||||
▲ Show 20 Lines • Show All 2,133 Lines • ▼ Show 20 Lines | for (const VernAux &Aux : VN.AuxV) | ||||||||||
OS << format(" 0x%04x: Name: %s Flags: %s Version: %u\n", Aux.Offset, | OS << format(" 0x%04x: Name: %s Flags: %s Version: %u\n", Aux.Offset, | ||||||||||
Aux.Name.data(), versionFlagToString(Aux.Flags).c_str(), | Aux.Name.data(), versionFlagToString(Aux.Flags).c_str(), | ||||||||||
Aux.Other); | Aux.Other); | ||||||||||
} | } | ||||||||||
OS << '\n'; | OS << '\n'; | ||||||||||
} | } | ||||||||||
template <class ELFT> | template <class ELFT> | ||||||||||
void GNUELFDumper<ELFT>::printHashHistogram(const Elf_Hash &HashTable) { | void GNUELFDumper<ELFT>::printHashHistogramStats(size_t NBucket, | ||||||||||
size_t NBucket = HashTable.nbucket; | size_t MaxChain, | ||||||||||
size_t NChain = HashTable.nchain; | size_t TotalSyms, | ||||||||||
ArrayRef<Elf_Word> Buckets = HashTable.buckets(); | ArrayRef<size_t> Count, | ||||||||||
ArrayRef<Elf_Word> Chains = HashTable.chains(); | bool IsGnu) const { | ||||||||||
jhendersonUnsubmitted I have a marginal preference to make this argument StringRef TableDescription (with values of "" and `.gnu.hash' respectively, since there's only one place the behaviour is different between the two output styles, as far as I can tell. jhenderson: I have a marginal preference to make this argument `StringRef TableDescription` (with values of… | |||||||||||
paulkirthAuthorUnsubmitted Sure, but if they have the same interface, then they can be overrides from the base class, as they are now. paulkirth: Sure, but if they have the same interface, then they can be overrides from the base class, as… | |||||||||||
jhendersonUnsubmitted Okay, that's fair. jhenderson: Okay, that's fair. | |||||||||||
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++) { | |||||||||||
BitVector Visited(NChain); | |||||||||||
for (size_t C = Buckets[B]; C < NChain; C = Chains[C]) { | |||||||||||
if (C == ELF::STN_UNDEF) | |||||||||||
break; | |||||||||||
if (Visited[C]) { | |||||||||||
this->reportUniqueWarning(".hash section is invalid: bucket " + | |||||||||||
Twine(C) + | |||||||||||
": a cycle was detected in the linked chain"); | |||||||||||
break; | |||||||||||
} | |||||||||||
Visited[C] = true; | |||||||||||
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); | |||||||||||
} | |||||||||||
} | |||||||||||
template <class ELFT> | |||||||||||
void GNUELFDumper<ELFT>::printGnuHashHistogram( | |||||||||||
const Elf_GnuHash &GnuHashTable) { | |||||||||||
Expected<ArrayRef<Elf_Word>> ChainsOrErr = | |||||||||||
getGnuHashTableChains<ELFT>(this->DynSymRegion, &GnuHashTable); | |||||||||||
if (!ChainsOrErr) { | |||||||||||
this->reportUniqueWarning("unable to print the GNU hash table histogram: " + | |||||||||||
toString(ChainsOrErr.takeError())); | |||||||||||
return; | |||||||||||
} | |||||||||||
ArrayRef<Elf_Word> Chains = *ChainsOrErr; | |||||||||||
size_t Symndx = GnuHashTable.symndx; | |||||||||||
size_t TotalSyms = 0; | |||||||||||
size_t MaxChain = 1; | |||||||||||
size_t CumulativeNonZero = 0; | size_t CumulativeNonZero = 0; | ||||||||||
OS << "Histogram for" << (IsGnu ? " `.gnu.hash'" : "") | |||||||||||
size_t NBucket = GnuHashTable.nbuckets; | << " bucket list length (total of " << NBucket << " buckets)\n" | ||||||||||
if (Chains.empty() || NBucket == 0) | |||||||||||
return; | |||||||||||
ArrayRef<Elf_Word> Buckets = GnuHashTable.buckets(); | |||||||||||
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"; | << " 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; | CumulativeNonZero += Count[I] * I; | ||||||||||
OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I], | OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I], | ||||||||||
(Count[I] * 100.0) / NBucket, | (Count[I] * 100.0) / NBucket, | ||||||||||
(CumulativeNonZero * 100.0) / TotalSyms); | (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 <class ELFT> void GNUELFDumper<ELFT>::printHashHistograms() { | |||||||||||
// Print histogram for the .hash section. | |||||||||||
if (this->HashTable) { | |||||||||||
if (Error E = checkHashTable<ELFT>(*this, this->HashTable)) | |||||||||||
this->reportUniqueWarning(std::move(E)); | |||||||||||
else | |||||||||||
printHashHistogram(*this->HashTable); | |||||||||||
} | |||||||||||
// Print histogram for the .gnu.hash section. | |||||||||||
if (this->GnuHashTable) { | |||||||||||
if (Error E = checkGNUHashTable<ELFT>(this->Obj, this->GnuHashTable)) | |||||||||||
this->reportUniqueWarning(std::move(E)); | |||||||||||
else | |||||||||||
printGnuHashHistogram(*this->GnuHashTable); | |||||||||||
} | |||||||||||
} | |||||||||||
template <class ELFT> void GNUELFDumper<ELFT>::printCGProfile() { | template <class ELFT> void GNUELFDumper<ELFT>::printCGProfile() { | ||||||||||
OS << "GNUStyle::printCGProfile not implemented\n"; | OS << "GNUStyle::printCGProfile not implemented\n"; | ||||||||||
} | } | ||||||||||
template <class ELFT> void GNUELFDumper<ELFT>::printBBAddrMaps() { | template <class ELFT> void GNUELFDumper<ELFT>::printBBAddrMaps() { | ||||||||||
OS << "GNUStyle::printBBAddrMaps not implemented\n"; | OS << "GNUStyle::printBBAddrMaps not implemented\n"; | ||||||||||
} | } | ||||||||||
▲ Show 20 Lines • Show All 2,193 Lines • ▼ Show 20 Lines | for (const VernAux &Aux : VN.AuxV) { | ||||||||||
W.printNumber("Hash", Aux.Hash); | W.printNumber("Hash", Aux.Hash); | ||||||||||
W.printFlags("Flags", Aux.Flags, ArrayRef(SymVersionFlags)); | W.printFlags("Flags", Aux.Flags, ArrayRef(SymVersionFlags)); | ||||||||||
W.printNumber("Index", Aux.Other); | W.printNumber("Index", Aux.Other); | ||||||||||
W.printString("Name", Aux.Name.c_str()); | W.printString("Name", Aux.Name.c_str()); | ||||||||||
} | } | ||||||||||
} | } | ||||||||||
} | } | ||||||||||
template <class ELFT> void LLVMELFDumper<ELFT>::printHashHistograms() { | template <class ELFT> | ||||||||||
W.startLine() << "Hash Histogram not implemented!\n"; | void LLVMELFDumper<ELFT>::printHashHistogramStats(size_t NBucket, | ||||||||||
size_t MaxChain, | |||||||||||
size_t TotalSyms, | |||||||||||
Any particular reason you've made the Count member const in these two methods? jhenderson: Any particular reason you've made the `Count` member `const` in these two methods? | |||||||||||
Thanks for pointing that out. I think it was just habit from writing const Foo& forever, but that doesn't make sense in this case. paulkirth: Thanks for pointing that out. I think it was just habit from writing `const Foo&` forever, but… | |||||||||||
ArrayRef<size_t> Count, | |||||||||||
Looking at this again, this and the GNU hash histogram version immediately below are practically identical. Can you try sharing the code rather than duplicating it, please? Whilst you're at it, you might want to do the same for the GNU output format versions of these two functions. jhenderson: Looking at this again, this and the GNU hash histogram version immediately below are… | |||||||||||
bool IsGnu) const { | |||||||||||
StringRef HistName = IsGnu ? "GnuHashHistogram" : "HashHistogram"; | |||||||||||
StringRef BucketName = IsGnu ? "Bucket" : "Chain"; | |||||||||||
StringRef ListName = IsGnu ? "Buckets" : "Chains"; | |||||||||||
jhenderson: | |||||||||||
DictScope Outer(W, HistName); | |||||||||||
W.printNumber("TotalBuckets", NBucket); | |||||||||||
ListScope Buckets(W, ListName); | |||||||||||
size_t CumulativeNonZero = 0; | |||||||||||
for (size_t I = 0; I < MaxChain; ++I) { | |||||||||||
CumulativeNonZero += Count[I] * I; | |||||||||||
DictScope Bucket(W, BucketName); | |||||||||||
W.printNumber("Length", I); | |||||||||||
W.printNumber("Count", Count[I]); | |||||||||||
W.printNumber("Percentage", (float)(Count[I] * 100.0) / NBucket); | |||||||||||
W.printNumber("Coverage", (float)(CumulativeNonZero * 100.0) / TotalSyms); | |||||||||||
} | |||||||||||
} | } | ||||||||||
// Returns true if rel/rela section exists, and populates SymbolIndices. | // Returns true if rel/rela section exists, and populates SymbolIndices. | ||||||||||
// Otherwise returns false. | // Otherwise returns false. | ||||||||||
template <class ELFT> | template <class ELFT> | ||||||||||
static bool getSymbolIndices(const typename ELFT::Shdr *CGRelSection, | static bool getSymbolIndices(const typename ELFT::Shdr *CGRelSection, | ||||||||||
jhenderson: https://llvm.org/docs/CodingStandards.html#prefer-preincrement | |||||||||||
This loop is taken directly from the GNUELFDumper, should I update this in the existing implementations too? paulkirth: This loop is taken directly from the `GNUELFDumper`, should I update this in the existing… | |||||||||||
I wouldn't change code that isn't already changing/moving, but if it is, you can make the tidy-up at the same time. jhenderson: I wouldn't change code that isn't already changing/moving, but if it is, you can make the tidy… | |||||||||||
const ELFFile<ELFT> &Obj, | const ELFFile<ELFT> &Obj, | ||||||||||
const LLVMELFDumper<ELFT> *Dumper, | const LLVMELFDumper<ELFT> *Dumper, | ||||||||||
SmallVector<uint32_t, 128> &SymbolIndices) { | SmallVector<uint32_t, 128> &SymbolIndices) { | ||||||||||
if (!CGRelSection) { | if (!CGRelSection) { | ||||||||||
Dumper->reportUniqueWarning( | Dumper->reportUniqueWarning( | ||||||||||
"relocation section for a call graph section doesn't exist"); | "relocation section for a call graph section doesn't exist"); | ||||||||||
return false; | return false; | ||||||||||
} | } | ||||||||||
▲ Show 20 Lines • Show All 586 Lines • Show Last 20 Lines |
Whilst moving, please add the missing "." to this comment.