forked from nuttx/nuttx-update
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:
parent
9e868cadfb
commit
52126aede1
20 changed files with 697 additions and 879 deletions
|
@ -16,9 +16,7 @@ Enable Kconfig
|
|||
|
||||
.. code-block:: console
|
||||
|
||||
CONFIG_ELF=y /* Enable ELF */
|
||||
|
||||
CONFIG_ELF_COREDUMP=y /* Enable ELF Coredump */
|
||||
CONFIG_COREDUMP=y /* Enable Coredump */
|
||||
|
||||
CONFIG_BOARD_COREDUMP_SYSLOG=y /* Enable Board Coredump, if exceptions and assertions occur, */
|
||||
|
||||
|
|
|
@ -39,8 +39,7 @@ list(
|
|||
binfmt_exec.c
|
||||
binfmt_copyargv.c
|
||||
binfmt_copyactions.c
|
||||
binfmt_dumpmodule.c
|
||||
binfmt_coredump.c)
|
||||
binfmt_dumpmodule.c)
|
||||
|
||||
if(CONFIG_BINFMT_LOADABLE)
|
||||
list(APPEND SRCS binfmt_exit.c)
|
||||
|
|
|
@ -27,7 +27,6 @@ include $(TOPDIR)/Make.defs
|
|||
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_exec.c binfmt_copyargv.c binfmt_copyactions.c binfmt_dumpmodule.c
|
||||
CSRCS += binfmt_coredump.c
|
||||
|
||||
ifeq ($(CONFIG_BINFMT_LOADABLE),y)
|
||||
CSRCS += binfmt_exit.c
|
||||
|
|
|
@ -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 */
|
34
binfmt/elf.c
34
binfmt/elf.c
|
@ -69,11 +69,6 @@ static int elf_loadbinary(FAR struct binary_s *binp,
|
|||
FAR const char *filename,
|
||||
FAR const struct symtab_s *exports,
|
||||
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)
|
||||
static void elf_dumploadinfo(FAR struct elf_loadinfo_s *loadinfo);
|
||||
#endif
|
||||
|
@ -87,9 +82,6 @@ static struct binfmt_s g_elfbinfmt =
|
|||
NULL, /* next */
|
||||
elf_loadbinary, /* load */
|
||||
NULL, /* unload */
|
||||
#ifdef CONFIG_ELF_COREDUMP
|
||||
elf_dumpbinary, /* coredump */
|
||||
#endif
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -370,32 +362,6 @@ errout_with_init:
|
|||
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
|
||||
****************************************************************************/
|
||||
|
|
|
@ -40,11 +40,6 @@ if(CONFIG_ELF)
|
|||
libelf_unload.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)
|
||||
list(APPEND SRCS libelf_ctors.c libelf_dtors.c)
|
||||
endif()
|
||||
|
|
|
@ -63,17 +63,6 @@ config ELF_SYMBOL_CACHECOUNT
|
|||
This is a cache that is used to store elf symbol table to
|
||||
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
|
||||
bool "ELF load sections to LMA"
|
||||
default n
|
||||
|
|
|
@ -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_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)
|
||||
CSRCS += libelf_ctors.c libelf_dtors.c
|
||||
endif
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -81,7 +81,6 @@ static struct binfmt_s g_nxflatbinfmt =
|
|||
NULL, /* next */
|
||||
nxflat_loadbinary, /* load */
|
||||
nxflat_unloadbinary, /* unload */
|
||||
NULL, /* coredump */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
@ -4634,14 +4634,14 @@ config BOARD_CRASHDUMP
|
|||
config BOARD_COREDUMP_SYSLOG
|
||||
bool "Enable Core dump to syslog"
|
||||
default n
|
||||
depends on ELF_COREDUMP
|
||||
depends on COREDUMP
|
||||
---help---
|
||||
Enable put coredump to syslog when crash.
|
||||
|
||||
config BOARD_COREDUMP_BLKDEV
|
||||
bool "Enable Core Dump to block device"
|
||||
default n
|
||||
depends on ELF_COREDUMP
|
||||
depends on COREDUMP
|
||||
---help---
|
||||
Enable save coredump at block device when crash.
|
||||
|
||||
|
|
|
@ -21,13 +21,12 @@ CONFIG_BOARD_COREDUMP_SYSLOG=y
|
|||
CONFIG_BOARD_LOOPSPERMSEC=99369
|
||||
CONFIG_BOOT_RUNFROMSDRAM=y
|
||||
CONFIG_BUILTIN=y
|
||||
CONFIG_COREDUMP=y
|
||||
CONFIG_DEBUG_ASSERTIONS=y
|
||||
CONFIG_DEBUG_FEATURES=y
|
||||
CONFIG_DEBUG_FULLOPT=y
|
||||
CONFIG_DEBUG_SYMBOLS=y
|
||||
CONFIG_DEV_ZERO=y
|
||||
CONFIG_ELF=y
|
||||
CONFIG_ELF_COREDUMP=y
|
||||
CONFIG_EXAMPLES_HELLO=y
|
||||
CONFIG_EXPERIMENTAL=y
|
||||
CONFIG_FS_PROCFS=y
|
||||
|
|
|
@ -31,18 +31,14 @@
|
|||
|
||||
#include <spawn.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include <nuttx/sched.h>
|
||||
#include <nuttx/streams.h>
|
||||
#include <nuttx/memoryregion.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define BINFMT_NALLOC 4
|
||||
#define COREDUMP_MAGIC 0x434f5245
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
|
@ -138,22 +134,6 @@ struct binfmt_s
|
|||
/* Unload module callback */
|
||||
|
||||
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);
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
*
|
||||
|
|
|
@ -129,19 +129,6 @@ struct elf_loadinfo_s
|
|||
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
|
||||
****************************************************************************/
|
||||
|
@ -233,24 +220,6 @@ int elf_bind(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
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
|
|
|
@ -27,9 +27,32 @@
|
|||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/memoryregion.h>
|
||||
#include <sys/utsname.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
|
||||
****************************************************************************/
|
||||
|
@ -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);
|
||||
|
||||
/****************************************************************************
|
||||
* 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 */
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_ELF_COREDUMP
|
||||
#ifdef CONFIG_COREDUMP
|
||||
typedef struct elf_prpsinfo_s
|
||||
{
|
||||
char pr_state; /* Numeric process state */
|
||||
|
|
|
@ -2047,3 +2047,15 @@ config ASSERT_PAUSE_CPU_TIMEOUT
|
|||
---help---
|
||||
Timeout in milisecond to pause another CPU when assert. Only available
|
||||
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.
|
||||
|
|
|
@ -26,7 +26,7 @@ if(CONFIG_ARCH_DEADLOCKDUMP)
|
|||
list(APPEND SRCS deadlock.c)
|
||||
endif()
|
||||
|
||||
if(CONFIG_BOARD_COREDUMP_SYSLOG OR CONFIG_BOARD_COREDUMP_BLKDEV)
|
||||
if(CONFIG_COREDUMP)
|
||||
list(APPEND SRCS coredump.c)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ ifeq ($(CONFIG_ARCH_DEADLOCKDUMP),y)
|
|||
CSRCS += deadlock.c
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_BOARD_COREDUMP_SYSLOG)$(CONFIG_BOARD_COREDUMP_BLKDEV),)
|
||||
ifeq ($(CONFIG_COREDUMP),y)
|
||||
CSRCS += coredump.c
|
||||
endif
|
||||
|
||||
|
|
|
@ -24,15 +24,55 @@
|
|||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <syslog.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/coredump.h>
|
||||
#include <nuttx/elf.h>
|
||||
#include <nuttx/sched.h>
|
||||
|
||||
#include "sched/sched.h"
|
||||
#include "coredump.h"
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
static struct lib_lzfoutstream_s g_lzfstream;
|
||||
#endif
|
||||
|
@ -63,6 +103,521 @@ static const struct memory_region_s *g_regions;
|
|||
* 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
|
||||
*
|
||||
|
@ -106,7 +661,7 @@ static void coredump_dump_syslog(pid_t pid)
|
|||
|
||||
/* Do core dump */
|
||||
|
||||
core_dump(g_regions, stream, pid);
|
||||
coredump(g_regions, stream, pid);
|
||||
|
||||
# ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
|
||||
_alert("Finish coredump (Compression Enabled). %s formatted\n",
|
||||
|
@ -161,7 +716,7 @@ static void coredump_dump_blkdev(pid_t pid)
|
|||
stream = &g_lzfstream;
|
||||
#endif
|
||||
|
||||
ret = core_dump(g_regions, stream, pid);
|
||||
ret = coredump(g_regions, stream, pid);
|
||||
if (ret < 0)
|
||||
{
|
||||
_alert("Coredump fail\n");
|
||||
|
@ -352,3 +907,87 @@ void coredump_dump(pid_t pid)
|
|||
coredump_dump_blkdev(pid);
|
||||
#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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue