diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h index 74557d3ddae8be..7a9dd8cb79e72e 100644 --- a/llvm/include/llvm/Object/ELF.h +++ b/llvm/include/llvm/Object/ELF.h @@ -392,7 +392,8 @@ class ELFFile { 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 Elf_Shdr *RelaSec = nullptr) const; /// Returns a map from every section matching \p IsMatch to its relocation /// section, or \p nullptr if it has no relocation section. This function diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp index 46e1b13e7c061a..715cb5c7765e41 100644 --- a/llvm/lib/Object/ELF.cpp +++ b/llvm/lib/Object/ELF.cpp @@ -640,7 +640,26 @@ ELFFile::toMappedAddr(uint64_t VAddr, WarningHandler WarnHandler) const { template Expected> -ELFFile::decodeBBAddrMap(const Elf_Shdr &Sec) const { +ELFFile::decodeBBAddrMap(const Elf_Shdr &Sec, + const Elf_Shdr *RelaSec) const { + bool IsRelocatable = getHeader().e_type == ELF::ET_REL; + + // This DenseMap maps the offset of each function (the location of the + // reference to the function in the SHT_LLVM_BB_ADDR_MAP section) to the + // addend (the location of the function in the text section). + llvm::DenseMap FunctionOffsetTranslations; + if (IsRelocatable && RelaSec) { + assert(RelaSec && + "Can't read a SHT_LLVM_BB_ADDR_MAP section in a relocatable " + "object file without providing a relocation section."); + Expected Relas = this->relas(*RelaSec); + if (!Relas) + return createError("unable to read relocations for section " + + describe(*this, Sec) + ": " + + toString(Relas.takeError())); + for (Elf_Rela Rela : *Relas) + FunctionOffsetTranslations[Rela.r_offset] = Rela.r_addend; + } Expected> ContentsOrErr = getSectionContents(Sec); if (!ContentsOrErr) return ContentsOrErr.takeError(); @@ -680,7 +699,20 @@ ELFFile::decodeBBAddrMap(const Elf_Shdr &Sec) const { Twine(static_cast(Version))); Data.getU8(Cur); // Feature byte } + uint64_t SectionOffset = Cur.tell(); uintX_t Address = static_cast(Data.getAddress(Cur)); + if (!Cur) + return Cur.takeError(); + if (IsRelocatable) { + assert(Address == 0); + auto FOTIterator = FunctionOffsetTranslations.find(SectionOffset); + if (FOTIterator == FunctionOffsetTranslations.end()) { + return createError("failed to get relocation data for offset: " + + Twine::utohexstr(SectionOffset) + " in section " + + describe(*this, Sec)); + } + Address = FOTIterator->second; + } 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 index 2cbfd8ac901b35..b9343d646db61e 100644 --- a/llvm/lib/Object/ELFObjectFile.cpp +++ b/llvm/lib/Object/ELFObjectFile.cpp @@ -681,24 +681,39 @@ template 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; + 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) { - 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())); - if (*TextSectionIndex != std::distance(Sections.begin(), *TextSecOrErr)) - continue; - } - Expected> BBAddrMapOrErr = EF.decodeBBAddrMap(Sec); + return false; + if (!TextSectionIndex) + return true; + 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())); + if (*TextSectionIndex != std::distance(Sections.begin(), *TextSecOrErr)) + return false; + return true; + }; + + Expected> SectionRelocMapOrErr = + EF.getSectionAndRelocations(IsMatch); + if (!SectionRelocMapOrErr) + return SectionRelocMapOrErr.takeError(); + + for (auto const &[Sec, RelocSec] : *SectionRelocMapOrErr) { + if (IsRelocatable && !RelocSec) + return createError("unable to get relocation section for " + + describe(EF, *Sec)); + Expected> BBAddrMapOrErr = + EF.decodeBBAddrMap(*Sec, RelocSec); 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 index 2d4a52211f812e..cf4ac77b3d154c 100644 --- 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 index 00000000000000..d5a618467bd2c9 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/X86/elf-bbaddrmap-symbolize-relocatable.yaml @@ -0,0 +1,91 @@ +## 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 att --no-show-raw-insn --no-leading-addr | \ +# RUN: FileCheck %s -DSYM=symbol --match-full-lines + +--- !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: FFFF + - Name: .llvm_bb_addr_map + Type: SHT_LLVM_BB_ADDR_MAP + Link: .text + Entries: + - Version: 2 + BBEntries: + - ID: 0 + AddressOffset: 0x0 + Size: 0x1 + Metadata: 0x1 + - Version: 2 + BBEntries: + - ID: 0 + AddressOffset: 0x0 + Size: 0x1 + 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: 1 +Symbols: + - Name: a + Section: .text + Value: 0x0 + - Name: c + Section: .text + Value: 0x1 + - Name: .text + Type: STT_SECTION + Section: .text + +# CHECK: : +# CHECK-NEXT: : +# CHECK: : +# CHECK-NEXT: : + +## Check that if we're missing a relocation section we get the appropriate +## warning. + +# RUN: yaml2obj %s --docnum=2 -o %t2 +# RUN: llvm-readobj %t2 --bb-addr-map 2>&1 | FileCheck %s --check-prefix=NO-RELA-SECTION -DFILE=%t2 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Content: FF + - Name: .llvm_bb_addr_map + Type: SHT_LLVM_BB_ADDR_MAP + Link: .text + +# NO-RELA-SECTION: warning: '[[FILE]]': unable to get relocation section for SHT_LLVM_BB_ADDR_MAP section with index 2 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 index 00000000000000..f59a694ae52e47 --- /dev/null +++ b/llvm/test/tools/llvm-readobj/ELF/bb-addr-map-relocatable.test @@ -0,0 +1,211 @@ +## 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: } +# CHECK-NEXT: ] + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +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 + - 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 + +## Check that if we have a relocatable file and no relocation section for +## a SHT_LLVM_BB_ADDR_MAP section, we give the appropriate warnings. + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + - Name: .llvm_bb_addr_map + Type: SHT_LLVM_BB_ADDR_MAP + Link: .text + +# RUN: yaml2obj %s --docnum=2 -o %t2.o +# RUN: llvm-readobj %t2.o --bb-addr-map 2>&1 | FileCheck %s --check-prefix=NO-RELA -DFILE=%t2.o + +# NO-RELA: warning: '[[FILE]]': unable to get relocation section for SHT_LLVM_BB_ADDR_MAP section with index 2 + +## Check that we get a warning if we expect a relocation and it is not present. + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +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 + - Name: .rela.llvm_bb_addr_map + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Info: .llvm_bb_addr_map + +# RUN: yaml2obj %s --docnum=3 -o %t3.o +# RUN: llvm-readobj %t3.o --bb-addr-map 2>&1 | FileCheck %s --check-prefix=MISSING-RELOCATION -DFILE=%t3.o + +# MISSING-RELOCATION: warning: '[[FILE]]': unable to dump SHT_LLVM_BB_ADDR_MAP section with index 2: failed to get relocation data for offset: 2 in section SHT_LLVM_BB_ADDR_MAP section with index 2 + +## Check that if we have a missing relocated section, we fail and give the +## appropriate warning. + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .rela.llvm_bb_addr_map + Type: SHT_RELA + Flags: [ SHF_INFO_LINK ] + Info: 0xFF + +# RUN: yaml2obj %s --docnum=4 -o %t4.o +# RUN: llvm-readobj %t4.o --bb-addr-map 2>&1 | FileCheck %s --check-prefix=NO-RELOCATED-SECTION -DFILE=%t4.o + +# NO-RELOCATED-SECTION: warning: '[[FILE]]': failed to get SHT_LLVM_BB_ADDR_MAP section(s): SHT_RELA section with index 1: failed to get a relocated section: invalid section index: 255 + +## Check that if we have an ET_DYN file with a .rela.dyn section, we don't get +## a warning about a missing relocation section and can get the baddrmap data. + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .rela.dyn + Type: SHT_RELA + Flags: [ SHF_ALLOC ] + - Name: .llvm_bb_addr_map + Type: SHT_LLVM_BB_ADDR_MAP + Flags: [ SHF_LINK_ORDER ] + Entries: + - Version: 2 + Address: 0xF + BBEntries: + - ID: 0 + AddressOffset: 0x0 + Size: 0xF + Metadata: 0x1 + +# RUN: yaml2obj %s --docnum=5 -o %t5.o +# RUN: llvm-readobj %t5.o --bb-addr-map 2>&1 | FileCheck %s --check-prefix=ET-DYN-NO-WARNING -DFILE=%t5.o + +# ET-DYN-NO-WARNING: BBAddrMap [ +# ET-DYN-NO-WARNING: Function { +# ET-DYN-NO-WARNING: At: 0xF +# ET-DYN-NO-WARNING: Name: +# ET-DYN-NO-WARNING: BB entries [ +# ET-DYN-NO-WARNING: { +# ET-DYN-NO-WARNING: ID: 0 +# ET-DYN-NO-WARNING: Offset: 0x0 +# ET-DYN-NO-WARNING: Size: 0xF +# ET-DYN-NO-WARNING: HasReturn: Yes +# ET-DYN-NO-WARNING: HasTailCall: No +# ET-DYN-NO-WARNING: IsEHPad: No +# ET-DYN-NO-WARNING: CanFallThrough: No +# ET-DYN-NO-WARNING: } +# ET-DYN-NO-WARNING: ] +# ET-DYN-NO-WARNING: } +# ET-DYN-NO-WARNING: ] diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp index 44f685f615c39a..e3d14192c0625e 100644 --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -1439,8 +1439,10 @@ static void disassembleObject(const Target *TheTarget, ObjectFile &Obj, AddrToBBAddrMap.clear(); if (const auto *Elf = dyn_cast(&Obj)) { auto BBAddrMapsOrErr = Elf->readBBAddrMap(SectionIndex); - if (!BBAddrMapsOrErr) + if (!BBAddrMapsOrErr) { reportWarning(toString(BBAddrMapsOrErr.takeError()), Obj.getFileName()); + return; + } for (auto &FunctionBBAddrMap : *BBAddrMapsOrErr) AddrToBBAddrMap.emplace(FunctionBBAddrMap.Addr, std::move(FunctionBBAddrMap)); diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index a462dbf2a622df..ec77f724515877 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -7173,21 +7173,35 @@ template void LLVMELFDumper::printCGProfile() { 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; + }; + Expected> SecRelocMapOrErr = + this->Obj.getSectionAndRelocations(IsMatch); + if (!SecRelocMapOrErr) { + this->reportUniqueWarning( + "failed to get SHT_LLVM_BB_ADDR_MAP section(s): " + + toString(SecRelocMapOrErr.takeError())); + return; + } + for (auto const &[Sec, RelocSec] : *SecRelocMapOrErr) { 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"); + if (IsRelocatable && !RelocSec) { + this->reportUniqueWarning("unable to get relocation section for " + + this->describe(*Sec)); + continue; + } Expected> BBAddrMapOrErr = - this->Obj.decodeBBAddrMap(Sec); + this->Obj.decodeBBAddrMap(*Sec, RelocSec); if (!BBAddrMapOrErr) { - this->reportUniqueWarning("unable to dump " + this->describe(Sec) + ": " + - toString(BBAddrMapOrErr.takeError())); + this->reportUniqueWarning("unable to dump " + this->describe(*Sec) + + ": " + toString(BBAddrMapOrErr.takeError())); continue; } for (const BBAddrMap &AM : *BBAddrMapOrErr) { @@ -7199,7 +7213,7 @@ template void LLVMELFDumper::printBBAddrMaps() { 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);