diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h --- a/llvm/include/llvm/Object/ELF.h +++ b/llvm/include/llvm/Object/ELF.h @@ -277,6 +277,9 @@ Expected> android_relas(const Elf_Shdr &Sec) const; + Expected> + decode_bbaddrmap(const Elf_Shdr &Sec) const; + /// Iterate over program header table. Expected program_headers() const { if (getHeader().e_phnum && getHeader().e_phentsize != sizeof(Elf_Phdr)) diff --git a/llvm/include/llvm/Object/ELFTypes.h b/llvm/include/llvm/Object/ELFTypes.h --- a/llvm/include/llvm/Object/ELFTypes.h +++ b/llvm/include/llvm/Object/ELFTypes.h @@ -43,6 +43,7 @@ template class Elf_Note_Impl; template class Elf_Note_Iterator_Impl; template struct Elf_CGProfile_Impl; +template struct Elf_BBAddrMap_Impl; template struct ELFType { private: @@ -74,6 +75,7 @@ using Note = Elf_Note_Impl>; using NoteIterator = Elf_Note_Iterator_Impl>; using CGProfile = Elf_CGProfile_Impl>; + using BBAddrMap = Elf_BBAddrMap_Impl>; using DynRange = ArrayRef; using ShdrRange = ArrayRef; using SymRange = ArrayRef; @@ -128,13 +130,14 @@ using Elf_Note = typename ELFT::Note; \ using Elf_Note_Iterator = typename ELFT::NoteIterator; \ using Elf_CGProfile = typename ELFT::CGProfile; \ + using Elf_BBAddrMap = typename ELFT::BBAddrMap; \ using Elf_Dyn_Range = typename ELFT::DynRange; \ using Elf_Shdr_Range = typename ELFT::ShdrRange; \ using Elf_Sym_Range = typename ELFT::SymRange; \ using Elf_Rel_Range = typename ELFT::RelRange; \ using Elf_Rela_Range = typename ELFT::RelaRange; \ using Elf_Relr_Range = typename ELFT::RelrRange; \ - using Elf_Phdr_Range = typename ELFT::PhdrRange; \ + using Elf_Phdr_Range = typename ELFT::PhdrRange; #define LLVM_ELF_COMMA , #define LLVM_ELF_IMPORT_TYPES(E, W) \ @@ -788,6 +791,19 @@ Elf_Word flags2; // General flags }; +// Struct representing the BBAddrMap for one function. +template struct Elf_BBAddrMap_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + uintX_t addr; // Function address + // Struct representing the BBAddrMap information for one basic block. + struct BBEntry { + uint32_t offset; // Offset of basic block relative to function begin + uint32_t size; // Size of the basic block + uint32_t metadata; // Metadata for this basic block. + }; + std::vector bb_entries; // Basic block entries for this function +}; + } // end namespace object. } // end namespace llvm. diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -364,6 +364,32 @@ return Relocs; } +template +Expected> +ELFFile::decode_bbaddrmap(const Elf_Shdr &Sec) const { + Expected> ContentsOrErr = getSectionContents(Sec); + if (!ContentsOrErr) + return ContentsOrErr.takeError(); + ArrayRef Content = *ContentsOrErr; + DataExtractor Data(Content, isLE(), ELFT::Is64Bits ? 8 : 4); + std::vector FunctionEntries; + DataExtractor::Cursor Cur(0); + while (Cur && Cur.tell() < Content.size()) { + uintX_t Address = static_cast(Data.getAddress(Cur)); + uint32_t NumBlocks = Data.getULEB128(Cur); + std::vector BBEntries; + for (uint32_t BlockID = 0; Cur && BlockID < NumBlocks; ++BlockID) { + uint32_t Offset = Data.getULEB128(Cur); + uint32_t Size = Data.getULEB128(Cur); + uint32_t Metadata = Data.getULEB128(Cur); + BBEntries.push_back({Offset, Size, Metadata}); + } + FunctionEntries.push_back({Address, BBEntries}); + } + if (!Cur) + return std::move(Cur.takeError()); + return FunctionEntries; +} template Expected> diff --git a/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map.test @@ -0,0 +1,71 @@ +## This test checks how we handle the --elf-bb-addr-map option. + +# RUN: yaml2obj --docnum=1 %s -o %t1.o +# RUN: llvm-readobj %t1.o --bb-addr-map | FileCheck %s --check-prefix=LLVM +# RUN: llvm-readelf %t1.o --bb-addr-map | FileCheck %s --check-prefix=GNU +# RUN: llvm-readobj %t1.o --elf-bb-addr-map | FileCheck %s --check-prefix=LLVM +# RUN: llvm-readelf %t1.o --elf-bb-addr-map | FileCheck %s --check-prefix=GNU + +# LLVM: BBAddrMap [ +# LLVM-NEXT: Function { +# LLVM-NEXT: At: 0x11111 +# LLVM-NEXT: BB entries [ +# LLVM-NEXT: { +# LLVM-NEXT: Offset: 0x0 +# LLVM-NEXT: Size: 0x1 +# LLVM-NEXT: Metadata: 2 +# LLVM-NEXT: } +# LLVM-NEXT: { +# LLVM-NEXT: Offset: 0x3 +# LLVM-NEXT: Size: 0x4 +# LLVM-NEXT: Metadata: 5 +# LLVM-NEXT: } +# LLVM-NEXT: ] +# LLVM-NEXT: } +# LLVM-NEXT: Function { +# LLVM-NEXT: At: 0x22222 +# LLVM-NEXT: BB entries [ +# LLVM-NEXT: { +# LLVM-NEXT: Offset: 0x6 +# LLVM-NEXT: Size: 0x7 +# LLVM-NEXT: Metadata: 8 +# LLVM-NEXT: } +# LLVM-NEXT: ] +# LLVM-NEXT: } +# LLVM-NEXT: ] +# GNU: GNUStyle::printBBAddrMap not implemented +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +Sections: + - Name: .llvm_bb_addr_map + Type: SHT_LLVM_BB_ADDR_MAP + Entries: + - Address: 0x11111 + BBEntries: + - AddressOffset: 0x0 + Size: 0x1 + Metadata: 0x2 + - AddressOffset: 0x3 + Size: 0x4 + Metadata: 0x5 + - Address: 0x22222 + BBEntries: + - AddressOffset: 0x6 + Size: 0x7 + Metadata: 0x8 + +# RUN: yaml2obj --docnum=2 %s -o %t2.o +# RUN: llvm-readobj %t2.o --bb-addr-map 2>&1 | FileCheck %s -DFILE=%t2.o --check-prefix=INVALID +# INVALID: warning: '[[FILE]]': unable to dump the SHT_LLVM_BB_ADDR_MAP section: unable to decode LEB128 at offset 0x{{([[:xdigit:]]{8})}}: malformed uleb128, extends past end +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC +Sections: + - Name: .llvm_bb_addr_map + Type: SHT_LLVM_BB_ADDR_MAP + Size: 8 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 @@ -350,6 +350,7 @@ const Elf_Shdr *DotSymtabSec = nullptr; const Elf_Shdr *DotDynsymSec = nullptr; const Elf_Shdr *DotCGProfileSec = nullptr; + const Elf_Shdr *DotBBAddrMapSec = nullptr; const Elf_Shdr *DotAddrsigSec = nullptr; DenseMap> ShndxTables; Optional SONameOffset; @@ -550,6 +551,7 @@ void printVersionDependencySection(const Elf_Shdr *Sec) override; void printHashHistograms() override; void printCGProfile() override; + void printBBAddrMap() override; void printAddrsig() override; void printNotes() override; void printELFLinkerOptions() override; @@ -660,6 +662,7 @@ void printVersionDependencySection(const Elf_Shdr *Sec) override; void printHashHistograms() override; void printCGProfile() override; + void printBBAddrMap() override; void printAddrsig() override; void printNotes() override; void printELFLinkerOptions() override; @@ -1747,6 +1750,10 @@ if (!DotCGProfileSec) DotCGProfileSec = &Sec; break; + case ELF::SHT_LLVM_BB_ADDR_MAP: + if (!DotBBAddrMapSec) + DotBBAddrMapSec = &Sec; + break; case ELF::SHT_LLVM_ADDRSIG: if (!DotAddrsigSec) DotAddrsigSec = &Sec; @@ -4623,6 +4630,10 @@ OS << "GNUStyle::printCGProfile not implemented\n"; } +template void GNUELFDumper::printBBAddrMap() { + OS << "GNUStyle::printBBAddrMap not implemented\n"; +} + static Expected> toULEB128Array(ArrayRef Data) { std::vector Ret; const uint8_t *Cur = Data.begin(); @@ -6432,6 +6443,33 @@ } } +template void LLVMELFDumper::printBBAddrMap() { + ListScope L(W, "BBAddrMap"); + if (!this->DotBBAddrMapSec) + return; + + Expected> BBAddrMapOrErr = + this->Obj.decode_bbaddrmap(*this->DotBBAddrMapSec); + if (!BBAddrMapOrErr) { + this->reportUniqueWarning( + "unable to dump the SHT_LLVM_BB_ADDR_MAP section: " + + toString(BBAddrMapOrErr.takeError())); + return; + } + + for (const Elf_BBAddrMap &AM : *BBAddrMapOrErr) { + DictScope D(W, "Function"); + W.printHex("At", AM.addr); + ListScope L(W, "BB entries"); + for (const typename Elf_BBAddrMap::BBEntry &BBE : AM.bb_entries) { + DictScope L(W); + W.printHex("Offset", BBE.offset); + W.printHex("Size", BBE.size); + W.printNumber("Metadata", BBE.metadata); + } + } +} + template void LLVMELFDumper::printAddrsig() { ListScope L(W, "Addrsig"); if (!this->DotAddrsigSec) 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 @@ -72,6 +72,7 @@ virtual void printGroupSections() {} virtual void printHashHistograms() {} virtual void printCGProfile() {} + virtual void printBBAddrMap() {} virtual void printAddrsig() {} virtual void printNotes() {} virtual void printELFLinkerOptions() {} 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 @@ -367,6 +367,12 @@ cl::alias ELFCGProfile("elf-cg-profile", cl::desc("Alias for --cg-profile"), cl::aliasopt(CGProfile)); + // --bb-addr-map + cl::opt BBAddrMap("bb-addr-map", + cl::desc("Display the BB address map section")); + cl::alias ELFBBAddrMap("elf-bb-addr-map", cl::desc("Alias for --bb-addr-map"), + cl::aliasopt(BBAddrMap)); + // -addrsig cl::opt Addrsig("addrsig", cl::desc("Display address-significance table")); @@ -542,6 +548,8 @@ Dumper->printHashHistograms(); if (opts::CGProfile) Dumper->printCGProfile(); + if (opts::BBAddrMap) + Dumper->printBBAddrMap(); if (opts::Addrsig) Dumper->printAddrsig(); if (opts::Notes)