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 @@ -184,6 +184,8 @@ ELFFile(StringRef Object); + std::vector FakeSections; + public: const Elf_Ehdr &getHeader() const { return *reinterpret_cast(base()); @@ -389,6 +391,8 @@ Expected> getSectionContents(const Elf_Shdr &Sec) const; Expected> getSegmentContents(const Elf_Phdr &Phdr) const; Expected> decodeBBAddrMap(const Elf_Shdr &Sec) const; + + void createFakeSections(); }; using ELF32LEFile = ELFFile; @@ -757,11 +761,37 @@ return ELFFile(Object); } +/// Used by llvm-objdump -d (which needs sections for disassembly) to +/// disassemble objects without a section header table (e.g. ET_CORE objects +/// analyzed by linux perf). +template void ELFFile::createFakeSections() { + if (getHeader().e_type != ELF::ET_CORE || !FakeSections.empty()) + return; + auto PhdrsOrErr = program_headers(); + if (!PhdrsOrErr) + return; + + for (auto Phdr : *PhdrsOrErr) { + if (!(Phdr.p_type & ELF::PT_LOAD) || !(Phdr.p_flags & ELF::PF_X)) + continue; + Elf_Shdr FakeShdr = {}; + FakeShdr.sh_type = ELF::SHT_PROGBITS; + FakeShdr.sh_flags = ELF::SHF_ALLOC | ELF::SHF_EXECINSTR; + FakeShdr.sh_addr = Phdr.p_vaddr; + FakeShdr.sh_size = Phdr.p_memsz; + FakeShdr.sh_offset = Phdr.p_offset; + FakeSections.push_back(FakeShdr); + } +} + template Expected ELFFile::sections() const { const uintX_t SectionTableOffset = getHeader().e_shoff; - if (SectionTableOffset == 0) + if (SectionTableOffset == 0) { + if (!FakeSections.empty()) + return makeArrayRef(FakeSections.data(), FakeSections.size()); return ArrayRef(); + } if (getHeader().e_shentsize != sizeof(Elf_Shdr)) return createError("invalid e_shentsize in ELF header: " + 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 @@ -457,6 +457,12 @@ elf_symbol_iterator_range getDynamicSymbolIterators() const override; bool isRelocatableObject() const override; + + void createFakeSections() { + if (getEType() == ELF::ET_CORE) { + EF.createFakeSections(); + } + } }; using ELF32LEObjectFile = ELFObjectFile; diff --git a/llvm/test/tools/llvm-objdump/X86/disassemble-no-section-kcore.test b/llvm/test/tools/llvm-objdump/X86/disassemble-no-section-kcore.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/X86/disassemble-no-section-kcore.test @@ -0,0 +1,45 @@ +# This test checks -d disassembles a kcore file extracted by linux perf tools +# which doesn't have section headers +# RUN: yaml2obj %s -o %t +# RUN: llvm-objdump -h %t | FileCheck %s --check-prefix HEADER +# RUN: llvm-objdump -d --start-address=0xffffffff8103398c \ +# RUN: --stop-address=0xffffffff81033996 %t | FileCheck %s --check-prefix DISAS + +# HEADER: Sections: +# HEADER-NEXT: Idx Name Size VMA Type +# HEADER-NEXT: 0 0000000a ffffffff8103398c TEXT + +# DISAS: <>: +# DISAS-NEXT: 55 pushq %rbp +# DISAS-NEXT: 48 89 e5 movq %rsp, %rbp +# DISAS-NEXT: 0f 1f 40 00 nopl (%rax) +# DISAS-NEXT: 5d popq %rbp +# DISAS-NEXT: c3 retq + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_CORE + Machine: EM_X86_64 +Sections: + - Type: SectionHeaderTable + NoHeaders: true + - Type: Fill + Name: code + Pattern: "554889E50F1F40005DC3" + Size: 10 + Offset: 0x1000 +ProgramHeaders: + - Type: PT_LOAD + Flags: [ PF_X, PF_W, PF_R ] + VAddr: 0xFFFFFFFF8103398C + PAddr: 0x0 + Offset: 0x1000 + FileSize: 10 + MemSize: 10 + Align: 0x1000 + FirstSec: code + LastSec: code +... + 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 @@ -1128,6 +1128,20 @@ FOS.flush(); } +static void createFakeELFSections(ObjectFile *Obj) { + assert(Obj->isELF()); + if (auto *Elf32LEObj = dyn_cast(Obj)) + Elf32LEObj->createFakeSections(); + else if (auto *Elf64LEObj = dyn_cast(Obj)) + Elf64LEObj->createFakeSections(); + else if (auto *Elf32BEObj = dyn_cast(Obj)) + Elf32BEObj->createFakeSections(); + else if (auto *Elf64BEObj = cast(Obj)) + Elf64BEObj->createFakeSections(); + else + llvm_unreachable("Unsupported binary format"); +} + static void disassembleObject(const Target *TheTarget, const ObjectFile *Obj, MCContext &Ctx, MCDisassembler *PrimaryDisAsm, MCDisassembler *SecondaryDisAsm, @@ -1195,6 +1209,9 @@ if (Obj->isWasm()) addMissingWasmCodeSymbols(cast(Obj), AllSymbols); + if (Obj->isELF() && Obj->sections().empty()) + createFakeELFSections(const_cast(Obj)); + BumpPtrAllocator A; StringSaver Saver(A); addPltEntries(Obj, AllSymbols, Saver); @@ -1899,6 +1916,9 @@ outs() << "Idx " << left_justify("Name", NameWidth) << " Size " << left_justify("VMA", AddressWidth) << " Type\n"; + if (Obj->isELF() && Obj->sections().empty()) + createFakeELFSections(const_cast(Obj)); + uint64_t Idx; for (const SectionRef &Section : ToolSectionFilter(*Obj, &Idx)) { StringRef Name = unwrapOrError(Section.getName(), Obj->getFileName());