diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h --- a/llvm/include/llvm/Object/ELFObjectFile.h +++ b/llvm/include/llvm/Object/ELFObjectFile.h @@ -102,6 +102,8 @@ /// Returns a vector containing a symbol version for each dynamic symbol. /// Returns an empty vector if version sections do not exist. Expected> readDynsymVersions() const; + + Expected> readBBAddrMap() const; }; class ELFSectionRef : public SectionRef { diff --git a/llvm/lib/Object/ELFObjectFile.cpp b/llvm/lib/Object/ELFObjectFile.cpp --- a/llvm/lib/Object/ELFObjectFile.cpp +++ b/llvm/lib/Object/ELFObjectFile.cpp @@ -657,6 +657,25 @@ return Result; } +template +static Expected> +readBBAddrMapImpl(const ELFFile &EF) { + using Elf_Shdr = typename ELFT::Shdr; + + for (const Elf_Shdr &Sec : cantFail(EF.sections())) { + if (Sec.sh_type != ELF::SHT_LLVM_BB_ADDR_MAP) + continue; + llvm::Expected> bb_addr_map = + EF.decodeBBAddrMap(Sec); + if (!bb_addr_map) { + return createError("Unable to read the bb-addr-map section " + + describe(EF, Sec)); + } + return *bb_addr_map; + } + return createError("No bb-addr-map section found!"); +} + template static Expected> readDynsymVersionsImpl(const ELFFile &EF, @@ -725,3 +744,16 @@ return readDynsymVersionsImpl(cast(this)->getELFFile(), Symbols); } + +Expected> ELFObjectFileBase::readBBAddrMap() const { + if (const auto *Obj = dyn_cast(this)) + return readBBAddrMapImpl(Obj->getELFFile()); + if (const auto *Obj = dyn_cast(this)) + return readBBAddrMapImpl(Obj->getELFFile()); + if (const auto *Obj = dyn_cast(this)) + return readBBAddrMapImpl(Obj->getELFFile()); + if (auto *Obj = cast(this)) + return readBBAddrMapImpl(Obj->getELFFile()); + else + llvm_unreachable("Unsupported binary format"); +} diff --git a/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml b/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-disassemble-symbolize-operands.yaml @@ -0,0 +1,72 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-objdump %t -d --symbolize-operands -M intel --no-show-raw-insn --no-leading-addr | \ +# RUN: FileCheck %s --match-full-lines --check-prefix=INTEL +# RUN: llvm-objdump %t -d --symbolize-operands -M att --no-show-raw-insn --no-leading-addr | \ +# RUN: FileCheck %s --match-full-lines --check-prefix=ATT + +## Expect to find the branch labels and global variable name. +# ATT: <_start>: +# ATT-NEXT: : +# ATT-NEXT: pushq %rax +# ATT-NEXT: : +# ATT-NEXT: cmpl , %eax +# ATT-NEXT: nop +# ATT-NEXT: : +# ATT-NEXT: jge +# ATT-NEXT: jmp +# ATT-NEXT: : +# ATT-NEXT: retq + +# INTEL: <_start>: +# INTEL-NEXT: : +# INTEL-NEXT: push rax +# INTEL-NEXT: : +# INTEL-NEXT: cmp eax, dword ptr +# INTEL-NEXT: nop +# INTEL-NEXT: : +# INTEL-NEXT: jge +# INTEL-NEXT: jmp +# INTEL-NEXT: : +# INTEL-NEXT: ret + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Address: 0x4000 + Flags: [SHF_ALLOC, SHF_EXECINSTR] + Content: '503b0505100000907d02ebf5c3' + - Name: .data + Type: SHT_PROGBITS + Flags: [SHF_ALLOC, SHF_WRITE] + Address: 0x5000 + - Name: bb_addr_map_1 + Type: SHT_LLVM_BB_ADDR_MAP + Link: .text + Entries: + - Address: 0x4000 + BBEntries: + - AddressOffset: 0x0 + Size: 0x1 + Metadata: 0x1 + - AddressOffset: 0x1 + Size: 0x6 + Metadata: 0x0 + - AddressOffset: 0x8 + Size: 0x3 + Metadata: 0x0 + - AddressOffset: 0xc + Size: 0x1 + Metadata: 0x2 +Symbols: + - Name: _start + Section: .text + Value: 0x4000 + - Name: symbol + Section: .data + Value: 0x500c diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -53,6 +53,7 @@ #include "llvm/Object/COFF.h" #include "llvm/Object/COFFImportFile.h" #include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/ELFTypes.h" #include "llvm/Object/FaultMapParser.h" #include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" @@ -981,6 +982,37 @@ return SymbolInfoTy(Addr, Name, Type); } +static void +readBBAddrMap(const ObjectFile *Obj, + std::unordered_map &AddrToBBAddrMap) { + if (auto *Elf = dyn_cast(Obj)) { + auto ObjBBAddrMapOrErr = Elf->readBBAddrMap(); + if (!ObjBBAddrMapOrErr) { + consumeError(ObjBBAddrMapOrErr.takeError()); + return; + } + for (const BBAddrMap &FunctionBBAddrMap : *ObjBBAddrMapOrErr) + AddrToBBAddrMap[FunctionBBAddrMap.Addr] = std::move(FunctionBBAddrMap); + } +} + +static void collectBBAddrMapLabels( + const std::unordered_map &AddrToBBAddrMap, + uint64_t SectionAddr, uint64_t Start, uint64_t End, + std::unordered_map> &Labels) { + uint64_t StartAddress = SectionAddr + Start; + uint64_t EndAddress = SectionAddr + End; + auto Iter = AddrToBBAddrMap.find(StartAddress); + if (Iter == AddrToBBAddrMap.end()) + return; + for (unsigned i = 0; i < Iter->second.BBEntries.size(); ++i) { + uint64_t BBAddress = Iter->second.BBEntries[i].Offset + Iter->second.Addr; + if (BBAddress >= EndAddress) + continue; + Labels[BBAddress].push_back(("BB#" + Twine(i)).str()); + } +} + static void collectLocalBranchTargets(ArrayRef Bytes, const MCInstrAnalysis *MIA, MCDisassembler *DisAsm, MCInstPrinter *IP, @@ -1297,6 +1329,10 @@ if (shouldAdjustVA(Section)) VMAAdjustment = AdjustVMA; + std::unordered_map AddrToBBAddrMap; + if (SymbolizeOperands) + readBBAddrMap(Obj, AddrToBBAddrMap); + // In executable and shared objects, r_offset holds a virtual address. // Subtract SectionAddr from the r_offset field of a relocation to get // the section offset. @@ -1413,9 +1449,13 @@ formatted_raw_ostream FOS(outs()); std::unordered_map AllLabels; - if (SymbolizeOperands) + std::unordered_map> BBAddrMapLabels; + if (SymbolizeOperands) { collectLocalBranchTargets(Bytes, MIA, DisAsm, IP, PrimarySTI, SectionAddr, Index, End, AllLabels); + collectBBAddrMapLabels(AddrToBBAddrMap, SectionAddr, Index, End, + BBAddrMapLabels); + } while (Index < End) { // ARM and AArch64 ELF binaries can interleave data and text in the @@ -1459,9 +1499,15 @@ } // Print local label if there's any. - auto Iter = AllLabels.find(SectionAddr + Index); - if (Iter != AllLabels.end()) - FOS << "<" << Iter->second << ">:\n"; + auto Iter1 = BBAddrMapLabels.find(SectionAddr + Index); + if (Iter1 != BBAddrMapLabels.end()) { + for (const std::string &Label : Iter1->second) + FOS << "<" << Label << ">:\n"; + } else { + auto Iter2 = AllLabels.find(SectionAddr + Index); + if (Iter2 != AllLabels.end()) + FOS << "<" << Iter2->second << ">:\n"; + } // Disassemble a real instruction or a data when disassemble all is // provided @@ -1556,6 +1602,7 @@ } // Print the labels corresponding to the target if there's any. + bool BBAddrMapLabelAvailable = BBAddrMapLabels.count(Target); bool LabelAvailable = AllLabels.count(Target); if (TargetSym != nullptr) { uint64_t TargetAddress = TargetSym->Addr; @@ -1569,14 +1616,18 @@ // Always Print the binary symbol precisely corresponding to // the target address. *TargetOS << TargetName; - } else if (!LabelAvailable) { + } else if (BBAddrMapLabelAvailable) { + *TargetOS << BBAddrMapLabels[Target].front(); + } else if (LabelAvailable) { + *TargetOS << AllLabels[Target]; + } else { // Always Print the binary symbol plus an offset if there's no // local label corresponding to the target address. *TargetOS << TargetName << "+0x" << Twine::utohexstr(Disp); - } else { - *TargetOS << AllLabels[Target]; } *TargetOS << ">"; + } else if (BBAddrMapLabelAvailable) { + *TargetOS << " <" << BBAddrMapLabels[Target].front() << ">"; } else if (LabelAvailable) { *TargetOS << " <" << AllLabels[Target] << ">"; }