forked from OSchip/llvm-project
[llvm-readobj] Optimize printing stack sizes to linear time.
Currently, each function name lookup is a linear iteration over all symbols defined in the object file which makes the total running time quadratic. This patch optimizes the function name lookup by populating an **address to index** map upon the first function name lookup which is used to lookup each function name in O(1). **impact**: For the clang binary built with `-fstack-size-section`, this improves the running time of `llvm-readobj --stack-size` from 7 minutes to 0.25 seconds. Reviewed By: jhenderson Differential Revision: https://reviews.llvm.org/D103072
This commit is contained in:
parent
fdf10e6197
commit
6505c63040
|
@ -298,6 +298,13 @@ protected:
|
||||||
|
|
||||||
std::vector<GroupSection> getGroups();
|
std::vector<GroupSection> getGroups();
|
||||||
|
|
||||||
|
// Returns the function symbol index for the given address. Matches the
|
||||||
|
// symbol's section with FunctionSec when specified.
|
||||||
|
// Returns None if no function symbol can be found for the address or in case
|
||||||
|
// it is not defined in the specified section.
|
||||||
|
Optional<uint32_t>
|
||||||
|
getSymbolIndexForFunctionAddress(uint64_t SymValue,
|
||||||
|
Optional<const Elf_Shdr *> FunctionSec);
|
||||||
bool printFunctionStackSize(uint64_t SymValue,
|
bool printFunctionStackSize(uint64_t SymValue,
|
||||||
Optional<const Elf_Shdr *> FunctionSec,
|
Optional<const Elf_Shdr *> FunctionSec,
|
||||||
const Elf_Shdr &StackSizeSec, DataExtractor Data,
|
const Elf_Shdr &StackSizeSec, DataExtractor Data,
|
||||||
|
@ -353,6 +360,7 @@ protected:
|
||||||
const Elf_Shdr *DotAddrsigSec = nullptr;
|
const Elf_Shdr *DotAddrsigSec = nullptr;
|
||||||
DenseMap<const Elf_Shdr *, ArrayRef<Elf_Word>> ShndxTables;
|
DenseMap<const Elf_Shdr *, ArrayRef<Elf_Word>> ShndxTables;
|
||||||
Optional<uint64_t> SONameOffset;
|
Optional<uint64_t> SONameOffset;
|
||||||
|
Optional<DenseMap<uint64_t, std::vector<uint32_t>>> AddressToIndexMap;
|
||||||
|
|
||||||
const Elf_Shdr *SymbolVersionSection = nullptr; // .gnu.version
|
const Elf_Shdr *SymbolVersionSection = nullptr; // .gnu.version
|
||||||
const Elf_Shdr *SymbolVersionNeedSection = nullptr; // .gnu.version_r
|
const Elf_Shdr *SymbolVersionNeedSection = nullptr; // .gnu.version_r
|
||||||
|
@ -5703,64 +5711,82 @@ template <class ELFT> void GNUELFDumper<ELFT>::printDependentLibs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
bool ELFDumper<ELFT>::printFunctionStackSize(
|
Optional<uint32_t> ELFDumper<ELFT>::getSymbolIndexForFunctionAddress(
|
||||||
uint64_t SymValue, Optional<const Elf_Shdr *> FunctionSec,
|
uint64_t SymValue, Optional<const Elf_Shdr *> FunctionSec) {
|
||||||
const Elf_Shdr &StackSizeSec, DataExtractor Data, uint64_t *Offset) {
|
if (!this->AddressToIndexMap.hasValue()) {
|
||||||
uint32_t FuncSymIndex = 0;
|
// Populate the address to index map upon the first invocation of this
|
||||||
if (this->DotSymtabSec) {
|
// function.
|
||||||
if (Expected<Elf_Sym_Range> SymsOrError = Obj.symbols(this->DotSymtabSec)) {
|
this->AddressToIndexMap.emplace();
|
||||||
uint32_t Index = (uint32_t)-1;
|
if (this->DotSymtabSec) {
|
||||||
for (const Elf_Sym &Sym : *SymsOrError) {
|
if (Expected<Elf_Sym_Range> SymsOrError =
|
||||||
++Index;
|
Obj.symbols(this->DotSymtabSec)) {
|
||||||
|
uint32_t Index = (uint32_t)-1;
|
||||||
|
for (const Elf_Sym &Sym : *SymsOrError) {
|
||||||
|
++Index;
|
||||||
|
|
||||||
if (Sym.st_shndx == ELF::SHN_UNDEF || Sym.getType() != ELF::STT_FUNC)
|
if (Sym.st_shndx == ELF::SHN_UNDEF || Sym.getType() != ELF::STT_FUNC)
|
||||||
continue;
|
|
||||||
|
|
||||||
if (Expected<uint64_t> SymAddrOrErr =
|
|
||||||
ObjF.toSymbolRef(this->DotSymtabSec, Index).getAddress()) {
|
|
||||||
if (SymValue != *SymAddrOrErr)
|
|
||||||
continue;
|
continue;
|
||||||
} else {
|
|
||||||
std::string Name = this->getStaticSymbolName(Index);
|
|
||||||
reportUniqueWarning("unable to get address of symbol '" + Name +
|
|
||||||
"': " + toString(SymAddrOrErr.takeError()));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the symbol is in the right section. FunctionSec == None
|
Expected<uint64_t> SymAddrOrErr =
|
||||||
// means "any section".
|
ObjF.toSymbolRef(this->DotSymtabSec, Index).getAddress();
|
||||||
if (FunctionSec) {
|
if (!SymAddrOrErr) {
|
||||||
if (Expected<const Elf_Shdr *> SecOrErr =
|
|
||||||
Obj.getSection(Sym, this->DotSymtabSec,
|
|
||||||
this->getShndxTable(this->DotSymtabSec))) {
|
|
||||||
if (*FunctionSec != *SecOrErr)
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
std::string Name = this->getStaticSymbolName(Index);
|
std::string Name = this->getStaticSymbolName(Index);
|
||||||
// Note: it is impossible to trigger this error currently, it is
|
reportUniqueWarning("unable to get address of symbol '" + Name +
|
||||||
// untested.
|
"': " + toString(SymAddrOrErr.takeError()));
|
||||||
reportUniqueWarning("unable to get section of symbol '" + Name +
|
return None;
|
||||||
"': " + toString(SecOrErr.takeError()));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
FuncSymIndex = Index;
|
(*this->AddressToIndexMap)[*SymAddrOrErr].push_back(Index);
|
||||||
break;
|
}
|
||||||
|
} else {
|
||||||
|
reportUniqueWarning("unable to read the symbol table: " +
|
||||||
|
toString(SymsOrError.takeError()));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
reportUniqueWarning("unable to read the symbol table: " +
|
|
||||||
toString(SymsOrError.takeError()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Symbols = this->AddressToIndexMap->find(SymValue);
|
||||||
|
if (Symbols == this->AddressToIndexMap->end())
|
||||||
|
return None;
|
||||||
|
|
||||||
|
for (uint32_t Index : Symbols->second) {
|
||||||
|
// Check if the symbol is in the right section. FunctionSec == None
|
||||||
|
// means "any section".
|
||||||
|
if (FunctionSec) {
|
||||||
|
const Elf_Sym &Sym = *cantFail(Obj.getSymbol(this->DotSymtabSec, Index));
|
||||||
|
if (Expected<const Elf_Shdr *> SecOrErr =
|
||||||
|
Obj.getSection(Sym, this->DotSymtabSec,
|
||||||
|
this->getShndxTable(this->DotSymtabSec))) {
|
||||||
|
if (*FunctionSec != *SecOrErr)
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
std::string Name = this->getStaticSymbolName(Index);
|
||||||
|
// Note: it is impossible to trigger this error currently, it is
|
||||||
|
// untested.
|
||||||
|
reportUniqueWarning("unable to get section of symbol '" + Name +
|
||||||
|
"': " + toString(SecOrErr.takeError()));
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Index;
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ELFT>
|
||||||
|
bool ELFDumper<ELFT>::printFunctionStackSize(
|
||||||
|
uint64_t SymValue, Optional<const Elf_Shdr *> FunctionSec,
|
||||||
|
const Elf_Shdr &StackSizeSec, DataExtractor Data, uint64_t *Offset) {
|
||||||
|
Optional<uint32_t> FuncSymIndex =
|
||||||
|
this->getSymbolIndexForFunctionAddress(SymValue, FunctionSec);
|
||||||
std::string FuncName = "?";
|
std::string FuncName = "?";
|
||||||
if (!FuncSymIndex)
|
if (!FuncSymIndex)
|
||||||
reportUniqueWarning(
|
reportUniqueWarning(
|
||||||
"could not identify function symbol for stack size entry in " +
|
"could not identify function symbol for stack size entry in " +
|
||||||
describe(StackSizeSec));
|
describe(StackSizeSec));
|
||||||
else
|
else
|
||||||
FuncName = this->getStaticSymbolName(FuncSymIndex);
|
FuncName = this->getStaticSymbolName(*FuncSymIndex);
|
||||||
|
|
||||||
// Extract the size. The expectation is that Offset is pointing to the right
|
// Extract the size. The expectation is that Offset is pointing to the right
|
||||||
// place, i.e. past the function address.
|
// place, i.e. past the function address.
|
||||||
|
|
Loading…
Reference in New Issue