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