[PATCH] D128705: [llvm-objdump] Create fake sections for a ELF core file

Namhyung Kim via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 28 00:19:15 PDT 2022


namhyung created this revision.
namhyung added reviewers: Bigcheese, MaskRay, irogers.
Herald added a subscriber: StephenFan.
Herald added a project: All.
namhyung requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

The linux perf tools use /proc/kcore for disassembly kernel functions.
Actually it copies the relevant parts to a temp file and then pass it to
objdump.  But it doesn't have section headers so llvm-objdump cannot
handle it.

Let's create fake section headers for the program headers.  It'd have a
single section for each segment to cover the entire range.  And for this
purpose we can consider only executable code segments.

With this change, I can see `perf annotate` shows proper outputs.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D128705

Files:
  llvm/include/llvm/Object/ELF.h


Index: llvm/include/llvm/Object/ELF.h
===================================================================
--- llvm/include/llvm/Object/ELF.h
+++ llvm/include/llvm/Object/ELF.h
@@ -184,7 +184,16 @@
 
   ELFFile(StringRef Object);
 
+  void createFakeSections();
+  std::unique_ptr<Elf_Shdr[]> FakeSec;
+  int NumFakeSec;
+
 public:
+  ELFFile(const ELFFile<ELFT>& other) : Buf(other.Buf) {
+    if (getHeader().e_type == ELF::ET_CORE)
+      createFakeSections();
+  }
+
   const Elf_Ehdr &getHeader() const {
     return *reinterpret_cast<const Elf_Ehdr *>(base());
   }
@@ -746,7 +755,10 @@
   return 0;
 }
 
-template <class ELFT> ELFFile<ELFT>::ELFFile(StringRef Object) : Buf(Object) {}
+template <class ELFT> ELFFile<ELFT>::ELFFile(StringRef Object) : Buf(Object) {
+  if (getHeader().e_type == ELF::ET_CORE)
+    createFakeSections();
+}
 
 template <class ELFT>
 Expected<ELFFile<ELFT>> ELFFile<ELFT>::create(StringRef Object) {
@@ -757,11 +769,51 @@
   return ELFFile(Object);
 }
 
+/// This function creates fake section headers from program headers.
+/// This is for linux perf tools because it copies a part of kcore
+/// to disassemble a single function in the kernel.
+template <class ELFT>
+void ELFFile<ELFT>::createFakeSections() {
+  auto PhdrsOrErr = program_headers();
+  if (!PhdrsOrErr)
+    return;
+
+  NumFakeSec = 0;
+  for (auto Phdr : *PhdrsOrErr) {
+    if (!(Phdr.p_type & ELF::PT_LOAD))
+      continue;
+    if (!(Phdr.p_flags & ELF::PF_X))
+      continue;
+    NumFakeSec++;
+  }
+  if (NumFakeSec == 0)
+    return;
+
+  FakeSec = std::make_unique<Elf_Shdr[]>(NumFakeSec);
+
+  auto Shdr = &FakeSec[0];
+  for (auto Phdr : *PhdrsOrErr) {
+    if (!(Phdr.p_type & ELF::PT_LOAD))
+      continue;
+    if (!(Phdr.p_flags & ELF::PF_X))
+      continue;
+    Shdr->sh_type = ELF::SHT_PROGBITS;
+    Shdr->sh_flags = ELF::SHF_ALLOC | ELF::SHF_EXECINSTR;
+    Shdr->sh_addr = Phdr.p_vaddr;
+    Shdr->sh_size = Phdr.p_memsz;
+    Shdr->sh_offset = Phdr.p_offset;
+    ++Shdr;
+  }
+}
+
 template <class ELFT>
 Expected<typename ELFT::ShdrRange> ELFFile<ELFT>::sections() const {
   const uintX_t SectionTableOffset = getHeader().e_shoff;
-  if (SectionTableOffset == 0)
+  if (SectionTableOffset == 0) {
+    if (getHeader().e_type == ELF::ET_CORE && NumFakeSec)
+      return makeArrayRef(&FakeSec[0], NumFakeSec);
     return ArrayRef<Elf_Shdr>();
+  }
 
   if (getHeader().e_shentsize != sizeof(Elf_Shdr))
     return createError("invalid e_shentsize in ELF header: " +


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D128705.440504.patch
Type: text/x-patch
Size: 2501 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20220628/8b4d9be4/attachment.bin>


More information about the llvm-commits mailing list