coredump: support coredump save to block device when crash

Signed-off-by: anjiahao <anjiahao@xiaomi.com>
This commit is contained in:
anjiahao 2023-11-09 12:02:37 +08:00 committed by Xiang Xiao
parent 542a5555d3
commit 35051dd715
12 changed files with 441 additions and 71 deletions

View File

@ -20,7 +20,7 @@ Enable Kconfig
CONFIG_ELF_COREDUMP=y /* Enable ELF Coredump */ CONFIG_ELF_COREDUMP=y /* Enable ELF Coredump */
CONFIG_BOARD_COREDUMP=y /* Enable Board Coredump, if exceptions and assertions occur, */ CONFIG_BOARD_COREDUMP_SYSLOG=y /* Enable Board Coredump, if exceptions and assertions occur, */
CONFIG_SYSTEM_COREDUMP=y /* Enable coredump in user command, which can capture the current CONFIG_SYSTEM_COREDUMP=y /* Enable coredump in user command, which can capture the current
state of one or all threads when the system is running, the state of one or all threads when the system is running, the

View File

@ -4366,18 +4366,30 @@ config BOARD_CRASHDUMP
"machine state" in a place where on the next reset can write it "machine state" in a place where on the next reset can write it
to more sophisticated storage in a sane operating environment. to more sophisticated storage in a sane operating environment.
config BOARD_COREDUMP config BOARD_COREDUMP_SYSLOG
bool "Enable Core Dump after assert" bool "Enable Core dump to syslog"
default n default n
depends on ELF_COREDUMP depends on ELF_COREDUMP
---help--- ---help---
Enable to support for the dump core information after assert. Enable put coredump to syslog when crash.
if BOARD_COREDUMP config BOARD_COREDUMP_BLKDEV
bool "Enable Core Dump to block device"
default n
depends on ELF_COREDUMP
---help---
Enable save coredump at block device when crash.
config BOARD_COREDUMP_BLKDEV_PATH
string "Save Core Dump block device PATH"
depends on BOARD_COREDUMP_BLKDEV
---help---
Save coredump file block device path.
config BOARD_COREDUMP_FULL config BOARD_COREDUMP_FULL
bool "Core Dump all thread registers and stacks" bool "Core Dump all thread registers and stacks"
default y default y
depends on BOARD_COREDUMP_SYSLOG || BOARD_COREDUMP_BLKDEV
---help--- ---help---
Enable to support for the dump all task registers and stacks. Enable to support for the dump all task registers and stacks.
@ -4385,11 +4397,10 @@ config BOARD_COREDUMP_COMPRESSION
bool "Enable Core Dump compression" bool "Enable Core Dump compression"
default y default y
select LIBC_LZF select LIBC_LZF
depends on BOARD_COREDUMP_SYSLOG || BOARD_COREDUMP_BLKDEV
---help--- ---help---
Enable LZF compression algorithm for core dump content Enable LZF compression algorithm for core dump content
endif # BOARD_COREDUMP
config BOARD_ENTROPY_POOL config BOARD_ENTROPY_POOL
bool "Enable Board level storing of entropy pool structure" bool "Enable Board level storing of entropy pool structure"
default n default n

View File

@ -17,7 +17,7 @@ CONFIG_ARCH_INTERRUPTSTACK=2048
CONFIG_ARCH_IRQBUTTONS=y CONFIG_ARCH_IRQBUTTONS=y
CONFIG_ARCH_LOWVECTORS=y CONFIG_ARCH_LOWVECTORS=y
CONFIG_ARCH_STACKDUMP=y CONFIG_ARCH_STACKDUMP=y
CONFIG_BOARD_COREDUMP=y 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

View File

@ -29,6 +29,7 @@
#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/streams.h>
@ -38,7 +39,8 @@
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
#define BINFMT_NALLOC 4 #define BINFMT_NALLOC 4
#define COREDUMP_MAGIC 0x434f5245
/**************************************************************************** /****************************************************************************
* Public Types * Public Types
@ -138,6 +140,16 @@ struct binfmt_s
pid_t pid); pid_t pid);
}; };
/* Coredump information for block header */
struct coredump_info_s
{
uint32_t magic;
struct utsname name;
time_t time;
size_t size;
};
/**************************************************************************** /****************************************************************************
* Public Data * Public Data
****************************************************************************/ ****************************************************************************/

View File

@ -63,4 +63,34 @@ ssize_t parse_memory_region(FAR const char *format,
FAR struct memory_region_s *region, FAR struct memory_region_s *region,
size_t num); size_t num);
/****************************************************************************
* Name: alloc_memory_region
*
* Input Parameters:
* format - The format string to parse. <start>,<end>,<flags>,...
* start - The start address of the memory region
* end - The end address of the memory region
* flags - Readable 0x1, writable 0x2, executable 0x4
* example: 0x1000,0x2000,0x1,0x2000,0x3000,0x3,0x3000,0x4000,0x7
*
* Return:
* The parsed memory region list on success; NULL on failure.
* The boundary value of the memory region is zero.
* The return value need free by caller.
*
****************************************************************************/
FAR struct memory_region_s *
alloc_memory_region(FAR const char *format);
/****************************************************************************
* Name: free_memory_region
*
* Input Parameters:
* region - The memory region list to free.
*
****************************************************************************/
void free_memory_region(FAR struct memory_region_s *region);
#endif /* __INCLUDE_MEMORYREGION_H */ #endif /* __INCLUDE_MEMORYREGION_H */

View File

@ -23,6 +23,7 @@
****************************************************************************/ ****************************************************************************/
#include <nuttx/memoryregion.h> #include <nuttx/memoryregion.h>
#include <nuttx/lib/lib.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
@ -52,11 +53,28 @@ ssize_t parse_memory_region(FAR const char *format,
FAR char *endptr; FAR char *endptr;
size_t i = 0; size_t i = 0;
if (format == NULL || region == NULL || num == 0) if (format == NULL)
{ {
return -EINVAL; return -EINVAL;
} }
if (num == 0 || region == NULL)
{
num = 0;
while (format[i] != '\0')
{
if (format[i++] == ',')
{
num++;
}
}
}
if (region == NULL)
{
return num / 3 + 1;
}
while (*format != '\0' && i < num * 3) while (*format != '\0' && i < num * 3)
{ {
if (i % 3 == 0) if (i % 3 == 0)
@ -78,3 +96,57 @@ ssize_t parse_memory_region(FAR const char *format,
return i / 3; return i / 3;
} }
/****************************************************************************
* Name: alloc_memory_region
*
* Input Parameters:
* format - The format string to parse. <start>,<end>,<flags>,...
* start - The start address of the memory region
* end - The end address of the memory region
* flags - Readable 0x1, writable 0x2, executable 0x4
* example: 0x1000,0x2000,0x1,0x2000,0x3000,0x3,0x3000,0x4000,0x7
*
* Return:
* The parsed memory region list on success; NULL on failure.
* The boundary value of the memory region is zero.
* The return value need free by caller.
*
****************************************************************************/
FAR struct memory_region_s *
alloc_memory_region(FAR const char *format)
{
FAR struct memory_region_s *region;
ssize_t num = parse_memory_region(format, NULL, 0);
if (num < 0)
{
return NULL;
}
region = lib_zalloc(sizeof(struct memory_region_s) * (num + 1));
if (region == NULL)
{
return NULL;
}
parse_memory_region(format, region, num);
return region;
}
/****************************************************************************
* Name: free_memory_region
*
* Input Parameters:
* region - The memory region list to free.
*
****************************************************************************/
void free_memory_region(FAR struct memory_region_s *region)
{
if (region != NULL)
{
lib_free(region);
}
}

View File

@ -48,6 +48,7 @@
#include "sched/sched.h" #include "sched/sched.h"
#include "wqueue/wqueue.h" #include "wqueue/wqueue.h"
#include "init/init.h" #include "init/init.h"
#include "misc/coredump.h"
/**************************************************************************** /****************************************************************************
* Pre-processor Definitions * Pre-processor Definitions
@ -248,6 +249,11 @@ static inline void nx_start_application(void)
board_late_initialize(); board_late_initialize();
#endif #endif
#if defined(CONFIG_BOARD_COREDUMP_SYSLOG) || \
defined(CONFIG_BOARD_COREDUMP_BLKDEV)
coredump_initialize();
#endif
posix_spawnattr_init(&attr); posix_spawnattr_init(&attr);
attr.priority = CONFIG_INIT_PRIORITY; attr.priority = CONFIG_INIT_PRIORITY;
attr.stacksize = CONFIG_INIT_STACKSIZE; attr.stacksize = CONFIG_INIT_STACKSIZE;

View File

@ -28,4 +28,8 @@ if(CONFIG_DUMP_ON_EXIT)
list(APPEND SRCS dump.c) list(APPEND SRCS dump.c)
endif() endif()
if(CONFIG_BOARD_COREDUMP_SYSLOG OR CONFIG_BOARD_COREDUMP_BLKDEV)
list(APPEND SRCS coredump.c)
endif()
target_sources(sched PRIVATE ${SRCS}) target_sources(sched PRIVATE ${SRCS})

View File

@ -28,6 +28,10 @@ ifeq ($(CONFIG_DUMP_ON_EXIT),y)
CSRCS += dump.c CSRCS += dump.c
endif endif
ifneq ($(CONFIG_BOARD_COREDUMP_SYSLOG)$(CONFIG_BOARD_COREDUMP_BLKDEV),)
CSRCS += coredump.c
endif
# Include init build support # Include init build support
DEPPATH += --dep-path misc DEPPATH += --dep-path misc

View File

@ -25,7 +25,6 @@
#include <nuttx/config.h> #include <nuttx/config.h>
#include <nuttx/arch.h> #include <nuttx/arch.h>
#include <nuttx/binfmt/binfmt.h>
#include <nuttx/board.h> #include <nuttx/board.h>
#include <nuttx/irq.h> #include <nuttx/irq.h>
#include <nuttx/tls.h> #include <nuttx/tls.h>
@ -47,6 +46,7 @@
#include "irq/irq.h" #include "irq/irq.h"
#include "sched/sched.h" #include "sched/sched.h"
#include "group/group.h" #include "group/group.h"
#include "misc/coredump.h"
/**************************************************************************** /****************************************************************************
* Pre-processor Definitions * Pre-processor Definitions
@ -77,15 +77,6 @@
****************************************************************************/ ****************************************************************************/
static uintptr_t g_last_regs[XCPTCONTEXT_REGS] aligned_data(16); static uintptr_t g_last_regs[XCPTCONTEXT_REGS] aligned_data(16);
#ifdef CONFIG_BOARD_COREDUMP
static struct lib_syslogstream_s g_syslogstream;
static struct lib_hexdumpstream_s g_hexstream;
# ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
static struct lib_lzfoutstream_s g_lzfstream;
# endif
#endif
static FAR const char *g_policy[4] = static FAR const char *g_policy[4] =
{ {
"FIFO", "RR", "SPORADIC" "FIFO", "RR", "SPORADIC"
@ -481,53 +472,6 @@ static void dump_tasks(void)
#endif #endif
} }
/****************************************************************************
* Name: dump_core
****************************************************************************/
#ifdef CONFIG_BOARD_COREDUMP
static void dump_core(pid_t pid)
{
FAR void *stream;
int logmask;
logmask = setlogmask(LOG_ALERT);
_alert("Start coredump:\n");
/* Initialize hex output stream */
lib_syslogstream(&g_syslogstream, LOG_EMERG);
stream = &g_syslogstream;
lib_hexdumpstream(&g_hexstream, stream);
stream = &g_hexstream;
# ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
/* Initialize LZF compression stream */
lib_lzfoutstream(&g_lzfstream, stream);
stream = &g_lzfstream;
# endif
/* Do core dump */
core_dump(NULL, stream, pid);
# ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
_alert("Finish coredump (Compression Enabled).\n");
# else
_alert("Finish coredump.\n");
# endif
setlogmask(logmask);
}
#endif
/**************************************************************************** /****************************************************************************
* Name: dump_deadlock * Name: dump_deadlock
****************************************************************************/ ****************************************************************************/
@ -681,16 +625,17 @@ void _assert(FAR const char *filename, int linenum,
#ifdef CONFIG_BOARD_CRASHDUMP #ifdef CONFIG_BOARD_CRASHDUMP
board_crashdump(up_getsp(), rtcb, filename, linenum, msg, regs); board_crashdump(up_getsp(), rtcb, filename, linenum, msg, regs);
#endif
#elif defined(CONFIG_BOARD_COREDUMP) #if defined(CONFIG_BOARD_COREDUMP_SYSLOG) || \
defined(CONFIG_BOARD_COREDUMP_BLKDEV)
/* Dump core information */ /* Dump core information */
# ifdef CONFIG_BOARD_COREDUMP_FULL # ifdef CONFIG_BOARD_COREDUMP_FULL
dump_core(INVALID_PROCESS_ID); coredump_dump(INVALID_PROCESS_ID);
# else # else
dump_core(rtcb->pid); coredump_dump(rtcb->pid);
# endif # endif
#endif #endif
/* Flush any buffered SYSLOG data */ /* Flush any buffered SYSLOG data */

228
sched/misc/coredump.c Normal file
View File

@ -0,0 +1,228 @@
/****************************************************************************
* sched/misc/coredump.c
*
* 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/binfmt/binfmt.h>
#include <syslog.h>
#include <debug.h>
#include "misc/coredump.h"
/****************************************************************************
* Private Data
****************************************************************************/
#ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
static struct lib_lzfoutstream_s g_lzfstream;
#endif
#ifdef CONFIG_BOARD_COREDUMP_SYSLOG
static struct lib_syslogstream_s g_syslogstream;
static struct lib_hexdumpstream_s g_hexstream;
#endif
#ifdef CONFIG_BOARD_COREDUMP_BLKDEV
static struct lib_blkoutstream_s g_blockstream;
static unsigned char *g_blockinfo;
#endif
static struct memory_region_s *g_regions;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: coredump_dump_syslog
*
* Description:
* Put coredump to block device.
*
****************************************************************************/
#ifdef CONFIG_BOARD_COREDUMP_SYSLOG
static void coredump_dump_syslog(pid_t pid)
{
FAR void *stream;
int logmask;
logmask = setlogmask(LOG_ALERT);
_alert("Start coredump:\n");
/* Initialize hex output stream */
lib_syslogstream(&g_syslogstream, LOG_EMERG);
stream = &g_syslogstream;
lib_hexdumpstream(&g_hexstream, stream);
stream = &g_hexstream;
# ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
/* Initialize LZF compression stream */
lib_lzfoutstream(&g_lzfstream, stream);
stream = &g_lzfstream;
# endif
/* Do core dump */
core_dump(g_regions, stream, pid);
# ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
_alert("Finish coredump (Compression Enabled).\n");
# else
_alert("Finish coredump.\n");
# endif
setlogmask(logmask);
}
#endif
/****************************************************************************
* Name: coredump_dump_blkdev
*
* Description:
* Save coredump to block device.
*
****************************************************************************/
#ifdef CONFIG_BOARD_COREDUMP_BLKDEV
static void coredump_dump_blkdev(pid_t pid)
{
FAR void *stream = &g_blockstream;
FAR struct coredump_info_s *info;
int ret;
if (g_blockstream.inode == NULL)
{
_alert("Coredump Device Not Found\n");
return;
}
ret = g_blockstream.inode->u.i_bops->read(g_blockstream.inode,
g_blockinfo, g_blockstream.geo.geo_nsectors - 1, 1);
if (ret < 0)
{
_alert("Coredump Device Read Fail\n");
return;
}
info = (FAR struct coredump_info_s *)g_blockinfo;
if (info->magic == COREDUMP_MAGIC)
{
_alert("Coredump Device Already Used\n");
return;
}
#ifdef CONFIG_BOARD_COREDUMP_COMPRESSION
lib_lzfoutstream(&g_lzfstream,
(FAR struct lib_outstream_s *)&g_blockstream);
stream = &g_lzfstream;
#endif
ret = core_dump(g_regions, stream, pid);
if (ret < 0)
{
_alert("Coredump Fail\n");
return;
}
info->magic = COREDUMP_MAGIC;
info->size = g_blockstream.common.nput;
info->time = time(NULL);
uname(&info->name);
g_blockstream.inode->u.i_bops->write(g_blockstream.inode,
(FAR void *)info, g_blockstream.geo.geo_nsectors - 1, 1);
}
#endif
/****************************************************************************
* Name: coredump_initialize
*
* Description:
* Initialize the coredump facility. Called once and only from
* nx_start_application.
*
****************************************************************************/
int coredump_initialize(void)
{
int ret = 0;
if (CONFIG_BOARD_MEMORY_RANGE[0] != '\0')
{
g_regions = alloc_memory_region(CONFIG_BOARD_MEMORY_RANGE);
if (g_regions == NULL)
{
_alert("Memory Region Alloc Fail\n");
return -ENOMEM;
}
}
#ifdef CONFIG_BOARD_COREDUMP_BLKDEV
ret = lib_blkoutstream_open(&g_blockstream,
CONFIG_BOARD_COREDUMP_BLKDEV_PATH);
if (ret < 0)
{
_alert("%s Coredump Device Not Found\n",
CONFIG_BOARD_COREDUMP_BLKDEV_PATH);
free_memory_region(g_regions);
g_regions = NULL;
return ret;
}
g_blockinfo = kmm_malloc(g_blockstream.geo.geo_sectorsize);
if (g_blockinfo == NULL)
{
_alert("Coredump Device Memory Alloc Fail\n");
free_memory_region(g_regions);
g_regions = NULL;
lib_blkoutstream_close(&g_blockstream);
return -ENOMEM;
}
#endif
return ret;
}
/****************************************************************************
* Name: coredump_dump
*
* Description:
* Do coredump of the task specified by pid.
*
* Input Parameters:
* pid - The task/thread ID of the thread to dump
*
****************************************************************************/
void coredump_dump(pid_t pid)
{
#ifdef CONFIG_BOARD_COREDUMP_SYSLOG
coredump_dump_syslog(pid);
#endif
#ifdef CONFIG_BOARD_COREDUMP_BLKDEV
coredump_dump_blkdev(pid);
#endif
}

58
sched/misc/coredump.h Normal file
View File

@ -0,0 +1,58 @@
/****************************************************************************
* sched/misc/coredump.h
*
* 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.
*
****************************************************************************/
#ifndef __SCHED_MISC_COREDUMP_H
#define __SCHED_MISC_COREDUMP_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <unistd.h>
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: coredump_initialize
*
* Description:
* Initialize the coredump facility. Called once and only from
* nx_start_application.
*
****************************************************************************/
int coredump_initialize(void);
/****************************************************************************
* Name: coredump_dump
*
* Description:
* Do coredump of the task specified by pid.
*
* Input Parameters:
* pid - The task/thread ID of the thread to dump
*
****************************************************************************/
void coredump_dump(pid_t pid);
#endif /* __SCHED_MISC_COREDUMP_H */