久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

CmBacktrace

 刀首木 2021-07-29

Foreword

CmBacktrace (Cortex Microcontroller Backtrace)是一款針對(duì) ARM Cortex-M 系列 MCU 的錯(cuò)誤代碼自動(dòng)追蹤,、定位,,錯(cuò)誤原因自動(dòng)分析的開源庫(kù)。主要特性如下:

支持的錯(cuò)誤包括: 斷言(assert) 故障(Hard Fault, Memory Management Fault, Bus Fault, Usage Fault, Debug Fault) 故障原因 自動(dòng)診斷 :可在故障發(fā)生時(shí),,自動(dòng)分析出故障的原因,,定位發(fā)生故障的代碼位置,而無(wú)需 再手動(dòng)分析繁雜的故障寄存器,; 輸出錯(cuò)誤現(xiàn)場(chǎng)的 函數(shù)調(diào)用棧(需配合 addr2line 工具進(jìn)行精確定位),,還原發(fā)生錯(cuò)誤時(shí)的現(xiàn)場(chǎng)信息 ,定位問(wèn)題代碼位置,、邏輯更加快捷、精準(zhǔn),。也可以在正常狀態(tài)下使用該庫(kù),,獲取當(dāng)前的函數(shù)調(diào)用 棧; 支持 裸機(jī) 及以下操作系統(tǒng)平臺(tái): RT-Thread UCOS FreeRTOS(需修改源碼) 根據(jù)錯(cuò)誤現(xiàn)場(chǎng)狀態(tài),輸出對(duì)應(yīng)的 線程棧 或 C 主棧,; 故障診斷信息支持多國(guó)語(yǔ)言(目前:簡(jiǎn)體中文,、英文); 適配 Cortex-M0/M3/M4/M7 MCU,; 支持 IAR,、KEIL、GCC 編譯器,;

https://github.com/armink/CmBacktrace

從介紹上來(lái)說(shuō),,非常友好,發(fā)生斷言,,Hard Fault 等情況可以幫忙記錄故障原因,,打印輸出寄存器 狀態(tài),堆棧等內(nèi)容,,實(shí)際使用時(shí)配合 Flash 保存這些信息也非常容易,,從而在一個(gè)復(fù)雜系統(tǒng)中可以 找到某些隱藏的BUG,進(jìn)而提升產(chǎn)品的穩(wěn)定性,,非常不錯(cuò)

詳細(xì)的介紹在 github 上也有,,當(dāng)然直接看源碼更合適。

Source Code

cmb_cfg.h

#ifndef _CMB_CFG_H_
#define _CMB_CFG_H_

/* print line, must config by user */
#define cmb_println(...)     /* e.g., printf(__VA_ARGS__);printf("\r\n") */

    首先 ... 表示給入的參數(shù)是一個(gè)不定長(zhǎng)度的參數(shù),, __VA_ARGS__ 則是把這個(gè)參數(shù)列表給傳入
    對(duì)應(yīng)使用的函數(shù)中,,需要注意的是 ... 只能代替最后面的宏參數(shù)

/* enable bare metal(no OS) platform */
/* #define CMB_USING_BARE_METAL_PLATFORM */
/* enable OS platform */
#define CMB_USING_OS_PLATFORM

/* OS platform type, must config when CMB_USING_OS_PLATFORM is enable */
/* #define CMB_OS_PLATFORM_TYPE           CMB_OS_PLATFORM_RTT or CMB_OS_PLATFORM_UCOSII or CMB_OS_PLATFORM_UCOSIII or CMB_OS_PLATFORM_FREERTOS */
#define CMB_OS_PLATFORM_TYPE           CMB_OS_PLATFORM_FREERTOS

/* cpu platform type, must config by user */
/* #define CMB_CPU_PLATFORM_TYPE           CMB_CPU_ARM_CORTEX_M0 or CMB_CPU_ARM_CORTEX_M3 or CMB_CPU_ARM_CORTEX_M4 or CMB_CPU_ARM_CORTEX_M7 */
#define CMB_CPU_PLATFORM_TYPE          CMB_CPU_ARM_CORTEX_M7

/* enable dump stack information */
#define CMB_USING_DUMP_STACK_INFO

/* language of print information */
/* #define CMB_PRINT_LANGUAGE             CMB_PRINT_LANGUAGE_ENGLISH(default) or CMB_PRINT_LANUUAGE_CHINESE */

#endif /* _CMB_CFG_H_ */

cmb_fault.S

AREA |.text|, CODE, READONLY, ALIGN=2
THUMB
REQUIRE8
PRESERVE8

; NOTE: If use this file's HardFault_Handler, please comments the HardFault_Handler code on other file.
IMPORT cm_backtrace_fault
EXPORT HardFault_Handler

HardFault_Handler    PROC
MOV     r0, lr                  ; get lr
MOV     r1, sp                  ; get stack pointer (current is MSP)
BL      cm_backtrace_fault

Fault_Loop
BL      Fault_Loop              ;while(1)
ENDP

END

這里是重寫了 HardFault 的中斷處理函數(shù),通過(guò)把 lr 和 sp 存入 r0 r1 (他們作為參數(shù))調(diào)用 cm_backtrace_fault 進(jìn)行錯(cuò)誤追蹤處理 ,,處理結(jié)束后程序死在這里,。

由于這里重構(gòu)了 HardFault 中斷,那么原本的中斷函數(shù)就需要注釋掉了,,當(dāng)然也可以自己重寫Hard Fault ,,不用他這里的 HardFault 。

cmb_def.h

定義了許多會(huì)使用到的寄存器結(jié)構(gòu)體,,以及和 OS,、編譯器、平臺(tái)相關(guān)的宏定義

cm_backtrace.h

#ifndef _CORTEXM_BACKTRACE_H_
#define _CORTEXM_BACKTRACE_H_

#include "cmb_def.h"

void cm_backtrace_init(const char *firmware_name, const char *hardware_ver, const char *software_ver);
void cm_backtrace_firmware_info(void);
size_t cm_backtrace_call_stack(uint32_t *buffer, size_t size, uint32_t sp);
void cm_backtrace_assert(uint32_t sp);
void cm_backtrace_fault(uint32_t fault_handler_lr, uint32_t fault_handler_sp);

#endif /* _CORTEXM_BACKTRACE_H_ */

這里定義了幾個(gè)會(huì)被調(diào)用的函數(shù)

其中 cm_backtrace_init 需要在系統(tǒng)啟動(dòng)之后 立馬進(jìn)行初始化,,保證可以在出錯(cuò)之前完成

cm_backtrace_fault 就是 HardFault 調(diào)用的處理函數(shù)

cm_backtrace_assert 是系統(tǒng)斷言中必須要加入的函數(shù)

cm_backtrace_call_stack 和 cm_backtrace_firmware_info 則是 斷言和 HardFault 調(diào)用的 子函數(shù)

cm_backtrace.c

void cm_backtrace_init(const char *firmware_name, const char *hardware_ver, const char *software_ver) {
    strncpy(fw_name, firmware_name, CMB_NAME_MAX);
    strncpy(hw_ver, hardware_ver, CMB_NAME_MAX);
    strncpy(sw_ver, software_ver, CMB_NAME_MAX);
    設(shè)定好對(duì)應(yīng)的固件名 硬件版本 軟件版本(這里的軟件版本其實(shí)可以對(duì)應(yīng)git commit號(hào))

#if defined(__CC_ARM)
    main_stack_start_addr = (uint32_t)&CSTACK_BLOCK_START(CMB_CSTACK_BLOCK_NAME);
    main_stack_size = (uint32_t)&CSTACK_BLOCK_END(CMB_CSTACK_BLOCK_NAME) - main_stack_start_addr;
    code_start_addr = (uint32_t)&CODE_SECTION_START(CMB_CODE_SECTION_NAME);
    code_size = (uint32_t)&CODE_SECTION_END(CMB_CODE_SECTION_NAME) - code_start_addr;
#elif defined(__ICCARM__)
    main_stack_start_addr = (uint32_t)__section_begin(CMB_CSTACK_BLOCK_NAME);
    main_stack_size = (uint32_t)__section_end(CMB_CSTACK_BLOCK_NAME) - main_stack_start_addr;
    code_start_addr = (uint32_t)__section_begin(CMB_CODE_SECTION_NAME);
    code_size = (uint32_t)__section_end(CMB_CODE_SECTION_NAME) - code_start_addr;
#elif defined(__GNUC__)
    main_stack_start_addr = (uint32_t)(&CMB_CSTACK_BLOCK_START);
    main_stack_size = (uint32_t)(&CMB_CSTACK_BLOCK_END) - main_stack_start_addr;
    code_start_addr = (uint32_t)(&CMB_CODE_SECTION_START);
    code_size = (uint32_t)(&CMB_CODE_SECTION_END) - code_start_addr;
#else
    #error "not supported compiler"
#endif
    根據(jù)編譯器決定具體的棧地址 棧大小,,代碼區(qū)地址,代碼大小

    init_ok = true;
}

打印硬件信息

void cm_backtrace_firmware_info(void) {
    cmb_println(print_info[PRINT_FIRMWARE_INFO], fw_name, hw_ver, sw_ver);
}

如果是在用戶態(tài)發(fā)生的問(wèn)題,,也就是 thread 中出現(xiàn)的問(wèn)題 ,,根據(jù) OS 獲取對(duì)應(yīng)的線程棧地址和大 小

static void get_cur_thread_stack_info(uint32_t sp, uint32_t *start_addr, size_t *size) {
    CMB_ASSERT(start_addr);
    CMB_ASSERT(size);

#if (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_RTT)
    *start_addr = (uint32_t) rt_thread_self()->stack_addr;
    *size = rt_thread_self()->stack_size;
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_UCOSII)
    extern OS_TCB *OSTCBCur;

    *start_addr = (uint32_t) OSTCBCur->OSTCBStkBottom;
    *size = OSTCBCur->OSTCBStkSize * sizeof(OS_STK);
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_UCOSIII)
    #error "not implemented, I hope you can do this"
    //TODO 待實(shí)現(xiàn)
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_FREERTOS)
    *start_addr = (uint32_t)vTaskStackAddr();
    *size = vTaskStackSize() * sizeof( StackType_t );
#endif
}

獲取出錯(cuò)任務(wù)的任務(wù)名

static const char *get_cur_thread_name(void) {
#if (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_RTT)
    return rt_thread_self()->name;
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_UCOSII)
    extern OS_TCB *OSTCBCur;

#if OS_TASK_NAME_SIZE > 0 || OS_TASK_NAME_EN > 0
        return (const char *)OSTCBCur->OSTCBTaskName;
#else
        return NULL;
#endif /* OS_TASK_NAME_SIZE > 0 || OS_TASK_NAME_EN > 0 */

#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_UCOSIII)
    #error "not implemented, I hope you can do this"
    //TODO 待實(shí)現(xiàn)
#elif (CMB_OS_PLATFORM_TYPE == CMB_OS_PLATFORM_FREERTOS)
    return vTaskName();
#endif
}

打印出錯(cuò)任務(wù)的所有棧內(nèi)容

static void dump_cur_thread_stack(uint32_t stack_start_addr, size_t stack_size, uint32_t *stack_pointer) {
    cmb_println(print_info[PRINT_THREAD_STACK_INFO]);
    for (; (uint32_t) stack_pointer < stack_start_addr + stack_size; stack_pointer++) {
        cmb_println("  addr: %08x    data: %08x", stack_pointer, *stack_pointer);
    }
    cmb_println("====================================");
}

打印當(dāng)前系統(tǒng)的棧內(nèi)容

static void dump_main_stack(uint32_t stack_start_addr, size_t stack_size, uint32_t *stack_pointer) {
    cmb_println(print_info[PRINT_MAIN_STACK_INFO]);
    for (; (uint32_t) stack_pointer < stack_start_addr + stack_size; stack_pointer++) {
        cmb_println("  addr: %08x    data: %08x", stack_pointer, *stack_pointer);
    }
    cmb_println("====================================");
}

通過(guò)這里獲取對(duì)應(yīng)的棧中調(diào)用的所有函數(shù)信息

size_t cm_backtrace_call_stack(uint32_t *buffer, size_t size, uint32_t sp) {
    uint32_t stack_start_addr = main_stack_start_addr, pc;
    size_t depth = 0, stack_size = main_stack_size;
    bool regs_saved_lr_is_valid = false;

    if (on_fault) {
        /* first depth is PC */
        buffer[depth++] = regs.saved.pc;
        /* second depth is from LR, so need decrease a word to PC */
        pc = regs.saved.lr - sizeof(size_t);
        if ((pc >= code_start_addr) && (pc <= code_start_addr + code_size) && (depth < CMB_CALL_STACK_MAX_DEPTH)
                && (depth < size)) {
            buffer[depth++] = pc;
            regs_saved_lr_is_valid = true;
        }

#ifdef CMB_USING_OS_PLATFORM
        /* program is running on thread before fault */
        if (on_thread_before_fault) {
            get_cur_thread_stack_info(sp, &stack_start_addr, &stack_size);
        }
    } else {
        /* OS environment */
        if (cmb_get_sp() == cmb_get_psp()) {
            get_cur_thread_stack_info(sp, &stack_start_addr, &stack_size);
        }
#endif /* CMB_USING_OS_PLATFORM */

    }

    /* copy called function address */
    for (; sp < stack_start_addr + stack_size; sp += sizeof(size_t)) {
        /* the *sp value may be LR, so need decrease a word to PC */
        pc = *((uint32_t *) sp) - sizeof(size_t);
        if ((pc >= code_start_addr) && (pc <= code_start_addr + code_size) && (depth < CMB_CALL_STACK_MAX_DEPTH)
                && (depth < size)) {
            /* the second depth function may be already saved, so need ignore repeat */
            if ((depth == 2) && regs_saved_lr_is_valid && (pc == buffer[1])) {
                continue;
            }
            buffer[depth++] = pc;
        }
    }

    return depth;
}

這里則是通過(guò)調(diào)用上面的函數(shù),打印出來(lái)所有的調(diào)用棧信息

static void print_call_stack(uint32_t sp) {
    size_t i, cur_depth = 0;
    uint32_t call_stack_buf[CMB_CALL_STACK_MAX_DEPTH] = {0};

    cur_depth = cm_backtrace_call_stack(call_stack_buf, CMB_CALL_STACK_MAX_DEPTH, sp);

    for (i = 0; i < cur_depth; i++) {
        sprintf(call_stack_info + i * (8 + 1), "%08lx", call_stack_buf[i]);
        call_stack_info[i * (8 + 1) + 8] = ' ';
    }

    if (cur_depth) {
        cmb_println(print_info[PRINT_CALL_STACK_INFO], fw_name, CMB_ELF_FILE_EXTENSION_NAME, cur_depth * (8 + 1),
                call_stack_info);
    } else {
        cmb_println(print_info[PRINT_CALL_STACK_ERR]);
    }
}

斷言函數(shù)

void cm_backtrace_assert(uint32_t sp) {
    CMB_ASSERT(init_ok);

#ifdef CMB_USING_OS_PLATFORM
    uint32_t cur_stack_pointer = cmb_get_sp();
#endif

    cmb_println("");
    cm_backtrace_firmware_info();

#ifdef CMB_USING_OS_PLATFORM
    /* OS environment */
    這里是根據(jù)是中斷中發(fā)生 ASSERT 還是線程中發(fā)生 ASSERT 來(lái)決定輸出內(nèi)容
    if (cur_stack_pointer == cmb_get_msp()) {
        cmb_println(print_info[PRINT_ASSERT_ON_HANDLER]);

#ifdef CMB_USING_DUMP_STACK_INFO
        dump_main_stack(main_stack_start_addr, main_stack_size, (uint32_t *) sp);
#endif /* CMB_USING_DUMP_STACK_INFO */

    } else if (cur_stack_pointer == cmb_get_psp()) {
        cmb_println(print_info[PRINT_ASSERT_ON_THREAD], get_cur_thread_name());

#ifdef CMB_USING_DUMP_STACK_INFO
        uint32_t stack_start_addr;
        size_t stack_size;
        get_cur_thread_stack_info(sp, &stack_start_addr, &stack_size);
        dump_cur_thread_stack(stack_start_addr, stack_size, (uint32_t *) sp);
#endif /* CMB_USING_DUMP_STACK_INFO */

    }

#else

    /* bare metal(no OS) environment */
#ifdef CMB_USING_DUMP_STACK_INFO
    dump_main_stack(main_stack_start_addr, main_stack_size, (uint32_t *) sp);
#endif /* CMB_USING_DUMP_STACK_INFO */

#endif /* CMB_USING_OS_PLATFORM */

    print_call_stack(sp);
}

根據(jù)獲取到的狀態(tài)寄存器等 判斷具體是什么出錯(cuò)

static void fault_diagnosis(void) {
    if (regs.hfsr.bits.VECTBL) {
        cmb_println(print_info[PRINT_HFSR_VECTBL]);
    }
    if (regs.hfsr.bits.FORCED) {
        /* Memory Management Fault */
        if (regs.mfsr.value) {
            if (regs.mfsr.bits.IACCVIOL) {
                cmb_println(print_info[PRINT_MFSR_IACCVIOL]);
            }
            if (regs.mfsr.bits.DACCVIOL) {
                cmb_println(print_info[PRINT_MFSR_DACCVIOL]);
            }
            if (regs.mfsr.bits.MUNSTKERR) {
                cmb_println(print_info[PRINT_MFSR_MUNSTKERR]);
            }
            if (regs.mfsr.bits.MSTKERR) {
                cmb_println(print_info[PRINT_MFSR_MSTKERR]);
            }

    ...

    /* Debug Fault */
    if (regs.hfsr.bits.DEBUGEVT) {
        if (regs.dfsr.value) {
            if (regs.dfsr.bits.HALTED) {
                cmb_println(print_info[PRINT_DFSR_HALTED]);
            }
            if (regs.dfsr.bits.BKPT) {
                cmb_println(print_info[PRINT_DFSR_BKPT]);
            }
            if (regs.dfsr.bits.DWTTRAP) {
                cmb_println(print_info[PRINT_DFSR_DWTTRAP]);
            }
            if (regs.dfsr.bits.VCATCH) {
                cmb_println(print_info[PRINT_DFSR_VCATCH]);
            }
            if (regs.dfsr.bits.EXTERNAL) {
                cmb_println(print_info[PRINT_DFSR_EXTERNAL]);
            }
        }
    }
}

如果是 M4 或者是 M7 由于自帶了 FPU ,,出錯(cuò)時(shí) 如果開啟了 FPU sp 中存的內(nèi)容有很大一部分是 與 FPU 有關(guān)的,,所以需要排除這一部分

#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7)
static uint32_t statck_del_fpu_regs(uint32_t fault_handler_lr, uint32_t sp) {
    statck_has_fpu_regs = (fault_handler_lr & (1UL << 4)) == 0 ? true : false;

    /* the stack has S0~S15 and FPSCR registers when statck_has_fpu_regs is true, double word align */
    return statck_has_fpu_regs == true ? sp + sizeof(size_t) * 18 : sp;
}
#endif

最重要的追蹤函數(shù)主體

void cm_backtrace_fault(uint32_t fault_handler_lr, uint32_t fault_handler_sp) {

    獲取到棧指針
    uint32_t stack_pointer = fault_handler_sp, saved_regs_addr = stack_pointer;
    const char *regs_name[] = { "R0 ", "R1 ", "R2 ", "R3 ", "R12", "LR ", "PC ", "PSR" };

#ifdef CMB_USING_DUMP_STACK_INFO
    拿到系統(tǒng)堆棧信息
    uint32_t stack_start_addr = main_stack_start_addr;
    size_t stack_size = main_stack_size;
#endif

    確保被初始化過(guò),,否則系統(tǒng)堆棧信息等都可能是錯(cuò)的
    CMB_ASSERT(init_ok);
    /* only call once */
    CMB_ASSERT(!on_fault);

    on_fault = true;

    cmb_println("");
    cm_backtrace_firmware_info();

#ifdef CMB_USING_OS_PLATFORM
    有操作系統(tǒng)下,判斷出問(wèn)題點(diǎn)是在中斷還是線程部分,,打印相關(guān)信息
    on_thread_before_fault = fault_handler_lr & (1UL << 2);
    /* check which stack was used before (MSP or PSP) */
    if (on_thread_before_fault) {
        cmb_println(print_info[PRINT_FAULT_ON_THREAD], get_cur_thread_name() != NULL ? get_cur_thread_name() : "NO_NAME");
        saved_regs_addr = stack_pointer = cmb_get_psp();

#ifdef CMB_USING_DUMP_STACK_INFO
        get_cur_thread_stack_info(stack_pointer, &stack_start_addr, &stack_size);
#endif /* CMB_USING_DUMP_STACK_INFO */

    } else {
        cmb_println(print_info[PRINT_FAULT_ON_HANDLER]);
    }
#else
    /* bare metal(no OS) environment */
    cmb_println(print_info[PRINT_FAULT_ON_HANDLER]);
#endif /* CMB_USING_OS_PLATFORM */

    /* delete saved R0~R3, R12, LR,PC,xPSR registers space */
    stack_pointer += sizeof(size_t) * 8;

#if (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7)
    stack_pointer = statck_del_fpu_regs(fault_handler_lr, stack_pointer);
#endif /* (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M4) || (CMB_CPU_PLATFORM_TYPE == CMB_CPU_ARM_CORTEX_M7) */

    輸出棧中所有內(nèi)容
    /* dump stack information */
#ifdef CMB_USING_DUMP_STACK_INFO
#ifdef CMB_USING_OS_PLATFORM
    if (on_thread_before_fault) {
        dump_cur_thread_stack(stack_start_addr, stack_size, (uint32_t *) stack_pointer);
    } else {
        dump_main_stack(stack_start_addr, stack_size, (uint32_t *) stack_pointer);
    }
#else
    /* bare metal(no OS) environment */
    dump_main_stack(stack_start_addr, stack_size, (uint32_t *) stack_pointer);
#endif /* CMB_USING_OS_PLATFORM */
#endif /* CMB_USING_DUMP_STACK_INFO */

    輸出寄存器中的信息
    /* dump register */
    cmb_println(print_info[PRINT_REGS_TITLE]);

    regs.saved.r0        = ((uint32_t *)saved_regs_addr)[0];  // Register R0
    regs.saved.r1        = ((uint32_t *)saved_regs_addr)[1];  // Register R1
    regs.saved.r2        = ((uint32_t *)saved_regs_addr)[2];  // Register R2
    regs.saved.r3        = ((uint32_t *)saved_regs_addr)[3];  // Register R3
    regs.saved.r12       = ((uint32_t *)saved_regs_addr)[4];  // Register R12
    regs.saved.lr        = ((uint32_t *)saved_regs_addr)[5];  // Link register LR
    regs.saved.pc        = ((uint32_t *)saved_regs_addr)[6];  // Program counter PC
    regs.saved.psr.value = ((uint32_t *)saved_regs_addr)[7];  // Program status word PSR


    cmb_println("  %s: %08x  %s: %08x  %s: %08x  %s: %08x", regs_name[0], regs.saved.r0,
                                                            regs_name[1], regs.saved.r1,
                                                            regs_name[2], regs.saved.r2,
                                                            regs_name[3], regs.saved.r3);
    cmb_println("  %s: %08x  %s: %08x  %s: %08x  %s: %08x", regs_name[4], regs.saved.r12,
                                                            regs_name[5], regs.saved.lr,
                                                            regs_name[6], regs.saved.pc,
                                                            regs_name[7], regs.saved.psr.value);
    cmb_println("==============================================================");

    /* the Cortex-M0 is not support fault diagnosis */
#if (CMB_CPU_PLATFORM_TYPE != CMB_CPU_ARM_CORTEX_M0)
    regs.syshndctrl.value = CMB_SYSHND_CTRL;  // System Handler Control and State Register
    regs.mfsr.value       = CMB_NVIC_MFSR;    // Memory Fault Status Register
    regs.mmar             = CMB_NVIC_MMAR;    // Memory Management Fault Address Register
    regs.bfsr.value       = CMB_NVIC_BFSR;    // Bus Fault Status Register
    regs.bfar             = CMB_NVIC_BFAR;    // Bus Fault Manage Address Register
    regs.ufsr.value       = CMB_NVIC_UFSR;    // Usage Fault Status Register
    regs.hfsr.value       = CMB_NVIC_HFSR;    // Hard Fault Status Register
    regs.dfsr.value       = CMB_NVIC_DFSR;    // Debug Fault Status Register
    regs.afsr             = CMB_NVIC_AFSR;    // Auxiliary Fault Status Register

    fault_diagnosis();
#endif

    print_call_stack(stack_pointer);
}

查錯(cuò)

當(dāng)發(fā)生錯(cuò)誤以后,,使用 addr2line 命令,查看函數(shù)調(diào)用棧詳細(xì)信息,,并定位錯(cuò)誤代碼

Addr2line 工具(它是標(biāo)準(zhǔn)的 GNU Binutils 中的一部分)是一個(gè)可以將指令的地址和可執(zhí)行映像轉(zhuǎn)換成文件名,、函數(shù)名和源代碼行數(shù)的工具。這種功能對(duì)于將跟蹤地址轉(zhuǎn)換成更有意義的內(nèi)容來(lái)說(shuō)簡(jiǎn)直是太棒了,。

通過(guò)上面的函數(shù),,會(huì)在串口或者什么其他輸出地方,輸出棧的函數(shù)指針的具體地址,,進(jìn)而就可以定位 出來(lái)具體是哪行出錯(cuò)了,,當(dāng)然調(diào)用 addr2line 命令應(yīng)該在程序的 bin/mot/elf 文件目錄下

如下,只需要到對(duì)應(yīng)的目錄下執(zhí)行下面的代碼即可

Firmware name: xxxxx, hardware version: xxxxx, software version: xxxxx
Fault on thread God
=================== Registers information ====================
  R0 : 2000ba2c  R1 : 2000903c  R2 : 00140006  R3 : 00140006
  R12: 2000a594  LR : 0807a5ad  PC : 08076ea8  PSR: 01070000
==============================================================
Bus fault is caused by precise data access violation
The bus fault occurred address is 0014000e
Show more call stack info by run: addr2line -e xxxx.elf -a -f 08076ea8 0807a5a9 0807d9dc 080769bf 0807d9d9 0807d517 0807d32b 080563bd 0804c207 0804c357 0804e65b 0804f89d 0804f6c7 080742af 080742c1 08077005

Summary

總的來(lái)說(shuō)大部分和寄存器以及出錯(cuò)相關(guān)的信息基本都來(lái)自于

  • Cortex M3 Technical Reference Manual

  • Cortex M4 Technical Reference Manual

  • Cortex M7 Technical Reference Manual

如果只用 trace 還不夠完美,,需要有一個(gè)用來(lái)長(zhǎng)時(shí)間保存出錯(cuò)信息的記錄功能,。

比如把所有出錯(cuò)信息寫到 flash 中去,或者是 log 記錄中去,。

CmBacktrace 的作者也提供了對(duì)應(yīng)的功能,,不過(guò)其中用 flash 來(lái)做數(shù)據(jù)庫(kù),有點(diǎn)沒意義,。 flash 燒寫次數(shù)有限,,而且刷寫新內(nèi)容時(shí)需要 sector 式的擦除,對(duì)于每條數(shù)據(jù)存儲(chǔ)也需要定義嚴(yán)格的格式 不是很推薦吧,,會(huì)上數(shù)據(jù)庫(kù)的應(yīng)用,,也不會(huì)差一個(gè) SD 的。

當(dāng)然你也可以在 CmBacktrace 中增加一些其他信息的代碼,,比如當(dāng)發(fā)生錯(cuò)誤以后,,如果能獲取到電 池電量的話,盡量獲取到,,然后輸出,,因?yàn)楹苡锌赡苁且驗(yàn)榈碗娪|發(fā)了什么異常情況,而這種情況很 可能并不一定,,什么都有,,所以用低電排除一些沒必要追究的異常,是有意義的

Quote

http://blog.csdn.net/jean_bai/article/details/45952247

https://github.com/armink/CmBacktrace

https://github.com/armink/EasyLogger

https://github.com/armink/EasyFlash

http://blog.csdn.net/lhf_tiger/article/details/9088609

https://www.ibm.com/developerworks/cn/linux/l-graphvis/

http://blog.csdn.net/whz_zb/article/details/7604760


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多