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

电子说

1.2w人已加入

描述

功能:给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

*/

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

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分