0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于rt_thread实现c语言的try catch finally捕获崩溃错误代码

冬至子 来源:kangchaoyang003 作者:kangchaoyang003 2023-09-27 11:47 次阅读

功能:给c语言添加try catch finally语句捕获崩溃代码块,
支持捕捉空指针访问,未对齐操作,除零崩溃,等等错误,帮助你高效调试代码.
直接上代码
.h文件内容
#ifndef C_TRY_CATCH_H
#define C_TRY_CATCH_H
#include "setjmp.h"
extern void exception_catch (void);
extern int push (jmp_buf env);
extern void finally_syntax (void);
extern jmp_buf env;
#define try if(0==setjmp(env) && push (env))
#define catch else
#define finally { finally_syntax ();}
#endif
.c文件内容

#include "c_try_catch.h"
#include "rtdef.h"
#include "rtservice.h"
#include "setjmp.h"
#include "rtthread.h"
#define ENABLE_DEBUG 1
#define TLS_MALLOC rt_malloc
#define TLS_FREE rt_free
#define TLS_MEMCPY rt_memcpy
#define TLS_MEMSET rt_memset
#define TLS_NULL RT_NULL
#define CATCH_CODE (!0)
#define LOGI rt_kprintf
struct _slist_node {
struct _slist_node *next;
}
;
typedef struct _slist_node _slist_t;
struct _try_catch_stack_node {
_slist_t list;
_slist_t stack;
rt_thread_t tid;
#if ENABLE_DEBUG == 1
char name[RT_NAME_MAX];
#endif
}
;
typedef struct _try_catch_stack_node try_catch_stack_node_t;
struct _jmp_buf_node {
_slist_t list;
jmp_buf env;
}
;
typedef struct _jmp_buf_node jmp_buf_node_t;
static _slist_t thread_list;
jmp_buf env;
static int list_len (const _slist_t *l);
#if ENABLE_DEBUG == 1
static void print_env (char *env,uint32_t len) ;
#endif
static void tls_context_read (void **context) {
try_catch_stack_node_t *stack_node = TLS_NULL;
_slist_t *pthread_list = &thread_list;
rt_thread_t self_tid = rt_thread_self();
const _slist_t *list_node = pthread_list->next;
while (list_node != TLS_NULL) {
stack_node = (try_catch_stack_node_t *)list_node;
if(stack_node!=TLS_NULL&&self_tid!=TLS_NULL&&stack_node ->tid == self_tid) {
*context = &(stack_node->stack);
#if ENABLE_DEBUG == 1
LOGI("找到已存在的TLS node,thread name:%s,thread tid:%drn",stack_node->name,stack_node->tid);
#endif
return;
}
list_node = list_node->next;
}
stack_node = (try_catch_stack_node_t *)TLS_MALLOC(sizeof(try_catch_stack_node_t));
if(stack_node!=TLS_NULL) {
if(self_tid!=TLS_NULL) {
TLS_MEMSET(stack_node,0,sizeof(try_catch_stack_node_t));
#if ENABLE_DEBUG == 1
TLS_MEMCPY(stack_node->name,self_tid->name,RT_NAME_MAX);
#endif
stack_node->tid = self_tid;
((_slist_t *)stack_node)->next = pthread_list->next;
pthread_list->next = (_slist_t *)stack_node;
*context = &(stack_node->stack);
#if ENABLE_DEBUG == 1
LOGI("新建TLS node,thread name:%s,thread tid:%drn",stack_node->name,stack_node->tid);
#endif
} else {
TLS_FREE(stack_node);
#if ENABLE_DEBUG == 1
LOGI("新建TLS node失败,self_tid is NULLrn");
#endif
}
} else {
#if ENABLE_DEBUG == 1
LOGI("新建TLS node失败,malloc failrn");
#endif
}
}
static void tls_context_destroy (void) {
try_catch_stack_node_t *stack_node = TLS_NULL;
_slist_t *pthread_list = &thread_list;
rt_thread_t self_tid = rt_thread_self();
//查找当前线程tls表头
const _slist_t *list_node = pthread_list->next;
while (list_node != TLS_NULL) {
stack_node = (try_catch_stack_node_t *)list_node;
if(stack_node!=TLS_NULL&&self_tid!=TLS_NULL&&stack_node ->tid == self_tid) {
if(stack_node->stack.next==TLS_NULL) {
/* remove slist head */
_slist_t *node = pthread_list;
while (node->next && node->next != &(stack_node->list)) node = node->next;
/* remove node */
if (node->next != (_slist_t *)0) node->next = node->next->next;
#if ENABLE_DEBUG == 1
LOGI("移除TLS node,thread name:%s,thread tid:%drn",stack_node->name,stack_node->tid);
LOGI("TLS node num:%drn",_list_len_(pthread_list));
#endif
TLS_FREE(stack_node);
}
return;
}
list_node = list_node->next;
}
}
int _push_(jmp_buf env) {
jmp_buf_node_t *jb_node = TLS_NULL;
_slist_t *context = TLS_NULL;
_tls_context_read_((void *)&context) ;
if(context!=TLS_NULL) {
jb_node = (jmp_buf_node_t *)TLS_MALLOC(sizeof(jmp_buf_node_t));
if(jb_node!=TLS_NULL) {
TLS_MEMCPY(jb_node->env,env,sizeof(jmp_buf));
((_slist_t *)jb_node)->next = context->next;
context->next = (_slist_t *)jb_node;
#if ENABLE_DEBUG == 1
LOGI("压栈 jb node env:rn");
_print_env_(((char *)&(jb_node->env)),sizeof(jmp_buf));
#endif
return 1;
} else {
#if ENABLE_DEBUG == 1
LOGI("压栈 jb node失败,malloc failrn");
#endif
}
}
return 0;
}
static void _pop_(void) {
_slist_t *context = TLS_NULL;
_tls_context_read_((void *)&context) ;
if(context!=TLS_NULL && context->next!=TLS_NULL) {
_slist_t *removed_node = context->next;
context->next = context->next->next;
if(removed_node!=TLS_NULL) {
#if ENABLE_DEBUG == 1
LOGI("出栈 jb node env:rn");
_print_env_(((char *)&(((jmp_buf_node_t*)removed_node)->env)),sizeof(jmp_buf));
#endif
TLS_FREE(removed_node);
}
} else {
#if ENABLE_DEBUG == 1
LOGI("出栈 jb node env failrn");
#endif
}
}
static void _peek_(jmp_buf *env) {
jmp_buf_node_t *jb_node = TLS_NULL;
_slist_t *context = TLS_NULL;
_tls_context_read_((void *)&context) ;
if(context!=TLS_NULL&&env!=TLS_NULL&&context->next!=TLS_NULL) {
jb_node=(jmp_buf_node_t *)(context->next);
if(jb_node!=TLS_NULL) {
TLS_MEMCPY(env,jb_node->env,sizeof(jmp_buf));
#if ENABLE_DEBUG == 1
LOGI("查看 jb node env:rn");
_print_env_(((char *)&(jb_node->env)),sizeof(jmp_buf));
#endif
}
} else {
#if ENABLE_DEBUG == 1
LOGI("查看 jb node env failrn");
#endif
}
}
static uint32_t _depth_(void) {
uint32_t _depth = 0;
_slist_t *context = TLS_NULL;
_tls_context_read_((void *)&context) ;
_depth = _list_len_(context);
#if ENABLE_DEBUG == 1
LOGI("stack depth:%drn",_depth);
#endif
return _depth;
}
void _exception_catch_(void) {
_peek_(&env);
longjmp(env,CATCH_CODE);
}
void _finally_syntax_(void) {
int stack_depth = _depth_();
if(stack_depth>=1) {
_pop_();
if(stack_depth==1) {
_tls_context_destroy_();
}
}
}
static int _list_len_(const _slist_t *l) {
unsigned int len = 0;
if(l) {
const _slist_t *list = l->next;
while (list != RT_NULL) {
list = list->next;
len ++;
}
}
return len;
}
#if ENABLE_DEBUG == 1
static void _print_env_(char *env,uint32_t len) {
int idx=0;
if(env) {
for (idx=0;idx LOGI("%X",env[idx]);
}
LOGI("rn");
}
}
#endif
/*
功能:给c语言添加try catch finally语句捕获崩溃代码块,
支持捕捉空指针访问,未对齐操作,除零崩溃,等等错误,帮助你高效调试代码
author: VX:kangchaoyang003
*/
移植方法
/*
把 void _exception_catch_(void) 方法放到 cpuport.c文件里面的
void rt_hw_hard_fault_exception(struct exception_info * exception_info)方法最后的
while(1){}之前。如下代码:
*/
/*

fault exception handler
/
void rt_hw_hard_fault_exception(struct exception_info * exception_info)
{
extern void exception_catch (void);
extern long list_thread(void);
struct stack_frame
context = &exception_info->stack_frame;
if (rt_exception_hook != RT_NULL)
{
rt_err_t result;
result = rt_exception_hook(exception_info);
if (result == RT_EOK)
return;
}
rt_kprintf("psr: 0x%08xn", context->exception_stack_frame.psr);
rt_kprintf("r00: 0x%08xn", context->exception_stack_frame.r0);
rt_kprintf("r01: 0x%08xn", context->exception_stack_frame.r1);
rt_kprintf("r02: 0x%08xn", context->exception_stack_frame.r2);
rt_kprintf("r03: 0x%08xn", context->exception_stack_frame.r3);
rt_kprintf("r04: 0x%08xn", context->r4);
rt_kprintf("r05: 0x%08xn", context->r5);
rt_kprintf("r06: 0x%08xn", context->r6);
rt_kprintf("r07: 0x%08xn", context->r7);
rt_kprintf("r08: 0x%08xn", context->r8);
rt_kprintf("r09: 0x%08xn", context->r9);
rt_kprintf("r10: 0x%08xn", context->r10);
rt_kprintf("r11: 0x%08xn", context->r11);
rt_kprintf("r12: 0x%08xn", context->exception_stack_frame.r12);
rt_kprintf(" lr: 0x%08xn", context->exception_stack_frame.lr);
rt_kprintf(" pc: 0x%08xn", context->exception_stack_frame.pc);
if(exception_info->exc_return & (1 << 2) )
{
rt_kprintf("hard fault on thread: %srnrn", rt_thread_self()->name);
#ifdef RT_USING_FINSH
list_thread();
#endif /* RT_USING_FINSH /
}
else
{
rt_kprintf("hard fault on handlerrnrn");
}
#ifdef RT_USING_FINSH
hard_fault_track();
#endif /
RT_USING_FINSH */
exception_catch ();
while (1);
}
测试代码
//测试空指针访问崩溃捕捉,支持无限制嵌套
void test_null_p(void) {
try {
rt_kprintf("try 1rn");
try {
rt_kprintf("try 2rn");
try {
int *p = RT_NULL;
rt_kprintf("try 3rn");
*p = 100;
}
catch {
rt_kprintf("catch 3rn");
rt_kprintf("catch hard fault on thread: %srnrn", rt_thread_self()->name);
try {
rt_kprintf("try 4rn");
}
catch {
rt_kprintf("catch 4rn");
}
finally {
rt_kprintf("finally 4rn");
}
}
finally {
rt_kprintf("finally 3rn");
}
}
catch {
rt_kprintf("catch 2rn");
}
finally {
rt_kprintf("finally 2rn");
}
}
catch {
rt_kprintf("catch 1rn");
}
finally {
rt_kprintf("finally 1rn");
}
while(1) {
}
}
该测试方法放到任意一个线程里面执行:
如下代码:

/*

main 函数

/
/
*

@brief 主函数
@param
@retval 无
/
int main(void)
{
/

开发板硬件初始化,RTT系统初始化已经在main函数之前完成,
即在component.c文件中的rtthread_startup()函数中完成了。
所以在main函数中,只需要创建线程和启动线程即可。
/
LED_GPIO_Config();
USART_Config();
led1_thread = /
线程控制块指针 /
rt_thread_create( "led1", /
线程名字 /
led1_thread_entry, /
线程入口函数 /
RT_NULL, /
线程入口函数参数 /
512, /
线程栈大小 /
3, /
线程的优先级 /
20); /
线程时间片 /
/
启动线程,开启调度 /
if (led1_thread != RT_NULL)
rt_thread_startup(led1_thread);
else
return -1;
}
/

线程定义

*/

static void led1_thread_entry(void* parameter)
{
while (1)
{
LED1_ON;
rt_thread_delay(500); /* 延时500个tick /
rt_kprintf("led1_thread running,LED1_ONrn");
LED1_OFF;
rt_thread_delay(500); /
延时500个tick */
rt_kprintf("led1_thread running,LED1_OFFrn");
test_null_p() ;
}
}
可以看到如下错误捕捉日志:

/*
LOG:

新建TLS node,thread name:led1,thread tid:536871776
压栈 jb node env:
EFBEADDEEFBEADDEEFBEADDEEFBEADDE7FC080100F4100EFBEADDEEFBEADDEE05020481302000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
try 1
找到已存在的TLS node,thread name:led1,thread tid:536871776
压栈 jb node env:
EFBEADDEEFBEADDEEFBEADDEEFBEADDE99C080100F4100EFBEADDEEFBEADDEE05020481302000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
try 2
找到已存在的TLS node,thread name:led1,thread tid:536871776
压栈 jb node env:
EFBEADDEEFBEADDEEFBEADDEEFBEADDEB3C080100F4100EFBEADDEEFBEADDEE05020481302000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
try 3
psr: 0x01000000
r00: 0x20001bc0
r01: 0x10000000
r02: 0xf0000000
r03: 0x00000004
r04: 0x00000000
r05: 0x000001f4
r06: 0xdeadbeef
r07: 0xdeadbeef
r08: 0xdeadbeef
r09: 0xdeadbeef
r10: 0xdeadbeef
r11: 0xdeadbeef
r12: 0x00000ff4
lr: 0x08001239
pc: 0x08002e30
hard fault on thread: led1

找到已存在的TLS node,thread name:led1,thread tid:536871776
查看 jb node env:
EFBEADDEEFBEADDEEFBEADDEEFBEADDEB3C080100F4100EFBEADDEEFBEADDEE05020481302000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
catch 3
catch hard fault on thread: led1

找到已存在的TLS node,thread name:led1,thread tid:536871776
压栈 jb node env:
EFBEADDEEFBEADDEEFBEADDEEFBEADDEE3C080100F4100EFBEADDEEFBEADDEE05020481302000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
try 4
找到已存在的TLS node,thread name:led1,thread tid:536871776
stack depth:4
找到已存在的TLS node,thread name:led1,thread tid:536871776
出栈 jb node env:
EFBEADDEEFBEADDEEFBEADDEEFBEADDEE3C080100F4100EFBEADDEEFBEADDEE05020481302000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
finally 4
找到已存在的TLS node,thread name:led1,thread tid:536871776
stack depth:3
找到已存在的TLS node,thread name:led1,thread tid:536871776
出栈 jb node env:
EFBEADDEEFBEADDEEFBEADDEEFBEADDEB3C080100F4100EFBEADDEEFBEADDEE05020481302000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
finally 3
找到已存在的TLS node,thread name:led1,thread tid:536871776
stack depth:2
找到已存在的TLS node,thread name:led1,thread tid:536871776
出栈 jb node env:
EFBEADDEEFBEADDEEFBEADDEEFBEADDE99C080100F4100EFBEADDEEFBEADDEE05020481302000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
finally 2
找到已存在的TLS node,thread name:led1,thread tid:536871776
stack depth:1
找到已存在的TLS node,thread name:led1,thread tid:536871776
出栈 jb node env:
EFBEADDEEFBEADDEEFBEADDEEFBEADDE7FC080100F4100EFBEADDEEFBEADDEE05020481302000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
移除TLS node,thread name:led1,thread tid:536871776
TLS node num:0
finally 1

*/

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7551

    浏览量

    131882
  • RT-Thread
    +关注

    关注

    31

    文章

    1196

    浏览量

    39057
  • printf函数
    +关注

    关注

    0

    文章

    31

    浏览量

    5846
收藏 人收藏

    评论

    相关推荐

    Java捕获异常处理的常用方法

    IllegalArgumentException 类,IllegalStateException 类。捕获异常的方法使用 trycatch 关键字可以捕获异常,
    发表于 11-27 11:40

    rt_thread(3.0.3)的移植准备工作

    文件夹内容简介添加RT_Thread源码到工程组文件夹config.h文件修改board.c文件修改修改main.c函数注意,此时编译还会存在问题,需要将stm32F10x_it.c
    发表于 08-03 07:44

    Sqlserver Try CatchCatch捕获错误重试一次的方法分享

    使用while重试一次不太好,如果try catch在游标里面,这样的话每个游标记录都要在try里面执行两次。还是需要等到Catch的结果来重试比较合适,所有用IF比较合适改成以下
    发表于 11-10 17:44

    MSN错误代码大全

    MSN错误代码大全  80004005   这是一个泛泛的错误代码,它意味着,“我知道出错了,但我不知道错误是什么”。   第一步,我们可以试着重新注册MSN所需的dll
    发表于 07-20 22:50 2642次阅读

    2013LabVIEW错误代码

    2013LabVIEW错误代码介绍,通过查看错误代码可知错误原因。
    发表于 02-25 15:00 8次下载

    Java异常处理之trycatchfinally,throw,throws

    后,程序继续运行。 java的异常处理是通过5个关键字来实现的:trycatchfinally、throw、throws。 二:java异常类的层次结构 三。常见的异常类型 Exc
    发表于 09-27 11:17 0次下载
    Java异常处理之<b class='flag-5'>try</b>,<b class='flag-5'>catch</b>,<b class='flag-5'>finally</b>,throw,throws

    基于正点原子精英版stm32f103zet6进行rt_thread(3.0.3)的移植

    基于正点原子精英版stm32f103zet6进行rt_thread(3.0.3)的移植准备工作安装rt_thread nano 3.0.3 软件包裸机工程添加rt_thread源码RT-Thr
    发表于 12-05 11:21 0次下载
    基于正点原子精英版stm32f103zet6进行<b class='flag-5'>rt_thread</b>(3.0.3)的移植

    RTthread线程调度详解

    rt_schedule(void){ struct rt_thread *to_thread; struct rt_thread *from_th
    的头像 发表于 05-19 17:07 2182次阅读

    N32G4FR系列通用MCU RT_Thread使用指南

    N32G4FR系列通用MCU RT_Thread使用指南
    发表于 11-11 21:50 2次下载
    N32G4FR系列通用MCU <b class='flag-5'>RT_Thread</b>使用指南

    N32G457系列通用MCU RT_Thread使用指南

    N32G457系列通用MCU RT_Thread使用指南
    发表于 11-11 21:50 0次下载
    N32G457系列通用MCU <b class='flag-5'>RT_Thread</b>使用指南

    N32G455系列通用MCU RT_Thread使用指南

    N32G455系列通用MCU RT_Thread使用指南
    发表于 11-11 21:50 2次下载
    N32G455系列通用MCU <b class='flag-5'>RT_Thread</b>使用指南

    N32G452系列通用MCU RT_Thread使用指南

    N32G452系列通用MCU RT_Thread使用指南
    发表于 11-11 21:50 3次下载
    N32G452系列通用MCU <b class='flag-5'>RT_Thread</b>使用指南

    公司这套架构统一处理try...catch真香!

    软件开发springboot项目过程中,不可避免的需要处理各种异常,spring mvc 架构中各层会出现大量的try {...} catch {...} finally {...} 代码
    的头像 发表于 02-27 10:47 373次阅读

    使用try-catch捕获异常会影响性能吗?

    “BB 不如 show code,看到没, 老王,我把 try-catch 从 for 循环里面提出来跟在for循环里面做个对比跑一下,你猜猜两个差多少?”
    的头像 发表于 04-01 11:08 928次阅读

    介绍C语言错误处理和异常处理的一些常用的方法和策略

    C语言是一种低级的、静态的、结构化的编程语言,它没有提供像C++或Java等高级语言中的异常处理机制,例如try-catch-finally等。
    的头像 发表于 02-28 14:25 352次阅读