You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2023/05/24 14:34:54 UTC

[nuttx] branch master updated: elf/coredump: add support of dump task stack without memory segments

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 24f4216066 elf/coredump: add support of dump task stack without memory segments
24f4216066 is described below

commit 24f421606666d254e7d03a3f817ab153385e65a6
Author: chao an <an...@xiaomi.com>
AuthorDate: Mon May 22 11:43:08 2023 +0800

    elf/coredump: add support of dump task stack without memory segments
    
    Signed-off-by: chao an <an...@xiaomi.com>
---
 binfmt/binfmt_coredump.c        |   5 +-
 binfmt/elf.c                    |   7 +-
 binfmt/libelf/libelf_coredump.c | 364 +++++++++++++++++++++++++++++++---------
 include/nuttx/binfmt/binfmt.h   |   6 +-
 include/nuttx/binfmt/elf.h      |   1 +
 5 files changed, 301 insertions(+), 82 deletions(-)

diff --git a/binfmt/binfmt_coredump.c b/binfmt/binfmt_coredump.c
index 3ac198a6fd..44266d4744 100644
--- a/binfmt/binfmt_coredump.c
+++ b/binfmt/binfmt_coredump.c
@@ -44,7 +44,8 @@
  ****************************************************************************/
 
 int core_dump(FAR struct memory_region_s *regions,
-              FAR struct lib_outstream_s *stream)
+              FAR struct lib_outstream_s *stream,
+              pid_t pid)
 {
   FAR struct binfmt_s *binfmt;
   int ret = -ENOENT;
@@ -55,7 +56,7 @@ int core_dump(FAR struct memory_region_s *regions,
 
       if (binfmt->coredump)
         {
-          ret = binfmt->coredump(regions, stream);
+          ret = binfmt->coredump(regions, stream, pid);
           if (ret == OK)
             {
               break;
diff --git a/binfmt/elf.c b/binfmt/elf.c
index e1c14863ef..56e6197d21 100644
--- a/binfmt/elf.c
+++ b/binfmt/elf.c
@@ -71,7 +71,8 @@ static int elf_loadbinary(FAR struct binary_s *binp,
                           int nexports);
 #ifdef CONFIG_ELF_COREDUMP
 static int elf_dumpbinary(FAR struct memory_region_s *regions,
-                          FAR struct lib_outstream_s *stream);
+                          FAR struct lib_outstream_s *stream,
+                          pid_t pid);
 #endif
 #if defined(CONFIG_DEBUG_FEATURES) && defined(CONFIG_DEBUG_BINFMT)
 static void elf_dumploadinfo(FAR struct elf_loadinfo_s *loadinfo);
@@ -316,12 +317,14 @@ errout_with_init:
 
 #ifdef CONFIG_ELF_COREDUMP
 static int elf_dumpbinary(FAR struct memory_region_s *regions,
-                          FAR struct lib_outstream_s *stream)
+                          FAR struct lib_outstream_s *stream,
+                          pid_t pid)
 {
   struct elf_dumpinfo_s dumpinfo;
 
   dumpinfo.regions = regions;
   dumpinfo.stream  = stream;
+  dumpinfo.pid     = pid;
 
   return elf_coredump(&dumpinfo);
 }
diff --git a/binfmt/libelf/libelf_coredump.c b/binfmt/libelf/libelf_coredump.c
index c0d5b28996..adbf42597b 100644
--- a/binfmt/libelf/libelf_coredump.c
+++ b/binfmt/libelf/libelf_coredump.c
@@ -23,6 +23,7 @@
  ****************************************************************************/
 
 #include <nuttx/config.h>
+#include <nuttx/arch.h>
 
 #include <sys/stat.h>
 #include <sys/param.h>
@@ -43,10 +44,20 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
-#define ELF_PAGESIZE    4096
+#ifdef PAGESIZE
+#  define ELF_PAGESIZE PAGESIZE
+#else
+#  define ELF_PAGESIZE 1024
+#endif
 
 #define ROUNDUP(x, y)   ((x + (y - 1)) / (y)) * (y)
 
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static uint8_t g_running_regs[XCPTCONTEXT_SIZE] aligned_data(16);
+
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -128,15 +139,15 @@ static int elf_emit_align(FAR struct elf_dumpinfo_s *cinfo)
 }
 
 /****************************************************************************
- * Name: elf_emit_header
+ * Name: elf_emit_hdr
  *
  * Description:
  *   Fill the elf header
  *
  ****************************************************************************/
 
-static int elf_emit_header(FAR struct elf_dumpinfo_s *cinfo,
-                           int segs)
+static int elf_emit_hdr(FAR struct elf_dumpinfo_s *cinfo,
+                        int segs)
 {
   Elf_Ehdr ehdr;
 
@@ -161,123 +172,293 @@ static int elf_emit_header(FAR struct elf_dumpinfo_s *cinfo,
 }
 
 /****************************************************************************
- * Name: elf_get_note_size
+ * Name: elf_get_ntcb
  *
  * Description:
  *   Calculate the note segment size
  *
  ****************************************************************************/
 
-static int elf_get_note_size(void)
+static int elf_get_ntcb(void)
 {
   int count = 0;
-  int total;
   int i;
 
   for (i = 0; i < g_npidhash; i++)
     {
-      if (g_pidhash[i])
+      if (g_pidhash[i] != NULL)
         {
           count++;
         }
     }
 
-  total  = count * (sizeof(Elf_Nhdr) + ROUNDUP(CONFIG_TASK_NAME_SIZE, 8) +
-                    sizeof(elf_prstatus_t));
-  total += count * (sizeof(Elf_Nhdr) + ROUNDUP(CONFIG_TASK_NAME_SIZE, 8) +
-                    sizeof(elf_prpsinfo_t));
+  return count;
+}
+
+/****************************************************************************
+ * Name: elf_get_note_size
+ *
+ * Description:
+ *   Calculate the note segment size
+ *
+ ****************************************************************************/
+
+static int elf_get_note_size(int stksegs)
+{
+  int total;
+
+  total  = stksegs * (sizeof(Elf_Nhdr) + ROUNDUP(CONFIG_TASK_NAME_SIZE, 8) +
+                     sizeof(elf_prstatus_t));
+  total += stksegs * (sizeof(Elf_Nhdr) + ROUNDUP(CONFIG_TASK_NAME_SIZE, 8) +
+                     sizeof(elf_prpsinfo_t));
   return total;
 }
 
 /****************************************************************************
- * Name: elf_emit_note_info
+ * Name: elf_emit_tcb_note
  *
  * Description:
- *   Fill the note segment information
+ *   Fill the note segment information from tcb
  *
  ****************************************************************************/
 
-static void elf_emit_note_info(FAR struct elf_dumpinfo_s *cinfo)
+static void elf_emit_tcb_note(FAR struct elf_dumpinfo_s *cinfo,
+                              FAR struct tcb_s *tcb)
 {
   char name[ROUNDUP(CONFIG_TASK_NAME_SIZE, 8)];
-  FAR struct tcb_s *tcb;
   elf_prstatus_t status;
   elf_prpsinfo_t info;
+  FAR uint32_t *regs;
   Elf_Nhdr nhdr;
   int i;
-  int j;
 
   memset(&info,   0x0, sizeof(info));
   memset(&status, 0x0, sizeof(status));
 
-  for (i = 0; i < g_npidhash; i++)
-    {
-      if (g_pidhash[i] == NULL)
-        {
-          continue;
-        }
-
-      tcb = g_pidhash[i];
+  /* Fill Process info */
 
-      /* Fill Process info */
+  nhdr.n_namesz = sizeof(name);
+  nhdr.n_descsz = sizeof(info);
+  nhdr.n_type   = NT_PRPSINFO;
 
-      nhdr.n_namesz = sizeof(name);
-      nhdr.n_descsz = sizeof(info);
-      nhdr.n_type   = NT_PRPSINFO;
+  elf_emit(cinfo, &nhdr, sizeof(nhdr));
 
-      elf_emit(cinfo, &nhdr, sizeof(nhdr));
+  strlcpy(name, tcb->name, sizeof(name));
+  elf_emit(cinfo, name, sizeof(name));
 
-      strlcpy(name, tcb->name, sizeof(name));
-      elf_emit(cinfo, name, sizeof(name));
+  info.pr_pid   = tcb->pid;
+  strlcpy(info.pr_fname, tcb->name, sizeof(info.pr_fname));
+  elf_emit(cinfo, &info, sizeof(info));
 
-      info.pr_pid   = tcb->pid;
-      strlcpy(info.pr_fname, tcb->name, sizeof(info.pr_fname));
-      elf_emit(cinfo, &info, sizeof(info));
+  /* Fill Process status */
 
-      /* Fill Process status */
+  nhdr.n_descsz = sizeof(status);
+  nhdr.n_type   = NT_PRSTATUS;
 
-      nhdr.n_descsz = sizeof(status);
-      nhdr.n_type   = NT_PRSTATUS;
+  elf_emit(cinfo, &nhdr, sizeof(nhdr));
+  elf_emit(cinfo, name, sizeof(name));
 
-      elf_emit(cinfo, &nhdr, sizeof(nhdr));
-      elf_emit(cinfo, name, sizeof(name));
+  status.pr_pid = tcb->pid;
 
-      status.pr_pid = tcb->pid;
+  if (running_task() == tcb)
+    {
+      if (up_interrupt_context())
+        {
+          regs = (FAR uint32_t *)CURRENT_REGS;
+        }
+      else
+        {
+          up_saveusercontext(g_running_regs);
+          regs = (FAR uint32_t *)g_running_regs;
+        }
+    }
+  else
+    {
+      regs = tcb->xcp.regs;
+    }
 
-      for (j = 0; j < nitems(status.pr_regs); j++)
+  if (regs != NULL)
+    {
+      for (i = 0; i < nitems(status.pr_regs); i++)
         {
-          if (tcb->xcp.regs == NULL)
+          if (g_tcbinfo.reg_off.p[i] == UINT16_MAX)
             {
               continue;
             }
+          else
+            {
+              status.pr_regs[i] =
+                *(uintptr_t *)((uint8_t *)regs + g_tcbinfo.reg_off.p[i]);
+            }
+        }
+    }
 
-          if (g_tcbinfo.reg_off.p[j] == UINT16_MAX)
+  elf_emit(cinfo, &status, sizeof(status));
+}
+
+/****************************************************************************
+ * Name: elf_emit_note
+ *
+ * Description:
+ *   Fill the note segment information
+ *
+ ****************************************************************************/
+
+static void elf_emit_note(FAR struct elf_dumpinfo_s *cinfo)
+{
+  int i;
+
+  if (cinfo->pid == INVALID_PROCESS_ID)
+    {
+      for (i = 0; i < g_npidhash; i++)
+        {
+          if (g_pidhash[i] != NULL)
             {
-              status.pr_regs[j] = 0;
+              elf_emit_tcb_note(cinfo, g_pidhash[i]);
             }
-          else
+        }
+    }
+  else
+    {
+      elf_emit_tcb_note(cinfo, nxsched_get_tcb(cinfo->pid));
+    }
+}
+
+/****************************************************************************
+ * Name: elf_emit_tcb_stack
+ *
+ * Description:
+ *   Fill the task stack information from tcb
+ *
+ ****************************************************************************/
+
+static void elf_emit_tcb_stack(FAR struct elf_dumpinfo_s *cinfo,
+                               FAR struct tcb_s *tcb)
+{
+  FAR void *buf;
+  size_t len;
+
+  if (running_task() != tcb)
+    {
+      len = ((uintptr_t)tcb->stack_base_ptr + tcb->adj_stack_size) -
+            up_getusrsp(tcb->xcp.regs);
+      buf = (FAR void *)up_getusrsp(tcb->xcp.regs);
+    }
+  else
+    {
+      buf = (FAR void *)tcb->stack_alloc_ptr;
+      len = tcb->adj_stack_size +
+            (tcb->stack_base_ptr - tcb->stack_alloc_ptr);
+    }
+
+  elf_emit(cinfo, buf, len);
+
+  /* Align to page */
+
+  elf_emit_align(cinfo);
+}
+
+/****************************************************************************
+ * Name: elf_emit_stack
+ *
+ * Description:
+ *   Fill the task stack information
+ *
+ ****************************************************************************/
+
+static void elf_emit_stack(FAR struct elf_dumpinfo_s *cinfo)
+{
+  int i;
+
+  if (cinfo->pid == INVALID_PROCESS_ID)
+    {
+      for (i = 0; i < g_npidhash; i++)
+        {
+          if (g_pidhash[i] != NULL)
             {
-              status.pr_regs[j] = *(uintptr_t *)((uint8_t *)tcb->xcp.regs +
-                                                 g_tcbinfo.reg_off.p[j]);
+              elf_emit_tcb_stack(cinfo, g_pidhash[i]);
             }
         }
+    }
+  else
+    {
+      elf_emit_tcb_stack(cinfo, nxsched_get_tcb(cinfo->pid));
+    }
+}
 
-      elf_emit(cinfo, &status, sizeof(status));
+/****************************************************************************
+ * Name: elf_emit_memory
+ *
+ * Description:
+ *   Fill the note segment information
+ *
+ ****************************************************************************/
+
+static void elf_emit_memory(FAR struct elf_dumpinfo_s *cinfo, int memsegs)
+{
+  int i;
+
+  for (i = 0; i < memsegs; i++)
+    {
+      elf_emit(cinfo, (FAR void *)cinfo->regions[i].start,
+               cinfo->regions[i].end -
+               cinfo->regions[i].start);
+
+      /* Align to page */
+
+      elf_emit_align(cinfo);
     }
 }
 
 /****************************************************************************
- * Name: elf_emit_program_header
+ * Name: elf_emit_tcb_phdr
+ *
+ * Description:
+ *   Fill the program segment header from tcb
+ *
+ ****************************************************************************/
+
+static void elf_emit_tcb_phdr(FAR struct elf_dumpinfo_s *cinfo,
+                              FAR struct tcb_s *tcb,
+                              FAR Elf_Phdr *phdr, off_t *offset)
+{
+  if (running_task() != tcb)
+    {
+      phdr->p_filesz = (uintptr_t)(tcb->stack_base_ptr +
+                       tcb->adj_stack_size) - up_getusrsp(tcb->xcp.regs);
+      phdr->p_vaddr  = up_getusrsp(tcb->xcp.regs);
+    }
+  else
+    {
+      phdr->p_vaddr  = (uintptr_t)tcb->stack_alloc_ptr;
+      phdr->p_filesz = tcb->adj_stack_size +
+                      (tcb->stack_base_ptr - tcb->stack_alloc_ptr);
+    }
+
+  phdr->p_type   = PT_LOAD;
+  phdr->p_offset = ROUNDUP(*offset, ELF_PAGESIZE);
+  phdr->p_paddr  = phdr->p_vaddr;
+  phdr->p_memsz  = phdr->p_filesz;
+  phdr->p_flags  = PF_X | PF_W | PF_R;
+  phdr->p_align  = ELF_PAGESIZE;
+  *offset       += ROUNDUP(phdr->p_memsz, ELF_PAGESIZE);
+
+  elf_emit(cinfo, phdr, sizeof(*phdr));
+}
+
+/****************************************************************************
+ * Name: elf_emit_phdr
  *
  * Description:
  *   Fill the program segment header
  *
  ****************************************************************************/
 
-static void elf_emit_program_header(FAR struct elf_dumpinfo_s *cinfo,
-                                    int segs)
+static void elf_emit_phdr(FAR struct elf_dumpinfo_s *cinfo,
+                          int stksegs, int memsegs)
 {
-  off_t offset = cinfo->stream->nput + (segs + 1) * sizeof(Elf_Phdr);
+  off_t offset = cinfo->stream->nput +
+                 (stksegs + memsegs + 1) * sizeof(Elf_Phdr);
   Elf_Phdr phdr;
   int i;
 
@@ -285,19 +466,35 @@ static void elf_emit_program_header(FAR struct elf_dumpinfo_s *cinfo,
 
   phdr.p_type   = PT_NOTE;
   phdr.p_offset = offset;
-  phdr.p_filesz = elf_get_note_size();
+  phdr.p_filesz = elf_get_note_size(stksegs);
   offset       += phdr.p_filesz;
 
   elf_emit(cinfo, &phdr, sizeof(phdr));
 
+  if (cinfo->pid == INVALID_PROCESS_ID)
+    {
+      for (i = 0; i < g_npidhash; i++)
+        {
+          if (g_pidhash[i] != NULL)
+            {
+              elf_emit_tcb_phdr(cinfo, g_pidhash[i], &phdr, &offset);
+            }
+        }
+    }
+  else
+    {
+      elf_emit_tcb_phdr(cinfo, nxsched_get_tcb(cinfo->pid),
+                        &phdr, &offset);
+    }
+
   /* Write program headers for segments dump */
 
-  for (i = 0; i < segs; i++)
+  for (i = 0; i < memsegs; i++)
     {
       phdr.p_type   = PT_LOAD;
       phdr.p_offset = ROUNDUP(offset, ELF_PAGESIZE);
       phdr.p_vaddr  = cinfo->regions[i].start;
-      phdr.p_paddr  = cinfo->regions[i].start;
+      phdr.p_paddr  = phdr.p_vaddr;
       phdr.p_filesz = cinfo->regions[i].end - cinfo->regions[i].start;
       phdr.p_memsz  = phdr.p_filesz;
       phdr.p_flags  = cinfo->regions[i].flags;
@@ -327,54 +524,69 @@ static void elf_emit_program_header(FAR struct elf_dumpinfo_s *cinfo,
 
 int elf_coredump(FAR struct elf_dumpinfo_s *cinfo)
 {
-  int segs = 0;
-  int i;
+  irqstate_t flags;
+  int memsegs = 0;
+  int stksegs;
 
-  /* Check the memory region */
+  flags = enter_critical_section();
+
+  if (cinfo->pid != INVALID_PROCESS_ID)
+    {
+      if (nxsched_get_tcb(cinfo->pid) == NULL)
+        {
+          leave_critical_section(flags);
+          return -EINVAL;
+        }
 
-  if (cinfo->regions)
+      stksegs = 1;
+    }
+  else
     {
-      for (; cinfo->regions[segs].start <
-             cinfo->regions[segs].end; segs++);
+      stksegs = elf_get_ntcb();
     }
 
-  if (segs == 0)
+  /* Check the memory region */
+
+  if (cinfo->regions != NULL)
     {
-      return -EINVAL;
+      for (; cinfo->regions[memsegs].start <
+             cinfo->regions[memsegs].end; memsegs++);
     }
 
   /* Fill notes section */
 
-  elf_emit_header(cinfo, segs + 1);
+  elf_emit_hdr(cinfo, stksegs + memsegs + 1);
 
   /* Fill all the program information about the process for the
    * notes.  This also sets up the file header.
    */
 
-  elf_emit_program_header(cinfo, segs);
+  elf_emit_phdr(cinfo, stksegs, memsegs);
 
   /* Fill note information */
 
-  elf_emit_note_info(cinfo);
+  elf_emit_note(cinfo);
 
   /* Align to page */
 
   elf_emit_align(cinfo);
 
-  /* Start dump the memory */
+  /* Dump stack */
 
-  for (i = 0; i < segs; i++)
-    {
-      elf_emit(cinfo, (FAR void *)cinfo->regions[i].start,
-               cinfo->regions[i].end -
-               cinfo->regions[i].start);
+  elf_emit_stack(cinfo);
 
-      /* Align to page */
+  /* Dump memory segments */
 
-      elf_emit_align(cinfo);
+  if (memsegs > 0)
+    {
+      elf_emit_memory(cinfo, memsegs);
     }
 
   /* Flush the dump */
 
-  return elf_flush(cinfo);
+  elf_flush(cinfo);
+
+  leave_critical_section(flags);
+
+  return OK;
 }
diff --git a/include/nuttx/binfmt/binfmt.h b/include/nuttx/binfmt/binfmt.h
index 1da05b65c9..0e9d6d61ab 100644
--- a/include/nuttx/binfmt/binfmt.h
+++ b/include/nuttx/binfmt/binfmt.h
@@ -139,7 +139,8 @@ struct binfmt_s
   /* Unload module callback */
 
   CODE int (*coredump)(FAR struct memory_region_s *regions,
-                       FAR struct lib_outstream_s *stream);
+                       FAR struct lib_outstream_s *stream,
+                       pid_t pid);
 };
 
 /****************************************************************************
@@ -209,7 +210,8 @@ int unregister_binfmt(FAR struct binfmt_s *binfmt);
  ****************************************************************************/
 
 int core_dump(FAR struct memory_region_s *regions,
-              FAR struct lib_outstream_s *stream);
+              FAR struct lib_outstream_s *stream,
+              pid_t pid);
 
 /****************************************************************************
  * Name: load_module
diff --git a/include/nuttx/binfmt/elf.h b/include/nuttx/binfmt/elf.h
index 3e800e392e..2acca1c4e2 100644
--- a/include/nuttx/binfmt/elf.h
+++ b/include/nuttx/binfmt/elf.h
@@ -141,6 +141,7 @@ struct elf_dumpinfo_s
 {
   FAR struct memory_region_s *regions;
   FAR struct lib_outstream_s *stream;
+  pid_t                       pid;
 };
 #endif