nuttx/sched/misc/coredump.c
anjiahao 35051dd715 coredump: support coredump save to block device when crash
Signed-off-by: anjiahao <anjiahao@xiaomi.com>
2023-12-10 07:02:03 -08:00

229 lines
6.1 KiB
C

/****************************************************************************
* 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
}