diff --git a/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test --- a/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test +++ b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test @@ -17,6 +17,7 @@ # LLVM: BBAddrMap [ # LLVM-NEXT: Function { # LLVM-NEXT: At: [[ADDR]] +# LLVM-NEXT: Name: ? # LLVM-NEXT: BB entries [ # LLVM-NEXT: { # LLVM-NEXT: Offset: 0x0 @@ -38,6 +39,7 @@ # LLVM-NEXT: } # LLVM-NEXT: Function { # LLVM-NEXT: At: 0x22222 +# LLVM-NEXT: Name: foo # LLVM-NEXT: BB entries [ # LLVM-NEXT: { # LLVM-NEXT: Offset: 0x6 @@ -53,6 +55,7 @@ # LLVM-NEXT: BBAddrMap [ # LLVM-NEXT: Function { # LLVM-NEXT: At: 0x33333 +# LLVM-NEXT: Name: bar # LLVM-NEXT: BB entries [ # LLVM-NEXT: { # LLVM-NEXT: Offset: 0x9 @@ -69,14 +72,15 @@ # GNU: GNUStyle::printBBAddrMaps not implemented # TRUNCATED: BBAddrMap [ -# TRUNCATED-NEXT: warning: '[[FILE]]': unable to dump SHT_LLVM_BB_ADDR_MAP section with index 1: unable to decode LEB128 at offset [[OFFSET]]: malformed uleb128, extends past end +# TRUNCATED-NEXT: warning: '[[FILE]]': unable to dump SHT_LLVM_BB_ADDR_MAP section with index 3: unable to decode LEB128 at offset [[OFFSET]]: malformed uleb128, extends past end # TRUNCATED-NEXT: ] ## Check that the other valid section is properly dumped. # TRUNCATED-NEXT: BBAddrMap [ # TRUNCATED-NEXT: Function { -# TRUNCATED-NEXT: At: 0x33333 -# TRUNCATED-NEXT: BB entries [ -# TRUNCATED-NEXT: { +# TRUNCATED-NEXT: At: 0x33333 +# TRUNCATED-NEXT: Name: bar +# TRUNCATED-NEXT: BB entries [ +# TRUNCATED-NEXT: { # TRUNCATED-NEXT: Offset: 0x9 # TRUNCATED-NEXT: Size: 0xA # TRUNCATED-NEXT: HasReturn: Yes @@ -94,9 +98,16 @@ Data: ELFDATA2LSB Type: ET_EXEC Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [SHF_ALLOC] + - Name: .text.bar + Type: SHT_PROGBITS + Flags: [SHF_ALLOC] - Name: bb_addr_map_1 Type: SHT_LLVM_BB_ADDR_MAP ShSize: [[SIZE=]] + Link: .text Entries: - Address: [[ADDR=0x11111]] BBEntries: @@ -116,9 +127,19 @@ Size: 16 - Name: bb_addr_map_2 Type: SHT_LLVM_BB_ADDR_MAP + Link: .text.bar Entries: - Address: 0x33333 BBEntries: - AddressOffset: 0x9 Size: 0xa Metadata: 0xb +Symbols: + - Name: foo + Section: .text + Type: STT_FUNC + Value: 0x22222 + - Name: bar + Section: .text.bar + Type: STT_FUNC + Value: 0x33333 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 @@ -298,6 +298,13 @@ std::vector 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 + getSymbolIndexForFunctionAddress(uint64_t SymValue, + Optional FunctionSec); bool printFunctionStackSize(uint64_t SymValue, Optional FunctionSec, const Elf_Shdr &StackSizeSec, DataExtractor Data, @@ -348,6 +355,7 @@ const Elf_Hash *HashTable = nullptr; const Elf_GnuHash *GnuHashTable = nullptr; const Elf_Shdr *DotSymtabSec = nullptr; + Optional>> SymbolValueToIndexMap; const Elf_Shdr *DotDynsymSec = nullptr; const Elf_Shdr *DotCGProfileSec = nullptr; const Elf_Shdr *DotAddrsigSec = nullptr; @@ -5701,64 +5709,83 @@ } template -bool ELFDumper::printFunctionStackSize( - uint64_t SymValue, Optional FunctionSec, - const Elf_Shdr &StackSizeSec, DataExtractor Data, uint64_t *Offset) { - uint32_t FuncSymIndex = 0; - if (this->DotSymtabSec) { - if (Expected SymsOrError = 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) - continue; - - if (Expected SymAddrOrErr = - ObjF.toSymbolRef(this->DotSymtabSec, Index).getAddress()) { - if (SymValue != *SymAddrOrErr) - 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 - // means "any section". - if (FunctionSec) { - if (Expected SecOrErr = - Obj.getSection(Sym, this->DotSymtabSec, - this->getShndxTable(this->DotSymtabSec))) { - if (*FunctionSec != *SecOrErr) - continue; - } else { +Optional ELFDumper::getSymbolIndexForFunctionAddress( + uint64_t SymValue, Optional FunctionSec) { + if (!this->SymbolValueToIndexMap.hasValue()) { + // Populate the address to index map upon the first invocation of this + // function. + this->SymbolValueToIndexMap.emplace(); + if (this->DotSymtabSec) { + if (Expected SymsOrError = + Obj.symbols(this->DotSymtabSec)) { + uint32_t Index = (uint32_t)-1; + for (const Elf_Sym &Sym : *SymsOrError) { + (void)Sym; + ++Index; + + Expected SymAddrOrErr = + ObjF.toSymbolRef(this->DotSymtabSec, Index).getAddress(); + if (!SymAddrOrErr) { 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())); - break; + reportUniqueWarning("unable to get address of symbol '" + Name + + "': " + toString(SymAddrOrErr.takeError())); + return None; } + + (*this->SymbolValueToIndexMap)[*SymAddrOrErr].push_back(Index); } + } else { + reportUniqueWarning("unable to read the symbol table: " + + toString(SymsOrError.takeError())); + } + } + } - FuncSymIndex = Index; - break; + auto Symbols = this->SymbolValueToIndexMap->find(SymValue); + if (Symbols == this->SymbolValueToIndexMap->end()) + return None; + for (auto Index : Symbols->second) { + + const Elf_Sym &Sym = *cantFail(Obj.getSymbol(this->DotSymtabSec, Index)); + if (Sym.st_shndx == ELF::SHN_UNDEF || Sym.getType() != ELF::STT_FUNC) + continue; + + // Check if the symbol is in the right section. FunctionSec == None + // means "any section". + if (FunctionSec) { + if (Expected 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; } - } else { - reportUniqueWarning("unable to read the symbol table: " + - toString(SymsOrError.takeError())); } + + return Index; } + return None; +} +template +bool ELFDumper::printFunctionStackSize( + uint64_t SymValue, Optional FunctionSec, + const Elf_Shdr &StackSizeSec, DataExtractor Data, uint64_t *Offset) { + Optional FuncSymIndex = + this->getSymbolIndexForFunctionAddress(SymValue, FunctionSec); std::string FuncName = "?"; if (!FuncSymIndex) reportUniqueWarning( "could not identify function symbol for stack size entry in " + describe(StackSizeSec)); else - FuncName = this->getStaticSymbolName(FuncSymIndex); + FuncName = this->getStaticSymbolName(*FuncSymIndex); // Extract the size. The expectation is that Offset is pointing to the right // place, i.e. past the function address. @@ -6694,9 +6721,14 @@ } template void LLVMELFDumper::printBBAddrMaps() { + bool IsRelocatable = this->Obj.getHeader().e_type == ELF::ET_REL; for (const Elf_Shdr &Sec : cantFail(this->Obj.sections())) { if (Sec.sh_type != SHT_LLVM_BB_ADDR_MAP) continue; + Optional FunctionSec = None; + if (IsRelocatable) + FunctionSec = + unwrapOrError(this->FileName, this->Obj.getSection(Sec.sh_link)); ListScope L(W, "BBAddrMap"); Expected> BBAddrMapOrErr = this->Obj.decodeBBAddrMap(Sec); @@ -6708,6 +6740,17 @@ for (const Elf_BBAddrMap &AM : *BBAddrMapOrErr) { DictScope D(W, "Function"); W.printHex("At", AM.Addr); + Optional FuncSymIndex = + this->getSymbolIndexForFunctionAddress(AM.Addr, FunctionSec); + std::string FuncName = "?"; + if (FuncSymIndex == None) + this->reportUniqueWarning( + "could not identify function symbol for address (0x" + + Twine::utohexstr(AM.Addr) + ") in " + this->describe(Sec)); + else + FuncName = this->getStaticSymbolName(*FuncSymIndex); + W.printString("Name", FuncName); + ListScope L(W, "BB entries"); for (const typename Elf_BBAddrMap::BBEntry &BBE : AM.BBEntries) { DictScope L(W);