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 @@ -392,7 +392,9 @@ Expected> getSectionContentsAsArray(const Elf_Shdr &Sec) const; Expected> getSectionContents(const Elf_Shdr &Sec) const; Expected> getSegmentContents(const Elf_Phdr &Phdr) const; - Expected> decodeBBAddrMap(const Elf_Shdr &Sec) const; + Expected> + decodeBBAddrMap(const Elf_Shdr &Sec, + const std::optional &RelaSec = {}) const; Error getSectionAndRelocations( std::function(const Elf_Shdr &)> IsMatch, llvm::MapVector &SecToRelocMap) const; 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 @@ -639,8 +639,19 @@ } template -Expected> -ELFFile::decodeBBAddrMap(const Elf_Shdr &Sec) const { +Expected> ELFFile::decodeBBAddrMap( + const Elf_Shdr &Sec, const std::optional &RelaSec) const { + bool IsRelocatable = getHeader().e_type == ELF::ET_REL; + assert(!IsRelocatable || (IsRelocatable && RelaSec)); + llvm::DenseMap BBAddrMapTranslations; + if(IsRelocatable && RelaSec) { + Expected Relas = this->relas(*RelaSec); + if(!Relas) + return Relas.takeError(); + for (Elf_Rela Rela: *Relas) { + BBAddrMapTranslations[Rela.r_offset] = Rela.r_addend; + } + } Expected> ContentsOrErr = getSectionContents(Sec); if (!ContentsOrErr) return ContentsOrErr.takeError(); @@ -680,7 +691,12 @@ Twine(static_cast(Version))); Data.getU8(Cur); // Feature byte } + uint64_t SectionOffset = Cur.tell(); uintX_t Address = static_cast(Data.getAddress(Cur)); + if(IsRelocatable) { + assert(Address == 0); + Address = BBAddrMapTranslations[SectionOffset]; + } uint32_t NumBlocks = ReadULEB128AsUInt32(); std::vector BBEntries; uint32_t PrevBBEndOffset = 0; 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 @@ -681,24 +681,36 @@ Expected> static readBBAddrMapImpl( const ELFFile &EF, std::optional TextSectionIndex) { using Elf_Shdr = typename ELFT::Shdr; + bool IsRelocatable = EF.getHeader().e_type == ELF::ET_REL; std::vector BBAddrMaps; + llvm::MapVector SectionRelocMap; + const auto &Sections = cantFail(EF.sections()); - for (const Elf_Shdr &Sec : Sections) { + auto IsMatch = [&](const Elf_Shdr &Sec) -> Expected { if (Sec.sh_type != ELF::SHT_LLVM_BB_ADDR_MAP && Sec.sh_type != ELF::SHT_LLVM_BB_ADDR_MAP_V0) - continue; - if (TextSectionIndex) { + return false; + if(TextSectionIndex) { Expected TextSecOrErr = EF.getSection(Sec.sh_link); if (!TextSecOrErr) - return createError("unable to get the linked-to section for " + - describe(EF, Sec) + ": " + - toString(TextSecOrErr.takeError())); + return TextSecOrErr.takeError(); if (*TextSectionIndex != std::distance(Sections.begin(), *TextSecOrErr)) - continue; + return false; } - Expected> BBAddrMapOrErr = EF.decodeBBAddrMap(Sec); + return true; + }; + + Error PossibleSecRelocError = EF.getSectionAndRelocations(IsMatch, SectionRelocMap); + if(PossibleSecRelocError) + return std::move(PossibleSecRelocError); + + for (auto const& [Sec, RelocSec] : SectionRelocMap) { + std::optional RelaSec = {}; + if(IsRelocatable) + RelaSec = *RelocSec; + Expected> BBAddrMapOrErr = EF.decodeBBAddrMap(*Sec, RelaSec); if (!BBAddrMapOrErr) - return createError("unable to read " + describe(EF, Sec) + ": " + + return createError("unable to read " + describe(EF, *Sec) + ": " + toString(BBAddrMapOrErr.takeError())); std::move(BBAddrMapOrErr->begin(), BBAddrMapOrErr->end(), std::back_inserter(BBAddrMaps)); 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 --- 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 @@ -5,19 +5,12 @@ # UNSUPPORTED: system-windows ## Executable object file. -# RUN: yaml2obj --docnum=1 -DTYPE=ET_EXEC -DFOO_ADDR=0x4000 -DBAR_ADDR=0x5000 %s -o %t1 +# RUN: yaml2obj --docnum=1 -DFOO_ADDR=0x4000 -DBAR_ADDR=0x5000 %s -o %t1 # RUN: llvm-objdump %t1 -d --symbolize-operands -M intel --no-show-raw-insn --no-leading-addr | \ # RUN: FileCheck %s -DSYM=symbol --match-full-lines --check-prefixes=INTEL # RUN: llvm-objdump %t1 -d --symbolize-operands -M att --no-show-raw-insn --no-leading-addr | \ # RUN: FileCheck %s -DSYM=symbol --match-full-lines --check-prefixes=ATT -## Relocatable object file. -# RUN: yaml2obj --docnum=1 -DTYPE=ET_REL -DFOO_ADDR=0x0 -DBAR_ADDR=0x0 %s -o %t2 -# RUN: llvm-objdump %t2 -d --symbolize-operands -M intel --no-show-raw-insn --no-leading-addr | \ -# RUN: FileCheck %s -DSYM=foo+0x200c --match-full-lines --check-prefix=INTEL -# RUN: llvm-objdump %t2 -d --symbolize-operands -M att --no-show-raw-insn --no-leading-addr | \ -# RUN: FileCheck %s -DSYM=foo+0x200c --match-full-lines --check-prefix=ATT - ## Executable object file with a single SHT_LLVM_BB_ADDR_MAP for multiple text sections. # RUN: yaml2obj --docnum=2 %s -o %t3 # RUN: llvm-objdump %t3 -d --symbolize-operands -M intel --no-show-raw-insn --no-leading-addr | \ @@ -78,7 +71,7 @@ FileHeader: Class: ELFCLASS64 Data: ELFDATA2LSB - Type: [[TYPE]] + Type: ET_EXEC Machine: EM_X86_64 Sections: - Name: .text.foo diff --git a/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-symbolize-relocatable.yaml b/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-symbolize-relocatable.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-symbolize-relocatable.yaml @@ -0,0 +1,137 @@ +## Test that in the presence of SHT_LLVM_BB_ADDR_MAP sections, +## --symbolize-operands can display labels properly in a relocatable +## object file. + +# Fails on windows (https://github.com/llvm/llvm-project/issues/60013). +# UNSUPPORTED: system-windows + +## Relocatable Object file. +# RUN: yaml2obj %s -o %t1 +# RUN: llvm-objdump %t1 -d --symbolize-operands -M intel --no-show-raw-insn --no-leading-addr | \ +# RUN: FileCheck %s -DSYM=symbol --match-full-lines --check-prefixes=INTEL +# RUN: llvm-objdump %t1 -d --symbolize-operands -M att --no-show-raw-insn --no-leading-addr | \ +# RUN: FileCheck %s -DSYM=symbol --match-full-lines --check-prefixes=ATT + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 + SectionHeaderStringTable: .strtab +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Content: 554889E5897DFC8B45FCC1E0015DC390554889E5897DF8837DF8050F8E0E0000008B45F883E8058945FCE9060000008B45F88945FC8B45FC5DC3 + - Name: .llvm_bb_addr_map + Type: SHT_LLVM_BB_ADDR_MAP + Link: .text + Entries: + - Version: 2 + BBEntries: + - ID: 0 + AddressOffset: 0x0 + Size: 0xF + Metadata: 0x1 + - Version: 2 + BBEntries: + - ID: 0 + AddressOffset: 0x0 + Size: 0x11 + Metadata: 0x8 + - ID: 1 + AddressOffset: 0x0 + Size: 0xE + Metadata: 0x0 + - ID: 2 + AddressOffset: 0x0 + Size: 0x6 + Metadata: 0x8 + - ID: 3 + AddressOffset: 0x0 + Size: 0x5 + Metadata: 0x1 + - Name: .rela.llvm_bb_addr_map + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + Info: .llvm_bb_addr_map + Relocations: + - Offset: 0x2 + Symbol: .text + Type: R_X86_64_64 + - Offset: 0x11 + Symbol: .text + Type: R_X86_64_64 + Addend: 16 +Symbols: + - Name: a + Section: .text + Value: 0x0 + - Name: c + Section: .text + Value: 0x10 + - Name: .text + Type: STT_SECTION + Section: .text + +# ATT: : +# ATT-NEXT: : +# ATT-NEXT: pushq %rbp +# ATT-NEXT: movq %rsp, %rbp +# ATT-NEXT: movl %edi, -0x4(%rbp) +# ATT-NEXT: movl -0x4(%rbp), %eax +# ATT-NEXT: shll $0x1, %eax +# ATT-NEXT: popq %rbp +# ATT-NEXT: retq +# ATT-NEXT: nop +# ATT: : +# ATT-NEXT: : +# ATT-NEXT: pushq %rbp +# ATT-NEXT: movq %rsp, %rbp +# ATT-NEXT: movl %edi, -0x8(%rbp) +# ATT-NEXT: cmpl $0x5, -0x8(%rbp) +# ATT-NEXT: jle +# ATT-NEXT: : +# ATT-NEXT: movl -0x8(%rbp), %eax +# ATT-NEXT: subl $0x5, %eax +# ATT-NEXT: movl %eax, -0x4(%rbp) +# ATT-NEXT: jmp +# ATT-NEXT: : +# ATT-NEXT: movl -0x8(%rbp), %eax +# ATT-NEXT: movl %eax, -0x4(%rbp) +# ATT-NEXT: : +# ATT-NEXT: movl -0x4(%rbp), %eax +# ATT-NEXT: popq %rbp +# ATT-NEXT: retq + +# INTEL: : +# INTEL-NEXT: : +# INTEL-NEXT: push rbp +# INTEL-NEXT: mov rbp, rsp +# INTEL-NEXT: mov dword ptr [rbp - 0x4], edi +# INTEL-NEXT: mov eax, dword ptr [rbp - 0x4] +# INTEL-NEXT: shl eax, 0x1 +# INTEL-NEXT: pop rbp +# INTEL-NEXT: ret +# INTEL-NEXT: nop +# INTEL: : +# INTEL-NEXT: : +# INTEL-NEXT: push rbp +# INTEL-NEXT: mov rbp, rsp +# INTEL-NEXT: mov dword ptr [rbp - 0x8], edi +# INTEL-NEXT: cmp dword ptr [rbp - 0x8], 0x5 +# INTEL-NEXT: jle +# INTEL-NEXT: : +# INTEL-NEXT: mov eax, dword ptr [rbp - 0x8] +# INTEL-NEXT: sub eax, 0x5 +# INTEL-NEXT: mov dword ptr [rbp - 0x4], eax +# INTEL-NEXT: jmp +# INTEL-NEXT: : +# INTEL-NEXT: mov eax, dword ptr [rbp - 0x8] +# INTEL-NEXT: mov dword ptr [rbp - 0x4], eax +# INTEL-NEXT: : +# INTEL-NEXT: mov eax, dword ptr [rbp - 0x4] +# INTEL-NEXT: pop rbp +# INTEL-NEXT: ret diff --git a/llvm/test/tools/llvm-readobj/ELF/bb-addr-map-relocatable.test b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map-relocatable.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map-relocatable.test @@ -0,0 +1,131 @@ +## This test checks how we handle the --bb-addr-map option on relocatable +## object files. + +## Fails on windows (https://github.com/llvm/llvm-project/issues/60013). +## UNSUPPORTED: system-windows + +# RUN: yaml2obj %s -o %t1.o +# RUN: llvm-readobj %t1.o --bb-addr-map | FileCheck %s + +# CHECK: BBAddrMap [ +# CHECK-NEXT: Function { +# CHECK-NEXT: At: 0x0 +# CHECK-NEXT: Name: +# CHECK-NEXT: BB entries [ +# CHECK-NEXT: { +# CHECK-NEXT: ID: 0 +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: Size: 0xF +# CHECK-NEXT: HasReturn: Yes +# CHECK-NEXT: HasTailCall: No +# CHECK-NEXT: IsEHPad: No +# CHECK-NEXT: CanFallThrough: No +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: Function { +# CHECK-NEXT: At: 0x10 +# CHECK-NEXT: Name: +# CHECK-NEXT: BB entries [ +# CHECK-NEXT: { +# CHECK-NEXT: ID: 0 +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: Size: 0x11 +# CHECK-NEXT: HasReturn: No +# CHECK-NEXT: HasTailCall: No +# CHECK-NEXT: IsEHPad: No +# CHECK-NEXT: CanFallThrough: Yes +# CHECK-NEXT: } +# CHECK-NEXT: { +# CHECK-NEXT: ID: 1 +# CHECK-NEXT: Offset: 0x11 +# CHECK-NEXT: Size: 0xE +# CHECK-NEXT: HasReturn: No +# CHECK-NEXT: HasTailCall: No +# CHECK-NEXT: IsEHPad: No +# CHECK-NEXT: CanFallThrough: No +# CHECK-NEXT: } +# CHECK-NEXT: { +# CHECK-NEXT: ID: 2 +# CHECK-NEXT: Offset: 0x1F +# CHECK-NEXT: Size: 0x6 +# CHECK-NEXT: HasReturn: No +# CHECK-NEXT: HasTailCall: No +# CHECK-NEXT: IsEHPad: No +# CHECK-NEXT: CanFallThrough: Yes +# CHECK-NEXT: } +# CHECK-NEXT: { +# CHECK-NEXT: ID: 3 +# CHECK-NEXT: Offset: 0x25 +# CHECK-NEXT: Size: 0x5 +# CHECK-NEXT: HasReturn: Yes +# CHECK-NEXT: HasTailCall: No +# CHECK-NEXT: IsEHPad: No +# CHECK-NEXT: CanFallThrough: No +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } +# CHECK-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 + SectionHeaderStringTable: .strtab +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + - Name: .llvm_bb_addr_map + Type: SHT_LLVM_BB_ADDR_MAP + Link: .text + Entries: + - Version: 2 + BBEntries: + - ID: 0 + AddressOffset: 0x0 + Size: 0xF + Metadata: 0x1 + - Version: 2 + BBEntries: + - ID: 0 + AddressOffset: 0x0 + Size: 0x11 + Metadata: 0x8 + - ID: 1 + AddressOffset: 0x0 + Size: 0xE + Metadata: 0x0 + - ID: 2 + AddressOffset: 0x0 + Size: 0x6 + Metadata: 0x8 + - ID: 3 + AddressOffset: 0x0 + Size: 0x5 + Metadata: 0x1 + - Name: .rela.llvm_bb_addr_map + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Link: .symtab + Info: .llvm_bb_addr_map + Relocations: + - Offset: 0x2 + Symbol: .text + Type: R_X86_64_64 + - Offset: 0x11 + Symbol: .text + Type: R_X86_64_64 + Addend: 16 +Symbols: + - Name: a + Section: .text + Value: 0x0 + - Name: c + Section: .text + Value: 0x10 + - Name: .text + Type: STT_SECTION + Section: .text 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 @@ -7093,20 +7093,26 @@ 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 && - Sec.sh_type != SHT_LLVM_BB_ADDR_MAP_V0) { - continue; - } + using Elf_Shdr = typename ELFT::Shdr; + auto IsMatch = [&](const Elf_Shdr &Sec) -> bool { + return Sec.sh_type == ELF::SHT_LLVM_BB_ADDR_MAP || + Sec.sh_type == ELF::SHT_LLVM_BB_ADDR_MAP_V0; + }; + llvm::MapVector Sections; + this->getSectionAndRelocations(IsMatch, Sections); + for (auto const& [Sec, RelocSec] : Sections) { std::optional FunctionSec; if (IsRelocatable) FunctionSec = - unwrapOrError(this->FileName, this->Obj.getSection(Sec.sh_link)); + unwrapOrError(this->FileName, this->Obj.getSection(Sec->sh_link)); ListScope L(W, "BBAddrMap"); + std::optional RelaSec = {}; + if(IsRelocatable) + RelaSec = *RelocSec; Expected> BBAddrMapOrErr = - this->Obj.decodeBBAddrMap(Sec); + this->Obj.decodeBBAddrMap(*Sec, RelaSec); if (!BBAddrMapOrErr) { - this->reportUniqueWarning("unable to dump " + this->describe(Sec) + ": " + + this->reportUniqueWarning("unable to dump " + this->describe(*Sec) + ": " + toString(BBAddrMapOrErr.takeError())); continue; } @@ -7119,7 +7125,7 @@ if (FuncSymIndex.empty()) this->reportUniqueWarning( "could not identify function symbol for address (0x" + - Twine::utohexstr(AM.Addr) + ") in " + this->describe(Sec)); + Twine::utohexstr(AM.Addr) + ") in " + this->describe(*Sec)); else FuncName = this->getStaticSymbolName(FuncSymIndex.front()); W.printString("Name", FuncName); diff --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp --- a/llvm/unittests/Object/ELFObjectFileTest.cpp +++ b/llvm/unittests/Object/ELFObjectFileTest.cpp @@ -720,9 +720,7 @@ )"; DoCheckFails(InvalidLinkedYamlString, /*TextSectionIndex=*/4, - "unable to get the linked-to section for " - "SHT_LLVM_BB_ADDR_MAP_V0 section with index 4: invalid section " - "index: 10"); + "invalid section index: 10"); // Linked sections are not checked when we don't target a specific text // section. DoCheckSucceeds(InvalidLinkedYamlString, /*TextSectionIndex=*/std::nullopt,