0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于rt_thread實(shí)現(xiàn)c語言的try catch finally捕獲崩潰錯(cuò)誤代碼

冬至子 ? 來源:kangchaoyang003 ? 作者:kangchaoyang003 ? 2023-09-27 11:47 ? 次閱讀

功能:給c語言添加try catch finally語句捕獲崩潰代碼塊,
支持捕捉空指針訪問,未對(duì)齊操作,除零崩潰,等等錯(cuò)誤,幫助你高效調(diào)試代碼.
直接上代碼
.h文件內(nèi)容
#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文件內(nèi)容

#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();
//查找當(dāng)前線程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語句捕獲崩潰代碼塊,
支持捕捉空指針訪問,未對(duì)齊操作,除零崩潰,等等錯(cuò)誤,幫助你高效調(diào)試代碼
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);
}
測(cè)試代碼
//測(cè)試空指針訪問崩潰捕捉,支持無限制嵌套
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) {
}
}
該測(cè)試方法放到任意一個(gè)線程里面執(zhí)行:
如下代碼:

/*

main 函數(shù)

/
/
*

@brief 主函數(shù)
@param
@retval 無
/
int main(void)
{
/

開發(fā)板硬件初始化,RTT系統(tǒng)初始化已經(jīng)在main函數(shù)之前完成,
即在component.c文件中的rtthread_startup()函數(shù)中完成了。
所以在main函數(shù)中,只需要?jiǎng)?chuàng)建線程和啟動(dòng)線程即可。
/
LED_GPIO_Config();
USART_Config();
led1_thread = /
線程控制塊指針 /
rt_thread_create( "led1", /
線程名字 /
led1_thread_entry, /
線程入口函數(shù) /
RT_NULL, /
線程入口函數(shù)參數(shù) /
512, /
線程棧大小 /
3, /
線程的優(yōu)先級(jí) /
20); /
線程時(shí)間片 /
/
啟動(dòng)線程,開啟調(diào)度 /
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); /* 延時(shí)500個(gè)tick /
rt_kprintf("led1_thread running,LED1_ONrn");
LED1_OFF;
rt_thread_delay(500); /
延時(shí)500個(gè)tick */
rt_kprintf("led1_thread running,LED1_OFFrn");
test_null_p() ;
}
}
可以看到如下錯(cuò)誤捕捉日志:

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

*/

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • C語言
    +關(guān)注

    關(guān)注

    180

    文章

    7595

    瀏覽量

    135876
  • RT-Thread
    +關(guān)注

    關(guān)注

    31

    文章

    1261

    瀏覽量

    39840
  • printf函數(shù)
    +關(guān)注

    關(guān)注

    0

    文章

    31

    瀏覽量

    5878
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Java捕獲異常處理的常用方法

    IllegalArgumentException 類,IllegalStateException 類。捕獲異常的方法使用 trycatch 關(guān)鍵字可以捕獲異常,
    發(fā)表于 11-27 11:40

    rt_thread(3.0.3)的移植準(zhǔn)備工作

    文件夾內(nèi)容簡(jiǎn)介添加RT_Thread源碼到工程組文件夾config.h文件修改board.c文件修改修改main.c函數(shù)注意,此時(shí)編譯還會(huì)存在問題,需要將stm32F10x_it.c
    發(fā)表于 08-03 07:44

    Sqlserver Try Catch時(shí)Catch捕獲錯(cuò)誤重試一次的方法分享

    使用while重試一次不太好,如果try catch在游標(biāo)里面,這樣的話每個(gè)游標(biāo)記錄都要在try里面執(zhí)行兩次。還是需要等到Catch的結(jié)果來重試比較合適,所有用IF比較合適改成以下
    發(fā)表于 11-10 17:44

    MSN錯(cuò)誤代碼大全

    MSN錯(cuò)誤代碼大全  80004005   這是一個(gè)泛泛的錯(cuò)誤代碼,它意味著,“我知道出錯(cuò)了,但我不知道錯(cuò)誤是什么”。   第一步,我們可以試著重新注冊(cè)MSN所需的dll
    發(fā)表于 07-20 22:50 ?2856次閱讀

    2013LabVIEW錯(cuò)誤代碼

    2013LabVIEW錯(cuò)誤代碼介紹,通過查看錯(cuò)誤代碼可知錯(cuò)誤原因。
    發(fā)表于 02-25 15:00 ?9次下載

    Java異常處理之try,catchfinally,throw,throws

    ,程序繼續(xù)運(yùn)行。 java的異常處理是通過5個(gè)關(guān)鍵字來實(shí)現(xiàn)的:try、catch、finally、throw、throws。 二:java異常類的層次結(jié)構(gòu) 三。常見的異常類型 Exce
    發(fā)表于 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

    基于正點(diǎn)原子精英版stm32f103zet6進(jìn)行rt_thread(3.0.3)的移植

    文件夾內(nèi)容簡(jiǎn)介添加RT_Thread源碼到工程組文件夾config.h文件修改board.c文件修改修改main.c函數(shù)注意,此時(shí)編譯還會(huì)存在問題,需要將stm32F10x_it.c
    發(fā)表于 12-05 11:21 ?0次下載
    基于正點(diǎn)原子精英版stm32f103zet6進(jìn)行<b class='flag-5'>rt_thread</b>(3.0.3)的移植

    RTthread線程調(diào)度詳解

    rt_schedule(void){ struct rt_thread *to_thread; struct rt_thread *from_th
    的頭像 發(fā)表于 05-19 17:07 ?2483次閱讀

    N32G432系列通用MCU RT_Thread設(shè)備注冊(cè)應(yīng)用筆記

    N32G432系列通用MCU RT_Thread設(shè)備注冊(cè)應(yīng)用筆記
    發(fā)表于 11-10 19:51 ?3次下載
    N32G432系列通用MCU <b class='flag-5'>RT_Thread</b>設(shè)備注冊(cè)應(yīng)用筆記

    N32L43x系列通用MCU RT_Thread設(shè)備注冊(cè)應(yīng)用筆記

    N32L43x系列通用MCU RT_Thread設(shè)備注冊(cè)應(yīng)用筆記
    發(fā)表于 11-10 19:51 ?0次下載
    N32L43x系列通用MCU <b class='flag-5'>RT_Thread</b>設(shè)備注冊(cè)應(yīng)用筆記

    N32G4FR系列通用MCU RT_Thread使用指南

    N32G4FR系列通用MCU RT_Thread使用指南
    發(fā)表于 11-11 21:50 ?2次下載
    N32G4FR系列通用MCU <b class='flag-5'>RT_Thread</b>使用指南

    N32G455系列通用MCU RT_Thread使用指南

    N32G455系列通用MCU RT_Thread使用指南
    發(fā)表于 11-11 21:50 ?2次下載
    N32G455系列通用MCU <b class='flag-5'>RT_Thread</b>使用指南

    公司這套架構(gòu)統(tǒng)一處理try...catch真香!

    軟件開發(fā)springboot項(xiàng)目過程中,不可避免的需要處理各種異常,spring mvc 架構(gòu)中各層會(huì)出現(xiàn)大量的try {...} catch {...} finally {...} 代碼
    的頭像 發(fā)表于 02-27 10:47 ?451次閱讀

    使用try-catch捕獲異常會(huì)影響性能嗎?

    “BB 不如 show code,看到?jīng)], 老王,我把 try-catch 從 for 循環(huán)里面提出來跟在for循環(huán)里面做個(gè)對(duì)比跑一下,你猜猜兩個(gè)差多少?”
    的頭像 發(fā)表于 04-01 11:08 ?1142次閱讀

    介紹C語言錯(cuò)誤處理和異常處理的一些常用的方法和策略

    C語言是一種低級(jí)的、靜態(tài)的、結(jié)構(gòu)化的編程語言,它沒有提供像C++或Java等高級(jí)語言中的異常處理機(jī)制,例如
    的頭像 發(fā)表于 02-28 14:25 ?580次閱讀