coredump:Move coredump to sched/misc

1. move coredump form libelf to sched/misc
2. rename core_dump to coredump

Signed-off-by: anjiahao <anjiahao@xiaomi.com>
This commit is contained in:
anjiahao 2024-07-06 15:22:51 +08:00 committed by Xiang Xiao
parent 9e868cadfb
commit 52126aede1
20 changed files with 697 additions and 879 deletions

View file

@ -16,9 +16,7 @@ Enable Kconfig
.. code-block:: console .. code-block:: console
CONFIG_ELF=y /* Enable ELF */ CONFIG_COREDUMP=y /* Enable Coredump */
CONFIG_ELF_COREDUMP=y /* Enable ELF Coredump */
CONFIG_BOARD_COREDUMP_SYSLOG=y /* Enable Board Coredump, if exceptions and assertions occur, */ CONFIG_BOARD_COREDUMP_SYSLOG=y /* Enable Board Coredump, if exceptions and assertions occur, */

View file

@ -39,8 +39,7 @@ list(
binfmt_exec.c binfmt_exec.c
binfmt_copyargv.c binfmt_copyargv.c
binfmt_copyactions.c binfmt_copyactions.c
binfmt_dumpmodule.c binfmt_dumpmodule.c)
binfmt_coredump.c)
if(CONFIG_BINFMT_LOADABLE) if(CONFIG_BINFMT_LOADABLE)
list(APPEND SRCS binfmt_exit.c) list(APPEND SRCS binfmt_exit.c)

View file

@ -27,7 +27,6 @@ include $(TOPDIR)/Make.defs
CSRCS = binfmt_globals.c binfmt_initialize.c binfmt_register.c binfmt_unregister.c CSRCS = binfmt_globals.c binfmt_initialize.c binfmt_register.c binfmt_unregister.c
CSRCS += binfmt_loadmodule.c binfmt_unloadmodule.c binfmt_execmodule.c CSRCS += binfmt_loadmodule.c binfmt_unloadmodule.c binfmt_execmodule.c
CSRCS += binfmt_exec.c binfmt_copyargv.c binfmt_copyactions.c binfmt_dumpmodule.c CSRCS += binfmt_exec.c binfmt_copyargv.c binfmt_copyactions.c binfmt_dumpmodule.c
CSRCS += binfmt_coredump.c
ifeq ($(CONFIG_BINFMT_LOADABLE),y) ifeq ($(CONFIG_BINFMT_LOADABLE),y)
CSRCS += binfmt_exit.c CSRCS += binfmt_exit.c

View file

@ -1,72 +0,0 @@
/****************************************************************************
* binfmt/binfmt_coredump.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/binfmt/binfmt.h>
#include <errno.h>
#include "binfmt.h"
#ifndef CONFIG_BINFMT_DISABLE
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: core_dump
*
* Description:
* This function for generating core dump stream.
*
****************************************************************************/
int core_dump(FAR const struct memory_region_s *regions,
FAR struct lib_outstream_s *stream,
pid_t pid)
{
FAR struct binfmt_s *binfmt;
int ret = -ENOENT;
for (binfmt = g_binfmts; binfmt; binfmt = binfmt->next)
{
/* Use this handler to try to load the format */
if (binfmt->coredump)
{
ret = binfmt->coredump(regions, stream, pid);
if (ret == OK)
{
break;
}
}
}
return ret;
}
#endif /* CONFIG_BINFMT_DISABLE */

View file

@ -69,11 +69,6 @@ static int elf_loadbinary(FAR struct binary_s *binp,
FAR const char *filename, FAR const char *filename,
FAR const struct symtab_s *exports, FAR const struct symtab_s *exports,
int nexports); int nexports);
#ifdef CONFIG_ELF_COREDUMP
static int elf_dumpbinary(FAR const struct memory_region_s *regions,
FAR struct lib_outstream_s *stream,
pid_t pid);
#endif
#if defined(CONFIG_DEBUG_FEATURES) && defined(CONFIG_DEBUG_BINFMT) #if defined(CONFIG_DEBUG_FEATURES) && defined(CONFIG_DEBUG_BINFMT)
static void elf_dumploadinfo(FAR struct elf_loadinfo_s *loadinfo); static void elf_dumploadinfo(FAR struct elf_loadinfo_s *loadinfo);
#endif #endif
@ -87,9 +82,6 @@ static struct binfmt_s g_elfbinfmt =
NULL, /* next */ NULL, /* next */
elf_loadbinary, /* load */ elf_loadbinary, /* load */
NULL, /* unload */ NULL, /* unload */
#ifdef CONFIG_ELF_COREDUMP
elf_dumpbinary, /* coredump */
#endif
}; };
/**************************************************************************** /****************************************************************************
@ -370,32 +362,6 @@ errout_with_init:
return ret; return ret;
} }
/****************************************************************************
* Name: elf_dumpbinary
*
* Description:
* Generat the core dump stream as ELF structure.
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
#ifdef CONFIG_ELF_COREDUMP
static int elf_dumpbinary(FAR const struct memory_region_s *regions,
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);
}
#endif
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/

View file

@ -40,11 +40,6 @@ if(CONFIG_ELF)
libelf_unload.c libelf_unload.c
libelf_verify.c) libelf_verify.c)
if(CONFIG_ELF_COREDUMP)
list(APPEND SRCS libelf_coredump.c)
target_include_directories(binfmt PRIVATE ${NUTTX_DIR}/sched)
endif()
if(CONFIG_BINFMT_CONSTRUCTORS) if(CONFIG_BINFMT_CONSTRUCTORS)
list(APPEND SRCS libelf_ctors.c libelf_dtors.c) list(APPEND SRCS libelf_ctors.c libelf_dtors.c)
endif() endif()

View file

@ -63,17 +63,6 @@ config ELF_SYMBOL_CACHECOUNT
This is a cache that is used to store elf symbol table to This is a cache that is used to store elf symbol table to
reduce access fs. Default: 256 reduce access fs. Default: 256
config ELF_COREDUMP
bool "ELF Coredump"
depends on ARCH_HAVE_TCBINFO
default n
---help---
Generate ELF core dump to provide information about the CPU state and the
memory state of program.
The memory state embeds a snapshot of all segments mapped in the
memory space of the program. The CPU state contains register values
when the core dump has been generated.
config ELF_LOADTO_LMA config ELF_LOADTO_LMA
bool "ELF load sections to LMA" bool "ELF load sections to LMA"
default n default n

View file

@ -28,12 +28,6 @@ CSRCS += libelf_bind.c libelf_init.c libelf_addrenv.c libelf_iobuffer.c
CSRCS += libelf_load.c libelf_read.c libelf_sections.c libelf_symbols.c CSRCS += libelf_load.c libelf_read.c libelf_sections.c libelf_symbols.c
CSRCS += libelf_uninit.c libelf_unload.c libelf_verify.c CSRCS += libelf_uninit.c libelf_unload.c libelf_verify.c
ifeq ($(CONFIG_ELF_COREDUMP),y)
CSRCS += libelf_coredump.c
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)sched
endif
ifeq ($(CONFIG_BINFMT_CONSTRUCTORS),y) ifeq ($(CONFIG_BINFMT_CONSTRUCTORS),y)
CSRCS += libelf_ctors.c libelf_dtors.c CSRCS += libelf_ctors.c libelf_dtors.c
endif endif

View file

@ -1,666 +0,0 @@
/****************************************************************************
* binfmt/libelf/libelf_coredump.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <debug.h>
#include <errno.h>
#include <nuttx/elf.h>
#include <nuttx/binfmt/elf.h>
#include <nuttx/binfmt/binfmt.h>
#include <nuttx/sched.h>
#include <sched/sched.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#ifdef PAGESIZE
# define ELF_PAGESIZE PAGESIZE
#else
# define ELF_PAGESIZE 1024
#endif
#define PROGRAM_ALIGNMENT 64
#define ROUNDUP(x, y) ((x + (y - 1)) / (y)) * (y)
#define ROUNDDOWN(x ,y) (((x) / (y)) * (y))
/****************************************************************************
* Private Data
****************************************************************************/
static uint8_t g_running_regs[XCPTCONTEXT_SIZE] aligned_data(16);
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: elf_flush
*
* Description:
* Flush the out stream
*
****************************************************************************/
static int elf_flush(FAR struct elf_dumpinfo_s *cinfo)
{
return lib_stream_flush(cinfo->stream);
}
/****************************************************************************
* Name: elf_emit
*
* Description:
* Send the dump data to binfmt_outstream_s
*
****************************************************************************/
static int elf_emit(FAR struct elf_dumpinfo_s *cinfo,
FAR const void *buf, size_t len)
{
FAR const uint8_t *ptr = buf;
size_t total = len;
int ret = 0;
while (total > 0)
{
ret = lib_stream_puts(cinfo->stream, ptr, total);
if (ret < 0)
{
break;
}
total -= ret;
ptr += ret;
}
return ret < 0 ? ret : len - total;
}
/****************************************************************************
* Name: elf_emit_align
*
* Description:
* Align the filled data according to the current offset
*
****************************************************************************/
static int elf_emit_align(FAR struct elf_dumpinfo_s *cinfo)
{
off_t align = ROUNDUP(cinfo->stream->nput,
ELF_PAGESIZE) - cinfo->stream->nput;
unsigned char null[256];
off_t total = align;
off_t ret = 0;
memset(null, 0, sizeof(null));
while (total > 0)
{
ret = elf_emit(cinfo, null, total > sizeof(null) ?
sizeof(null) : total);
if (ret <= 0)
{
break;
}
total -= ret;
}
return ret < 0 ? ret : align;
}
/****************************************************************************
* Name: elf_emit_hdr
*
* Description:
* Fill the elf header
*
****************************************************************************/
static int elf_emit_hdr(FAR struct elf_dumpinfo_s *cinfo,
int segs)
{
Elf_Ehdr ehdr;
memset(&ehdr, 0, sizeof(ehdr));
memcpy(ehdr.e_ident, ELFMAG, EI_MAGIC_SIZE);
ehdr.e_ident[EI_CLASS] = ELF_CLASS;
ehdr.e_ident[EI_DATA] = ELF_DATA;
ehdr.e_ident[EI_VERSION] = EV_CURRENT;
ehdr.e_ident[EI_OSABI] = ELF_OSABI;
ehdr.e_type = ET_CORE;
ehdr.e_machine = EM_ARCH;
ehdr.e_version = EV_CURRENT;
ehdr.e_phoff = sizeof(Elf_Ehdr);
ehdr.e_flags = EF_FLAG;
ehdr.e_ehsize = sizeof(Elf_Ehdr);
ehdr.e_phentsize = sizeof(Elf_Phdr);
ehdr.e_phnum = segs;
return elf_emit(cinfo, &ehdr, sizeof(ehdr));
}
/****************************************************************************
* Name: elf_get_ntcb
*
* Description:
* Calculate the note segment size
*
****************************************************************************/
static int elf_get_ntcb(void)
{
int count = 0;
int i;
for (i = 0; i < g_npidhash; i++)
{
if (g_pidhash[i] != NULL)
{
count++;
}
}
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_tcb_note
*
* Description:
* Fill the note segment information from tcb
*
****************************************************************************/
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)];
elf_prstatus_t status;
elf_prpsinfo_t info;
FAR uintptr_t *regs;
Elf_Nhdr nhdr;
int i;
memset(&info, 0x0, sizeof(info));
memset(&status, 0x0, sizeof(status));
/* Fill Process info */
nhdr.n_namesz = sizeof(name);
nhdr.n_descsz = sizeof(info);
nhdr.n_type = NT_PRPSINFO;
elf_emit(cinfo, &nhdr, sizeof(nhdr));
strlcpy(name, get_task_name(tcb), sizeof(name));
elf_emit(cinfo, name, sizeof(name));
info.pr_pid = tcb->pid;
strlcpy(info.pr_fname, get_task_name(tcb), sizeof(info.pr_fname));
elf_emit(cinfo, &info, sizeof(info));
/* Fill Process status */
nhdr.n_descsz = sizeof(status);
nhdr.n_type = NT_PRSTATUS;
elf_emit(cinfo, &nhdr, sizeof(nhdr));
elf_emit(cinfo, name, sizeof(name));
status.pr_pid = tcb->pid;
if (running_task() == tcb)
{
if (up_interrupt_context())
{
regs = (FAR uintptr_t *)up_current_regs();
}
else
{
up_saveusercontext(g_running_regs);
regs = (FAR uintptr_t *)g_running_regs;
}
}
else
{
regs = (FAR uintptr_t *)tcb->xcp.regs;
}
if (regs != NULL)
{
for (i = 0; i < nitems(status.pr_regs); i++)
{
if (g_tcbinfo.reg_off.p[i] == UINT16_MAX)
{
continue;
}
else
{
status.pr_regs[i] = *(FAR uintptr_t *)
((FAR uint8_t *)regs + g_tcbinfo.reg_off.p[i]);
}
}
}
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)
{
elf_emit_tcb_note(cinfo, g_pidhash[i]);
}
}
}
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)
{
uintptr_t buf = 0;
uintptr_t sp;
size_t len;
if (running_task() != tcb)
{
sp = up_getusrsp(tcb->xcp.regs);
if (sp > (uintptr_t)tcb->stack_base_ptr &&
sp < (uintptr_t)tcb->stack_base_ptr + tcb->adj_stack_size)
{
len = ((uintptr_t)tcb->stack_base_ptr +
tcb->adj_stack_size) - sp;
buf = sp;
}
#ifdef CONFIG_STACK_COLORATION
else
{
len = up_check_tcbstack(tcb);
buf = (uintptr_t)tcb->stack_base_ptr +
(tcb->adj_stack_size - len);
}
#endif
}
if (buf == 0)
{
buf = (uintptr_t)tcb->stack_alloc_ptr;
len = tcb->adj_stack_size +
(tcb->stack_base_ptr - tcb->stack_alloc_ptr);
}
sp = ROUNDDOWN(buf, PROGRAM_ALIGNMENT);
len = ROUNDUP(len + (buf - sp), PROGRAM_ALIGNMENT);
buf = sp;
elf_emit(cinfo, (FAR void *)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)
{
elf_emit_tcb_stack(cinfo, g_pidhash[i]);
}
}
}
else
{
elf_emit_tcb_stack(cinfo, nxsched_get_tcb(cinfo->pid));
}
}
/****************************************************************************
* 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++)
{
if (cinfo->regions[i].flags & PF_REGISTER)
{
FAR uintptr_t *start = (FAR uintptr_t *)cinfo->regions[i].start;
FAR uintptr_t *end = (FAR uintptr_t *)cinfo->regions[i].end;
uintptr_t buf[64];
size_t offset = 0;
while (start < end)
{
buf[offset++] = *start++;
if (offset % (sizeof(buf) / sizeof(uintptr_t)) == 0)
{
elf_emit(cinfo, buf, sizeof(buf));
offset = 0;
}
}
if (offset != 0)
{
elf_emit(cinfo, buf, offset * sizeof(uintptr_t));
}
}
else
{
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_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, FAR off_t *offset)
{
uintptr_t sp;
phdr->p_vaddr = 0;
if (running_task() != tcb)
{
sp = up_getusrsp(tcb->xcp.regs);
if (sp > (uintptr_t)tcb->stack_base_ptr &&
sp < (uintptr_t)tcb->stack_base_ptr + tcb->adj_stack_size)
{
phdr->p_filesz = ((uintptr_t)tcb->stack_base_ptr +
tcb->adj_stack_size) - sp;
phdr->p_vaddr = sp;
}
#ifdef CONFIG_STACK_COLORATION
else
{
phdr->p_filesz = up_check_tcbstack(tcb);
phdr->p_vaddr = (uintptr_t)tcb->stack_base_ptr +
(tcb->adj_stack_size - phdr->p_filesz);
}
#endif
}
if (phdr->p_vaddr == 0)
{
phdr->p_vaddr = (uintptr_t)tcb->stack_alloc_ptr;
phdr->p_filesz = tcb->adj_stack_size +
(tcb->stack_base_ptr - tcb->stack_alloc_ptr);
}
sp = ROUNDDOWN(phdr->p_vaddr, PROGRAM_ALIGNMENT);
phdr->p_filesz = ROUNDUP(phdr->p_filesz +
(phdr->p_vaddr - sp), PROGRAM_ALIGNMENT);
phdr->p_vaddr = sp;
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_phdr(FAR struct elf_dumpinfo_s *cinfo,
int stksegs, int memsegs)
{
off_t offset = cinfo->stream->nput +
(stksegs + memsegs + 1) * sizeof(Elf_Phdr);
Elf_Phdr phdr;
int i;
memset(&phdr, 0, sizeof(Elf_Phdr));
phdr.p_type = PT_NOTE;
phdr.p_offset = offset;
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 < memsegs; i++)
{
phdr.p_type = PT_LOAD;
phdr.p_offset = ROUNDUP(offset, ELF_PAGESIZE);
phdr.p_vaddr = 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;
phdr.p_align = ELF_PAGESIZE;
offset += ROUNDUP(phdr.p_memsz, ELF_PAGESIZE);
elf_emit(cinfo, &phdr, sizeof(phdr));
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: elf_coredump
*
* Description:
* Generat the core dump stream as ELF structure.
*
* Input Parameters:
* dumpinfo - elf coredump informations
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int elf_coredump(FAR struct elf_dumpinfo_s *cinfo)
{
irqstate_t flags;
int memsegs = 0;
int stksegs;
flags = enter_critical_section();
if (cinfo->pid != INVALID_PROCESS_ID)
{
if (nxsched_get_tcb(cinfo->pid) == NULL)
{
leave_critical_section(flags);
return -EINVAL;
}
stksegs = 1;
}
else
{
stksegs = elf_get_ntcb();
}
/* Check the memory region */
if (cinfo->regions != NULL)
{
for (; cinfo->regions[memsegs].start <
cinfo->regions[memsegs].end; memsegs++);
}
/* Fill notes section */
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_phdr(cinfo, stksegs, memsegs);
/* Fill note information */
elf_emit_note(cinfo);
/* Align to page */
elf_emit_align(cinfo);
/* Dump stack */
elf_emit_stack(cinfo);
/* Dump memory segments */
if (memsegs > 0)
{
elf_emit_memory(cinfo, memsegs);
}
/* Flush the dump */
elf_flush(cinfo);
leave_critical_section(flags);
return OK;
}

View file

@ -81,7 +81,6 @@ static struct binfmt_s g_nxflatbinfmt =
NULL, /* next */ NULL, /* next */
nxflat_loadbinary, /* load */ nxflat_loadbinary, /* load */
nxflat_unloadbinary, /* unload */ nxflat_unloadbinary, /* unload */
NULL, /* coredump */
}; };
/**************************************************************************** /****************************************************************************

View file

@ -4634,14 +4634,14 @@ config BOARD_CRASHDUMP
config BOARD_COREDUMP_SYSLOG config BOARD_COREDUMP_SYSLOG
bool "Enable Core dump to syslog" bool "Enable Core dump to syslog"
default n default n
depends on ELF_COREDUMP depends on COREDUMP
---help--- ---help---
Enable put coredump to syslog when crash. Enable put coredump to syslog when crash.
config BOARD_COREDUMP_BLKDEV config BOARD_COREDUMP_BLKDEV
bool "Enable Core Dump to block device" bool "Enable Core Dump to block device"
default n default n
depends on ELF_COREDUMP depends on COREDUMP
---help--- ---help---
Enable save coredump at block device when crash. Enable save coredump at block device when crash.

View file

@ -21,13 +21,12 @@ CONFIG_BOARD_COREDUMP_SYSLOG=y
CONFIG_BOARD_LOOPSPERMSEC=99369 CONFIG_BOARD_LOOPSPERMSEC=99369
CONFIG_BOOT_RUNFROMSDRAM=y CONFIG_BOOT_RUNFROMSDRAM=y
CONFIG_BUILTIN=y CONFIG_BUILTIN=y
CONFIG_COREDUMP=y
CONFIG_DEBUG_ASSERTIONS=y CONFIG_DEBUG_ASSERTIONS=y
CONFIG_DEBUG_FEATURES=y CONFIG_DEBUG_FEATURES=y
CONFIG_DEBUG_FULLOPT=y CONFIG_DEBUG_FULLOPT=y
CONFIG_DEBUG_SYMBOLS=y CONFIG_DEBUG_SYMBOLS=y
CONFIG_DEV_ZERO=y CONFIG_DEV_ZERO=y
CONFIG_ELF=y
CONFIG_ELF_COREDUMP=y
CONFIG_EXAMPLES_HELLO=y CONFIG_EXAMPLES_HELLO=y
CONFIG_EXPERIMENTAL=y CONFIG_EXPERIMENTAL=y
CONFIG_FS_PROCFS=y CONFIG_FS_PROCFS=y

View file

@ -31,18 +31,14 @@
#include <spawn.h> #include <spawn.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/utsname.h>
#include <nuttx/sched.h> #include <nuttx/sched.h>
#include <nuttx/streams.h>
#include <nuttx/memoryregion.h>
/**************************************************************************** /****************************************************************************
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
#define BINFMT_NALLOC 4 #define BINFMT_NALLOC 4
#define COREDUMP_MAGIC 0x434f5245
/**************************************************************************** /****************************************************************************
* Public Types * Public Types
@ -138,22 +134,6 @@ struct binfmt_s
/* Unload module callback */ /* Unload module callback */
CODE int (*unload)(FAR struct binary_s *bin); CODE int (*unload)(FAR struct binary_s *bin);
/* Coredump callback */
CODE int (*coredump)(FAR const struct memory_region_s *regions,
FAR struct lib_outstream_s *stream,
pid_t pid);
};
/* Coredump information for block header */
struct coredump_info_s
{
uint32_t magic;
struct utsname name;
time_t time;
size_t size;
}; };
/**************************************************************************** /****************************************************************************
@ -209,23 +189,6 @@ int register_binfmt(FAR struct binfmt_s *binfmt);
int unregister_binfmt(FAR struct binfmt_s *binfmt); int unregister_binfmt(FAR struct binfmt_s *binfmt);
/****************************************************************************
* Name: core_dump
*
* Description:
* This function for generating core dump stream.
*
* Returned Value:
* This is a NuttX internal function so it follows the convention that
* 0 (OK) is returned on success and a negated errno is returned on
* failure.
*
****************************************************************************/
int core_dump(FAR const struct memory_region_s *regions,
FAR struct lib_outstream_s *stream,
pid_t pid);
/**************************************************************************** /****************************************************************************
* Name: load_module * Name: load_module
* *

View file

@ -129,19 +129,6 @@ struct elf_loadinfo_s
struct file file; /* Descriptor for the file being loaded */ struct file file; /* Descriptor for the file being loaded */
}; };
/* This struct provides a description of the dump information of
* memory regions.
*/
#ifdef CONFIG_ELF_COREDUMP
struct elf_dumpinfo_s
{
FAR const struct memory_region_s *regions;
FAR struct lib_outstream_s *stream;
pid_t pid;
};
#endif
/**************************************************************************** /****************************************************************************
* Public Function Prototypes * Public Function Prototypes
****************************************************************************/ ****************************************************************************/
@ -233,24 +220,6 @@ int elf_bind(FAR struct elf_loadinfo_s *loadinfo,
int elf_unload(FAR struct elf_loadinfo_s *loadinfo); int elf_unload(FAR struct elf_loadinfo_s *loadinfo);
/****************************************************************************
* Name: elf_coredump
*
* Description:
* Generat the core dump stream as ELF structure.
*
* Input Parameters:
* dumpinfo - elf coredump informations
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
#ifdef CONFIG_ELF_COREDUMP
int elf_coredump(FAR struct elf_dumpinfo_s *dumpinfo);
#endif
#undef EXTERN #undef EXTERN
#if defined(__cplusplus) #if defined(__cplusplus)
} }

View file

@ -27,9 +27,32 @@
* Included Files * Included Files
****************************************************************************/ ****************************************************************************/
#include <nuttx/memoryregion.h> #include <sys/utsname.h>
#include <unistd.h> #include <unistd.h>
#include <nuttx/streams.h>
#include <nuttx/memoryregion.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define COREDUMP_MAGIC 0x434f5245
/****************************************************************************
* Public Types
****************************************************************************/
/* Coredump information for block header */
struct coredump_info_s
{
uint32_t magic;
struct utsname name;
time_t time;
size_t size;
};
/**************************************************************************** /****************************************************************************
* Public Function Prototypes * Public Function Prototypes
****************************************************************************/ ****************************************************************************/
@ -54,4 +77,16 @@ int coredump_set_memory_region(FAR const struct memory_region_s *region);
int coredump_add_memory_region(FAR const void *ptr, size_t size); int coredump_add_memory_region(FAR const void *ptr, size_t size);
/****************************************************************************
* Name: coredump
*
* Description:
* This function for generating core dump stream.
*
****************************************************************************/
int coredump(FAR const struct memory_region_s *regions,
FAR struct lib_outstream_s *stream,
pid_t pid);
#endif /* __INCLUDE_NUTTX_COREDUMP_H */ #endif /* __INCLUDE_NUTTX_COREDUMP_H */

View file

@ -40,7 +40,7 @@
* Public Types * Public Types
****************************************************************************/ ****************************************************************************/
#ifdef CONFIG_ELF_COREDUMP #ifdef CONFIG_COREDUMP
typedef struct elf_prpsinfo_s typedef struct elf_prpsinfo_s
{ {
char pr_state; /* Numeric process state */ char pr_state; /* Numeric process state */

View file

@ -2047,3 +2047,15 @@ config ASSERT_PAUSE_CPU_TIMEOUT
---help--- ---help---
Timeout in milisecond to pause another CPU when assert. Only available Timeout in milisecond to pause another CPU when assert. Only available
when SMP is enabled. when SMP is enabled.
Enable to support perf events.
config COREDUMP
bool "Coredump support"
depends on ARCH_HAVE_TCBINFO
default n
---help---
Generate ELF core dump to provide information about the CPU state and the
memory state of program.
The memory state embeds a snapshot of all segments mapped in the
memory space of the program. The CPU state contains register values
when the core dump has been generated.

View file

@ -26,7 +26,7 @@ if(CONFIG_ARCH_DEADLOCKDUMP)
list(APPEND SRCS deadlock.c) list(APPEND SRCS deadlock.c)
endif() endif()
if(CONFIG_BOARD_COREDUMP_SYSLOG OR CONFIG_BOARD_COREDUMP_BLKDEV) if(CONFIG_COREDUMP)
list(APPEND SRCS coredump.c) list(APPEND SRCS coredump.c)
endif() endif()

View file

@ -26,7 +26,7 @@ ifeq ($(CONFIG_ARCH_DEADLOCKDUMP),y)
CSRCS += deadlock.c CSRCS += deadlock.c
endif endif
ifneq ($(CONFIG_BOARD_COREDUMP_SYSLOG)$(CONFIG_BOARD_COREDUMP_BLKDEV),) ifeq ($(CONFIG_COREDUMP),y)
CSRCS += coredump.c CSRCS += coredump.c
endif endif

View file

@ -24,15 +24,55 @@
* Included Files * Included Files
****************************************************************************/ ****************************************************************************/
#include <sys/stat.h>
#include <sys/param.h>
#include <syslog.h> #include <syslog.h>
#include <debug.h> #include <debug.h>
#include <nuttx/coredump.h>
#include <nuttx/elf.h>
#include <nuttx/sched.h>
#include "sched/sched.h"
#include "coredump.h" #include "coredump.h"
/**************************************************************************** /****************************************************************************
* Private Data * Private Data
****************************************************************************/ ****************************************************************************/
#ifdef PAGESIZE
# define ELF_PAGESIZE PAGESIZE
#else
# define ELF_PAGESIZE 1024
#endif
#define PROGRAM_ALIGNMENT 64
#define ROUNDUP(x, y) ((x + (y - 1)) / (y)) * (y)
#define ROUNDDOWN(x ,y) (((x) / (y)) * (y))
/****************************************************************************
* Private Types
****************************************************************************/
/* This struct provides a description of the dump information of
* memory regions.
*/
struct elf_dumpinfo_s
{
FAR const struct memory_region_s *regions;
FAR struct lib_outstream_s *stream;
pid_t pid;
};
/****************************************************************************
* Private Data
****************************************************************************/
static uint8_t g_running_regs[XCPTCONTEXT_SIZE] aligned_data(16);
#ifdef CONFIG_BOARD_COREDUMP_COMPRESSION #ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
static struct lib_lzfoutstream_s g_lzfstream; static struct lib_lzfoutstream_s g_lzfstream;
#endif #endif
@ -63,6 +103,521 @@ static const struct memory_region_s *g_regions;
* Private Functions * Private Functions
****************************************************************************/ ****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: elf_flush
*
* Description:
* Flush the out stream
*
****************************************************************************/
static int elf_flush(FAR struct elf_dumpinfo_s *cinfo)
{
return lib_stream_flush(cinfo->stream);
}
/****************************************************************************
* Name: elf_emit
*
* Description:
* Send the dump data to binfmt_outstream_s
*
****************************************************************************/
static int elf_emit(FAR struct elf_dumpinfo_s *cinfo,
FAR const void *buf, size_t len)
{
FAR const uint8_t *ptr = buf;
size_t total = len;
int ret;
while (total > 0)
{
ret = lib_stream_puts(cinfo->stream, ptr, total);
if (ret < 0)
{
break;
}
total -= ret;
ptr += ret;
}
return ret < 0 ? ret : len - total;
}
/****************************************************************************
* Name: elf_emit_align
*
* Description:
* Align the filled data according to the current offset
*
****************************************************************************/
static int elf_emit_align(FAR struct elf_dumpinfo_s *cinfo)
{
off_t align = ROUNDUP(cinfo->stream->nput,
ELF_PAGESIZE) - cinfo->stream->nput;
unsigned char null[256];
off_t total = align;
off_t ret;
memset(null, 0, sizeof(null));
while (total > 0)
{
ret = elf_emit(cinfo, null, total > sizeof(null) ?
sizeof(null) : total);
if (ret <= 0)
{
break;
}
total -= ret;
}
return ret < 0 ? ret : align;
}
/****************************************************************************
* Name: elf_emit_hdr
*
* Description:
* Fill the elf header
*
****************************************************************************/
static int elf_emit_hdr(FAR struct elf_dumpinfo_s *cinfo,
int segs)
{
Elf_Ehdr ehdr;
memset(&ehdr, 0, sizeof(ehdr));
memcpy(ehdr.e_ident, ELFMAG, EI_MAGIC_SIZE);
ehdr.e_ident[EI_CLASS] = ELF_CLASS;
ehdr.e_ident[EI_DATA] = ELF_DATA;
ehdr.e_ident[EI_VERSION] = EV_CURRENT;
ehdr.e_ident[EI_OSABI] = ELF_OSABI;
ehdr.e_type = ET_CORE;
ehdr.e_machine = EM_ARCH;
ehdr.e_version = EV_CURRENT;
ehdr.e_phoff = sizeof(Elf_Ehdr);
ehdr.e_flags = EF_FLAG;
ehdr.e_ehsize = sizeof(Elf_Ehdr);
ehdr.e_phentsize = sizeof(Elf_Phdr);
ehdr.e_phnum = segs;
return elf_emit(cinfo, &ehdr, sizeof(ehdr));
}
/****************************************************************************
* Name: elf_get_ntcb
*
* Description:
* Calculate the note segment size
*
****************************************************************************/
static int elf_get_ntcb(void)
{
int count = 0;
int i;
for (i = 0; i < g_npidhash; i++)
{
if (g_pidhash[i] != NULL)
{
count++;
}
}
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_tcb_note
*
* Description:
* Fill the note segment information from tcb
*
****************************************************************************/
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)];
elf_prstatus_t status;
elf_prpsinfo_t info;
FAR uintptr_t *regs;
Elf_Nhdr nhdr;
int i;
memset(&info, 0x0, sizeof(info));
memset(&status, 0x0, sizeof(status));
/* Fill Process info */
nhdr.n_namesz = sizeof(name);
nhdr.n_descsz = sizeof(info);
nhdr.n_type = NT_PRPSINFO;
elf_emit(cinfo, &nhdr, sizeof(nhdr));
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));
/* Fill Process status */
nhdr.n_descsz = sizeof(status);
nhdr.n_type = NT_PRSTATUS;
elf_emit(cinfo, &nhdr, sizeof(nhdr));
elf_emit(cinfo, name, sizeof(name));
status.pr_pid = tcb->pid;
if (running_task() == tcb)
{
if (up_interrupt_context())
{
regs = (FAR uintptr_t *)up_current_regs();
}
else
{
up_saveusercontext(g_running_regs);
regs = (FAR uintptr_t *)g_running_regs;
}
}
else
{
regs = (FAR uintptr_t *)tcb->xcp.regs;
}
if (regs != NULL)
{
for (i = 0; i < nitems(status.pr_regs); i++)
{
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]);
}
}
}
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)
{
elf_emit_tcb_note(cinfo, g_pidhash[i]);
}
}
}
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)
{
uintptr_t buf = 0;
uintptr_t sp;
size_t len;
if (running_task() != tcb)
{
sp = up_getusrsp(tcb->xcp.regs);
if (sp > (uintptr_t)tcb->stack_base_ptr &&
sp < (uintptr_t)tcb->stack_base_ptr + tcb->adj_stack_size)
{
len = ((uintptr_t)tcb->stack_base_ptr +
tcb->adj_stack_size) - sp;
buf = sp;
}
#ifdef CONFIG_STACK_COLORATION
else
{
len = up_check_tcbstack(tcb);
buf = (uintptr_t)tcb->stack_base_ptr +
(tcb->adj_stack_size - len);
}
#endif
}
if (buf == 0)
{
buf = (uintptr_t)tcb->stack_alloc_ptr;
len = tcb->adj_stack_size +
(tcb->stack_base_ptr - tcb->stack_alloc_ptr);
}
sp = ROUNDDOWN(buf, PROGRAM_ALIGNMENT);
len = ROUNDUP(len + (buf - sp), PROGRAM_ALIGNMENT);
buf = sp;
elf_emit(cinfo, (FAR void *)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)
{
elf_emit_tcb_stack(cinfo, g_pidhash[i]);
}
}
}
else
{
elf_emit_tcb_stack(cinfo, nxsched_get_tcb(cinfo->pid));
}
}
/****************************************************************************
* 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++)
{
if (cinfo->regions[i].flags & PF_REGISTER)
{
FAR uintptr_t *start = (FAR uintptr_t *)cinfo->regions[i].start;
FAR uintptr_t *end = (FAR uintptr_t *)cinfo->regions[i].end;
uintptr_t buf[64];
size_t offset = 0;
while (start < end)
{
buf[offset++] = *start++;
if (offset % (sizeof(buf) / sizeof(uintptr_t)) == 0)
{
elf_emit(cinfo, buf, sizeof(buf));
offset = 0;
}
}
if (offset != 0)
{
elf_emit(cinfo, buf, offset * sizeof(uintptr_t));
}
}
else
{
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_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)
{
uintptr_t sp;
phdr->p_vaddr = 0;
if (running_task() != tcb)
{
sp = up_getusrsp(tcb->xcp.regs);
if (sp > (uintptr_t)tcb->stack_base_ptr &&
sp < (uintptr_t)tcb->stack_base_ptr + tcb->adj_stack_size)
{
phdr->p_filesz = ((uintptr_t)tcb->stack_base_ptr +
tcb->adj_stack_size) - sp;
phdr->p_vaddr = sp;
}
#ifdef CONFIG_STACK_COLORATION
else
{
phdr->p_filesz = up_check_tcbstack(tcb);
phdr->p_vaddr = (uintptr_t)tcb->stack_base_ptr +
(tcb->adj_stack_size - phdr->p_filesz);
}
#endif
}
if (phdr->p_vaddr == 0)
{
phdr->p_vaddr = (uintptr_t)tcb->stack_alloc_ptr;
phdr->p_filesz = tcb->adj_stack_size +
(tcb->stack_base_ptr - tcb->stack_alloc_ptr);
}
sp = ROUNDDOWN(phdr->p_vaddr, PROGRAM_ALIGNMENT);
phdr->p_filesz = ROUNDUP(phdr->p_filesz +
(phdr->p_vaddr - sp), PROGRAM_ALIGNMENT);
phdr->p_vaddr = sp;
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_phdr(FAR struct elf_dumpinfo_s *cinfo,
int stksegs, int memsegs)
{
off_t offset = cinfo->stream->nput +
(stksegs + memsegs + 1) * sizeof(Elf_Phdr);
Elf_Phdr phdr;
int i;
memset(&phdr, 0, sizeof(Elf_Phdr));
phdr.p_type = PT_NOTE;
phdr.p_offset = offset;
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 < memsegs; i++)
{
phdr.p_type = PT_LOAD;
phdr.p_offset = ROUNDUP(offset, ELF_PAGESIZE);
phdr.p_vaddr = 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;
phdr.p_align = ELF_PAGESIZE;
offset += ROUNDUP(phdr.p_memsz, ELF_PAGESIZE);
elf_emit(cinfo, &phdr, sizeof(phdr));
}
}
/**************************************************************************** /****************************************************************************
* Name: coredump_dump_syslog * Name: coredump_dump_syslog
* *
@ -106,7 +661,7 @@ static void coredump_dump_syslog(pid_t pid)
/* Do core dump */ /* Do core dump */
core_dump(g_regions, stream, pid); coredump(g_regions, stream, pid);
# ifdef CONFIG_BOARD_COREDUMP_COMPRESSION # ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
_alert("Finish coredump (Compression Enabled). %s formatted\n", _alert("Finish coredump (Compression Enabled). %s formatted\n",
@ -161,7 +716,7 @@ static void coredump_dump_blkdev(pid_t pid)
stream = &g_lzfstream; stream = &g_lzfstream;
#endif #endif
ret = core_dump(g_regions, stream, pid); ret = coredump(g_regions, stream, pid);
if (ret < 0) if (ret < 0)
{ {
_alert("Coredump fail\n"); _alert("Coredump fail\n");
@ -352,3 +907,87 @@ void coredump_dump(pid_t pid)
coredump_dump_blkdev(pid); coredump_dump_blkdev(pid);
#endif #endif
} }
/****************************************************************************
* Name: coredump
*
* Description:
* This function for generating core dump stream.
*
****************************************************************************/
int coredump(FAR const struct memory_region_s *regions,
FAR struct lib_outstream_s *stream,
pid_t pid)
{
struct elf_dumpinfo_s cinfo;
irqstate_t flags;
int memsegs = 0;
int stksegs;
cinfo.regions = regions;
cinfo.stream = stream;
cinfo.pid = pid;
flags = enter_critical_section();
if (cinfo.pid != INVALID_PROCESS_ID)
{
if (nxsched_get_tcb(cinfo.pid) == NULL)
{
leave_critical_section(flags);
return -EINVAL;
}
stksegs = 1;
}
else
{
stksegs = elf_get_ntcb();
}
/* Check the memory region */
if (cinfo.regions != NULL)
{
for (; cinfo.regions[memsegs].start <
cinfo.regions[memsegs].end; memsegs++);
}
/* Fill notes section */
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_phdr(&cinfo, stksegs, memsegs);
/* Fill note information */
elf_emit_note(&cinfo);
/* Align to page */
elf_emit_align(&cinfo);
/* Dump stack */
elf_emit_stack(&cinfo);
/* Dump memory segments */
if (memsegs > 0)
{
elf_emit_memory(&cinfo, memsegs);
}
/* Flush the dump */
elf_flush(&cinfo);
leave_critical_section(flags);
return OK;
}