SylixOS内核的cdump功能

2023-11-03 06:18
文章标签 功能 内核 sylixos cdump

本文主要是介绍SylixOS内核的cdump功能,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

概念

cdump即CrashDump(奔溃信息转储),就是在紧急情况下存储故障信息,待系统恢复时还能读取或存入文件系统。

来由

当系统奔溃时,一般会通过串口控制台将奔溃信息(如当前寄存器值,线程名称,出错原因等)输出,以供开发人员对故障进行定位和分析。但有时的奔溃情况非常严重,不能或不便于通过串口输出,其他通信方式或磁盘访问也不能正常调用,此时就可以先把奔溃信息记录到指定内存中,等系统恢复或复位后再从指定内存读出或记录。这也是系统尽最大可能去保存奔溃信息的方法了。

大部分情况下cdump还是能起效的,这在于即便是很严重的奔溃,一般不会完全断电,内存一般也还是能正常的可访问的,且访问内存的速度非常快。但也可能达不到效果,比如指定内存在DDR内存空间中,DDR控制器故障或者重启后重新初始化了DDR内存,或则系统完全掉电,都会使得奔溃信息丢失。再有就是奔溃后CPU极快就被复位或停止了,没有足够的时间去进行保存操作。所以配置cdump的存储地址时,最好是选用同在SOC中的紧耦合内存(TCM)来存储,速度快,无需初始化控制器,也不需要太大空间,默认是2KB。

用法

首先在系统编译时,要保证 LW_CFG_CDUMP_ENLW_CFG_DEVICE_EN 配置宏都使能才会启用cdump功能。这两个配置宏位于libsylixos\SylixOS\config\system\system_cfg.h文件中,启停cdump功能只修改 LW_CFG_CDUMP_EN 宏即可。

系统默认的cdump存储空间大小是2KB,位于内核堆的末尾。通过内置的cdump命令即可显示或存储奔溃信息,存储文件名为 /var/log/cdump/ + UTC时间
在这里插入图片描述
以上是系统默认的配置或操作接口,系统同时也提供了3个API接口函数,供开发者编程定制。

  1. 设置存储地址及大小。
/*********************************************************************************************************
** 函数名称: API_CrashDumpBuffer
** 功能描述: 重新定位系统/应用崩溃信息记录位置. (必须是内核能访问的地址)
** 输 入  : pvCdump           缓冲地址
**           stSize            缓冲大小
** 输 出  : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
INT  API_CrashDumpBuffer (PVOID  pvCdump, size_t  stSize);
  1. 保存到指定文件。
/*********************************************************************************************************
** 函数名称: API_CrashDumpSave
** 功能描述: 最近一次系统/应用崩溃信息保存入文件.
** 输 入  : pcLogFile         日志文件名
**           iFlag             open 第二个参数
**           iMode             open 第三个参数
**           bClear            成功保存后是否清空缓冲区
** 输 出  : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
INT  API_CrashDumpSave (CPCHAR  pcLogFile, INT  iFlag, INT  iMode, BOOL  bClear);
  1. 通过指定文件输出显示,一般是标准输出文件。
/*********************************************************************************************************
** 函数名称: API_CrashDumpShow
** 功能描述: 显示最近一次系统/应用崩溃信息.
** 输 入  : iFd               打印文件描述符
**           bClear            是否清空缓冲区
** 输 出  : ERROR_NONE or PX_ERROR
*********************************************************************************************************/ 
INT  API_CrashDumpShow (INT  iFd, BOOL  bClear);

实现

cdump功能的实现代码主要位于 libsylixos\SylixOS\kernel\cdump 文件夹中。

基本配置

#define LW_CFG_CDUMP_EN                         1       /*  是否允许系统/应用崩溃信息暂存               */
#define LW_CFG_CDUMP_BUF_SIZE                   2048    /*  缓存大小                                    */
#define LW_CFG_CDUMP_CALL_STACK_DEPTH           20      /*  调用栈深度                                  */

默认位置及大小
这里决定了cdump的默认存储空间位于内核堆的末尾2KB空间。

/*********************************************************************************************************崩溃信息暂存配置
*********************************************************************************************************/
#if LW_CFG_CDUMP_EN > 0
#define LW_KERNEL_HEAP_START(a)     ((PVOID)a)
#define LW_KERNEL_HEAP_SIZE(s)      ((size_t)s - LW_CFG_CDUMP_BUF_SIZE)
#define LW_KERNEL_CDUMP_START(a, s) ((PVOID)((addr_t)a + LW_KERNEL_HEAP_SIZE(s)))
#define LW_KERNEL_CDUMP_SIZE(s)     LW_CFG_CDUMP_BUF_SIZE
#else
#define LW_KERNEL_HEAP_START(a)     ((PVOID)a)
#define LW_KERNEL_HEAP_SIZE(s)      ((size_t)s)
#endif

魔数头定义
奔溃信息在存储时前4字节是一个特征魔数,用于表征是否已存储及存储收正常。后面这是根据不同奔溃状态的信息字符串。

/*********************************************************************************************************宏定义
*********************************************************************************************************/
#define LW_CDUMP_MAGIC_0    0xab
#define LW_CDUMP_MAGIC_1    0x56
#define LW_CDUMP_MAGIC_2    0xef
#define LW_CDUMP_MAGIC_3    0x33
#define LW_CDUMP_MAGIC_LEN  4

存储区地址及长度全局变量定义及相关基本操作

static PVOID  _K_pvCrashDumpBuffer = (PVOID)PX_ERROR;
static size_t _K_stCrashDumpSize   = LW_CFG_CDUMP_BUF_SIZE;#define LW_CDUMP_BUF_SIZE   (_K_stCrashDumpSize)
#define LW_CDUMP_MAX_LEN    (LW_CDUMP_BUF_SIZE - 1)VOID  _CrashDumpSet (PVOID  pvCdump, size_t  stSize)
{_K_pvCrashDumpBuffer = pvCdump;_K_stCrashDumpSize   = stSize;
}PVOID  _CrashDumpGet (size_t  *pstSize)
{*pstSize = _K_stCrashDumpSize;return  (_K_pvCrashDumpBuffer);
}

奔溃时不同类型的存储信息调用接口,这些接口只会被内核调用。

/*********************************************************************************************************
** 函数名称: _CrashDumpAbortStkOf
** 功能描述: 堆栈溢出崩溃信息记录.
** 输 入  : ulRetAddr     异常返回 PC 地址
**           ulAbortAddr   异常地址
**           pcInfo        异常信息
**           ptcb          异常任务
** 输 出  : NONE
*********************************************************************************************************/
VOID  _CrashDumpAbortStkOf (addr_t  ulRetAddr, addr_t  ulAbortAddr, CPCHAR  pcInfo, PLW_CLASS_TCB  ptcb)
{PCHAR   pcCdump = (PCHAR)_K_pvCrashDumpBuffer;size_t  stOft   = 4;if (!pcCdump || (pcCdump == (PCHAR)PX_ERROR)) {return;}pcCdump[0] = LW_CDUMP_MAGIC_0;pcCdump[1] = LW_CDUMP_MAGIC_1;pcCdump[2] = LW_CDUMP_MAGIC_2;pcCdump[3] = LW_CDUMP_MAGIC_3;stOft = bnprintf(pcCdump, LW_CDUMP_MAX_LEN, stOft, "FATAL ERROR: thread %lx[%s] stack overflow. ""ret_addr: 0x%08lx abt_addr: 0x%08lx abt_type: %s\n""rebooting...\n",ptcb->TCB_ulId, ptcb->TCB_cThreadName,ulRetAddr, ulAbortAddr, pcInfo);pcCdump[stOft] = PX_EOS;
}
/*********************************************************************************************************
** 函数名称: _CrashDumpAbortFatal
** 功能描述: 崩溃信息记录.
** 输 入  : ulRetAddr     异常返回 PC 地址
**           ulAbortAddr   异常地址
**           pcInfo        异常信息
** 输 出  : NONE
*********************************************************************************************************/
VOID  _CrashDumpAbortFatal (addr_t  ulRetAddr, addr_t  ulAbortAddr, CPCHAR  pcInfo)
{PCHAR   pcCdump = (PCHAR)_K_pvCrashDumpBuffer;size_t  stOft   = 4;if (!pcCdump || (pcCdump == (PCHAR)PX_ERROR)) {return;}pcCdump[0] = LW_CDUMP_MAGIC_0;pcCdump[1] = LW_CDUMP_MAGIC_1;pcCdump[2] = LW_CDUMP_MAGIC_2;pcCdump[3] = LW_CDUMP_MAGIC_3;stOft = bnprintf(pcCdump, LW_CDUMP_MAX_LEN, stOft, "FATAL ERROR: abort occur in exception mode. ""ret_addr: 0x%08lx abt_addr: 0x%08lx abt_type: %s\n""rebooting...\n",ulRetAddr, ulAbortAddr, pcInfo);pcCdump[stOft] = PX_EOS;
}
/*********************************************************************************************************
** 函数名称: _CrashDumpAbortKernel
** 功能描述: 内核崩溃信息记录.
** 输 入  : ulOwner       占用内核的任务
**           pcKernelFunc  进入内核的函数
**           pvCtx         异常信息结构
**           pcInfo        异常信息
**           pcTail        附加信息
** 输 出  : NONE 
*********************************************************************************************************/
VOID  _CrashDumpAbortKernel (LW_OBJECT_HANDLE   ulOwner, CPCHAR             pcKernelFunc, PVOID              pvCtx,CPCHAR             pcInfo, CPCHAR             pcTail)
{PLW_VMM_ABORT_CTX  pabtctx = (PLW_VMM_ABORT_CTX)pvCtx;PCHAR              pcCdump = (PCHAR)_K_pvCrashDumpBuffer;size_t             stOft;if (!pcCdump || (pcCdump == (PCHAR)PX_ERROR)) {return;}lib_bzero(pcCdump, LW_CDUMP_BUF_SIZE);pcCdump[0] = LW_CDUMP_MAGIC_0;pcCdump[1] = LW_CDUMP_MAGIC_1;pcCdump[2] = LW_CDUMP_MAGIC_2;pcCdump[3] = LW_CDUMP_MAGIC_3;archTaskCtxPrint(&pcCdump[4], (LW_CDUMP_MAX_LEN - LW_CDUMP_MAGIC_LEN), &pabtctx->ABTCTX_archRegCtx);stOft = lib_strlen(pcCdump);stOft = bnprintf(pcCdump, LW_CDUMP_MAX_LEN, stOft, "FATAL ERROR: abort in kernel status. ""kowner: 0x%08lx, kfunc: %s, ""ret_addr: 0x%08lx abt_addr: 0x%08lx, abt_type: %s, %s.\n",ulOwner, pcKernelFunc, pabtctx->ABTCTX_ulRetAddr,pabtctx->ABTCTX_ulAbortAddr, pcInfo, pcTail);
}
/*********************************************************************************************************
** 函数名称: _CrashDumpAbortAccess
** 功能描述: 崩溃信息记录.
** 输 入  : pvCtx            异常信息结构
**           pcInfo           异常信息
** 输 出  : NONE
*********************************************************************************************************/
VOID  _CrashDumpAbortAccess (PVOID  pvCtx, CPCHAR  pcInfo)
{PLW_VMM_ABORT_CTX  pabtctx = (PLW_VMM_ABORT_CTX)pvCtx;PCHAR              pcCdump = (PCHAR)_K_pvCrashDumpBuffer;size_t             stOft;if (!pcCdump || (pcCdump == (PCHAR)PX_ERROR)) {return;}lib_bzero(pcCdump, LW_CDUMP_BUF_SIZE);pcCdump[0] = LW_CDUMP_MAGIC_0;pcCdump[1] = LW_CDUMP_MAGIC_1;pcCdump[2] = LW_CDUMP_MAGIC_2;pcCdump[3] = LW_CDUMP_MAGIC_3;archTaskCtxPrint(&pcCdump[4], (LW_CDUMP_MAX_LEN - LW_CDUMP_MAGIC_LEN), &pabtctx->ABTCTX_archRegCtx);stOft = lib_strlen(pcCdump);switch (__ABTCTX_ABORT_TYPE(pabtctx)) {case LW_VMM_ABORT_TYPE_UNDEF:stOft = bnprintf(pcCdump, LW_CDUMP_MAX_LEN, stOft, "UNDEF ERROR: abort in thread %lx[%s]. ""ret_addr: 0x%08lx abt_addr: 0x%08lx, abt_type: %s.\n",pabtctx->ABTCTX_ptcb->TCB_ulId,pabtctx->ABTCTX_ptcb->TCB_cThreadName,pabtctx->ABTCTX_ulRetAddr,pabtctx->ABTCTX_ulAbortAddr, pcInfo);break;case LW_VMM_ABORT_TYPE_FPE:stOft = bnprintf(pcCdump, LW_CDUMP_MAX_LEN, stOft, "FPU ERROR: abort in thread %lx[%s]. ""ret_addr: 0x%08lx abt_addr: 0x%08lx, abt_type: %s.\n",pabtctx->ABTCTX_ptcb->TCB_ulId,pabtctx->ABTCTX_ptcb->TCB_cThreadName,pabtctx->ABTCTX_ulRetAddr,pabtctx->ABTCTX_ulAbortAddr, pcInfo);break;default:stOft = bnprintf(pcCdump, LW_CDUMP_MAX_LEN, stOft, "ACCESS ERROR: abort in thread %lx[%s]. ""ret_addr: 0x%08lx abt_addr: 0x%08lx, abt_type: %s.\n",pabtctx->ABTCTX_ptcb->TCB_ulId,pabtctx->ABTCTX_ptcb->TCB_cThreadName,pabtctx->ABTCTX_ulRetAddr,pabtctx->ABTCTX_ulAbortAddr, pcInfo);break;}API_BacktracePrint(&pcCdump[stOft], (LW_CDUMP_MAX_LEN - stOft), LW_CFG_CDUMP_CALL_STACK_DEPTH);
}

API接口的实现

/*********************************************************************************************************
** 函数名称: API_CrashDumpBuffer
** 功能描述: 重新定位系统/应用崩溃信息记录位置. (必须是内核能访问的地址)
** 输 入  : pvCdump           缓冲地址
**           stSize            缓冲大小
** 输 出  : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
LW_API  
INT  API_CrashDumpBuffer (PVOID  pvCdump, size_t  stSize)
{if (!pvCdump || (pvCdump == (PVOID)PX_ERROR) || (stSize < 512)) {_ErrorHandle(EINVAL);return  (PX_ERROR);}_CrashDumpSet(pvCdump, stSize);return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: API_CrashDumpSave
** 功能描述: 最近一次系统/应用崩溃信息保存入文件.
** 输 入  : pcLogFile         日志文件名
**           iFlag             open 第二个参数
**           iMode             open 第三个参数
**           bClear            成功保存后是否清空缓冲区
** 输 出  : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
LW_API  
INT  API_CrashDumpSave (CPCHAR  pcLogFile, INT  iFlag, INT  iMode, BOOL  bClear)
{PCHAR   pcCdump, pcBuffer;size_t  stSize, stLen;INT     iFd;pcCdump = (PCHAR)_CrashDumpGet(&stSize);if (!pcCdump || (pcCdump == (PCHAR)PX_ERROR) || (stSize < 512)) {_ErrorHandle(EINVAL);return  (PX_ERROR);}if (((UINT8)pcCdump[0] != LW_CDUMP_MAGIC_0) ||((UINT8)pcCdump[1] != LW_CDUMP_MAGIC_1) ||((UINT8)pcCdump[2] != LW_CDUMP_MAGIC_2) ||((UINT8)pcCdump[3] != LW_CDUMP_MAGIC_3)) {_ErrorHandle(EMSGSIZE);return  (PX_ERROR);}pcCdump[stSize - 1] = PX_EOS;iFd = open(pcLogFile, iFlag, iMode);if (iFd < 0) {return  (PX_ERROR);}pcBuffer = &pcCdump[4];stLen    = lib_strlen(pcBuffer);if (write(iFd, pcBuffer, stLen) != stLen) {close(iFd);return  (PX_ERROR);}close(iFd);if (bClear) {pcCdump[0] = 0;pcCdump[1] = 0;pcCdump[2] = 0;pcCdump[3] = 0;}return  (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: API_CrashDumpShow
** 功能描述: 显示最近一次系统/应用崩溃信息.
** 输 入  : iFd               打印文件描述符
**           bClear            是否清空缓冲区
** 输 出  : ERROR_NONE or PX_ERROR
*********************************************************************************************************/
LW_API  
INT  API_CrashDumpShow (INT  iFd, BOOL  bClear)
{PCHAR   pcCdump, pcBuffer;size_t  stSize;pcCdump = (PCHAR)_CrashDumpGet(&stSize);if (!pcCdump || (pcCdump == (PCHAR)PX_ERROR) || (stSize < 512)) {_ErrorHandle(EINVAL);return  (PX_ERROR);}if (((UINT8)pcCdump[0] != LW_CDUMP_MAGIC_0) ||((UINT8)pcCdump[1] != LW_CDUMP_MAGIC_1) ||((UINT8)pcCdump[2] != LW_CDUMP_MAGIC_2) ||((UINT8)pcCdump[3] != LW_CDUMP_MAGIC_3)) {_ErrorHandle(EMSGSIZE);return  (PX_ERROR);}pcCdump[stSize - 1] = PX_EOS;pcBuffer            = &pcCdump[4];fdprintf(iFd, "%s", pcBuffer);if (bClear) {pcCdump[0] = 0;pcCdump[1] = 0;pcCdump[2] = 0;pcCdump[3] = 0;}return  (ERROR_NONE);
}

cdump命令的实现

/*********************************************************************************************************
** 函数名称: __tshellSysCmdCdump
** 功能描述: 系统命令 "cdump"
** 输 入  : iArgC         参数个数
**           ppcArgV       参数表
** 输 出  : 0
*********************************************************************************************************/
static INT  __tshellSysCmdCdump (INT  iArgC, PCHAR  ppcArgV[])
{INT         iC;BOOL        bSave  = LW_FALSE;BOOL        bClear = LW_FALSE;CHAR        cFile[MAX_FILENAME_LENGTH] = "/var/log/cdump/";time_t      tm;while ((iC = getopt(iArgC, ppcArgV, "sc")) != EOF) {switch (iC) {case 's':bSave = LW_TRUE;break;case 'c':bClear = LW_TRUE;break;}}getopt_free();if (bSave) {lib_time(&tm);snprintf(cFile, MAX_FILENAME_LENGTH, "%s/%lld","/var/log/cdump", tm);if (API_CrashDumpSave(cFile, O_CREAT | O_WRONLY | O_TRUNC, DEFAULT_FILE_PERM, bClear) < ERROR_NONE) {if (errno == EMSGSIZE) {fprintf(stderr, "no message in crash dump buffer.\n");} else {fprintf(stderr, "crash dump save (%s) fail: %s.\n", cFile, lib_strerror(errno));}return  (PX_ERROR);} else {printf("crash dump save (%s) ok.\n", cFile);}} else {if (API_CrashDumpShow(STD_OUT, bClear) < ERROR_NONE) {if (errno == EMSGSIZE) {fprintf(stderr, "no message in crash dump buffer.\n");}return  (PX_ERROR);}}return  (ERROR_NONE);
}

这篇关于SylixOS内核的cdump功能的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/336174

相关文章

使用EasyPoi快速导出Word文档功能的实现步骤

《使用EasyPoi快速导出Word文档功能的实现步骤》EasyPoi是一个基于ApachePOI的开源Java工具库,旨在简化Excel和Word文档的操作,本文将详细介绍如何使用EasyPoi快速... 目录一、准备工作1、引入依赖二、准备好一个word模版文件三、编写导出方法的工具类四、在Export

JS纯前端实现浏览器语音播报、朗读功能的完整代码

《JS纯前端实现浏览器语音播报、朗读功能的完整代码》在现代互联网的发展中,语音技术正逐渐成为改变用户体验的重要一环,下面:本文主要介绍JS纯前端实现浏览器语音播报、朗读功能的相关资料,文中通过代码... 目录一、朗读单条文本:① 语音自选参数,按钮控制语音:② 效果图:二、朗读多条文本:① 语音有默认值:②

C#实现高性能拍照与水印添加功能完整方案

《C#实现高性能拍照与水印添加功能完整方案》在工业检测、质量追溯等应用场景中,经常需要对产品进行拍照并添加相关信息水印,本文将详细介绍如何使用C#实现一个高性能的拍照和水印添加功能,包含完整的代码实现... 目录1. 概述2. 功能架构设计3. 核心代码实现python3.1 主拍照方法3.2 安全HBIT

录音功能在哪里? 电脑手机等设备打开录音功能的技巧

《录音功能在哪里?电脑手机等设备打开录音功能的技巧》很多时候我们需要使用录音功能,电脑和手机这些常用设备怎么使用录音功能呢?下面我们就来看看详细的教程... 我们在会议讨论、采访记录、课堂学习、灵感创作、法律取证、重要对话时,都可能有录音需求,便于留存关键信息。下面分享一下如何在电脑端和手机端上找到录音功能

Android实现图片浏览功能的示例详解(附带源码)

《Android实现图片浏览功能的示例详解(附带源码)》在许多应用中,都需要展示图片并支持用户进行浏览,本文主要为大家介绍了如何通过Android实现图片浏览功能,感兴趣的小伙伴可以跟随小编一起学习一... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

Debian 13升级后网络转发等功能异常怎么办? 并非错误而是管理机制变更

《Debian13升级后网络转发等功能异常怎么办?并非错误而是管理机制变更》很多朋友反馈,更新到Debian13后网络转发等功能异常,这并非BUG而是Debian13Trixie调整... 日前 Debian 13 Trixie 发布后已经有众多网友升级到新版本,只不过升级后发现某些功能存在异常,例如网络转

基于Java和FFmpeg实现视频压缩和剪辑功能

《基于Java和FFmpeg实现视频压缩和剪辑功能》在视频处理开发中,压缩和剪辑是常见的需求,本文将介绍如何使用Java结合FFmpeg实现视频压缩和剪辑功能,同时去除数据库操作,仅专注于视频处理,需... 目录引言1. 环境准备1.1 项目依赖1.2 安装 FFmpeg2. 视频压缩功能实现2.1 主要功

使用Python实现无损放大图片功能

《使用Python实现无损放大图片功能》本文介绍了如何使用Python的Pillow库进行无损图片放大,区分了JPEG和PNG格式在放大过程中的特点,并给出了示例代码,JPEG格式可能受压缩影响,需先... 目录一、什么是无损放大?二、实现方法步骤1:读取图片步骤2:无损放大图片步骤3:保存图片三、示php

深度解析Python yfinance的核心功能和高级用法

《深度解析Pythonyfinance的核心功能和高级用法》yfinance是一个功能强大且易于使用的Python库,用于从YahooFinance获取金融数据,本教程将深入探讨yfinance的核... 目录yfinance 深度解析教程 (python)1. 简介与安装1.1 什么是 yfinance?