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

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

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

什么是CmBacktrace?在RT-Thread中使用CmBacktrace的例子

lPCU_elecfans ? 來源:未知 ? 作者:李倩 ? 2018-07-09 10:31 ? 次閱讀

對(duì)于從C51 、MSP430 等簡(jiǎn)單單片機(jī)轉(zhuǎn)而使用更加復(fù)雜的 ARM 新人來說,時(shí)不時(shí)出現(xiàn)的"hard falut"死機(jī)會(huì)讓新人瞬間懵掉。定位錯(cuò)誤的方法也往往是連接上仿真器,一步步 F10/F11單步,定位到具體的錯(cuò)誤代碼,再去猜測(cè)、排除、推敲錯(cuò)誤原因,這種過程十分痛苦,且花費(fèi)的時(shí)間很長(zhǎng)。

當(dāng)然,也有部分開發(fā)者通過故障寄存器信息來定位故障原因及故障代碼地址,雖然這樣能解決一小部分問題,但是重復(fù)的、繁瑣的分析過程也會(huì)耽誤很多時(shí)間。而且對(duì)于一些復(fù)雜問題,只依靠代碼地址是無法解決的,必須得還原錯(cuò)誤現(xiàn)場(chǎng)的函數(shù)調(diào)用邏輯關(guān)系。雖然連接仿真器可以查看到的函數(shù)調(diào)用棧,但故障狀態(tài)下是無法顯示的,所以還是得一步步F10/F11單步去定位錯(cuò)誤代碼的位置。另外,很多產(chǎn)品真機(jī)調(diào)試時(shí)必須斷開仿真器,這又使定位錯(cuò)誤代碼雪上加霜。

為了能讓開發(fā)者更快的知道造成hard falut 的原因,更快的定位到錯(cuò)誤代碼的位置,本應(yīng)用筆記將一步步介紹CmBacktrace 的相關(guān)知識(shí)和使用方法,讓開發(fā)者能不費(fèi)吹灰之力就找出代碼中的問題所在。

本文的結(jié)構(gòu)

本文首先介紹了什么是 CmBacktrace,然后介紹了使用 CmBacktrace 要做的準(zhǔn)備工作,接著介紹了在RT-Thread中使用CmBacktrace的例子,最后總結(jié)了使用 CmBacktrace 時(shí)的常見問題。通過這些講解,希望開發(fā)者能更快上手 CmBacktrace。

CmBacktrace 是什么

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

主要特性如下:

支持的錯(cuò)誤包括:

斷言(assert)

故障(Hard Fault, Memory Management Fault, Bus Fault, Usage Fault, Debug Fault)

故障原因自動(dòng)診斷:可在故障發(fā)生時(shí),自動(dòng)分析出故障的原因,定位發(fā)生故障的代碼位置,而無需再手動(dòng)分析繁雜的故障寄存器;

輸出錯(cuò)誤現(xiàn)場(chǎng)的函數(shù)調(diào)用棧(需配合 addr2line 工具進(jìn)行精確定位),還原發(fā)生錯(cuò)誤時(shí)的現(xiàn)場(chǎng)信息,定位問題代碼位置、邏輯更加快捷、精準(zhǔn)。也可以在正常狀態(tài)下使用該庫,獲取當(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 主棧;

故障診斷信息支持多國語言(目前:簡(jiǎn)體中文、英文);

適配 Cortex-M0/M3/M4/M7 MCU;

支持 IAR、KEIL、GCC 編譯器;

準(zhǔn)備工作

準(zhǔn)備 addr2line

在 https://github.com/armink/CmBacktrace/tree/master/tools/addr2line 頁面中下載 addr2line(需要按照自己的系統(tǒng)版本下載),然后將下載下來的addr2line 拷貝至C:\Windows下 ,這樣就可以使用 addr2line 了。

ENV配置

RT-Thread 已經(jīng)對(duì) CmBacktrace 做了適配,直接在 ENV 使能 CmBacktrace 就可以使用了。

下面介紹如何在 ENV 中配置CmBacktrace:

打開 ENV,進(jìn)入相應(yīng)的 bsp 目錄

輸入 menuconfig

進(jìn)入 RT-Thread online packages -> tools packages

使能 CmBacktrace

進(jìn)入 CmBacktrace 配置界面

選擇自己的 CPU 平臺(tái)

選擇打印的語言

選擇版本,推薦使用最新版

確認(rèn)宏定義

CmBacktrace 的運(yùn)行需要知道存放代碼的 SECTION 的開始地址和結(jié)束地址以及棧的 SECTION 的開始地址和結(jié)束地址。用戶只需要查看 cmb_def.h 文件里默認(rèn)定義的 CMB_CSTACK_BLOCK_NAME 和 CMB_CODE_SECTION_NAME 這兩個(gè)宏是否正確即可。如不正確,用戶需要根據(jù)分散加載文件和啟動(dòng)文件來確定這兩個(gè)宏的值并在 cmb_cfg.h 里重新定義這兩個(gè)宏。

這里以 rt1052 的 mdk 工程為例進(jìn)行講解如何在工程里找到這兩個(gè)宏的值。首先找 CMB_CSTACK_BLOCK_NAME 的值,我們打開工程里的啟動(dòng)文件,可以在文件的開頭看到這樣一段代碼

AREA RESET, DATA, READONLY EXPORT __Vectors EXPORT __Vectors_End EXPORT __Vectors_Size IMPORT |Image$$ARM_LIB_STACK$$ZI$$Limit| __Vectors DCD |Image$$ARM_LIB_STACK$$ZI$$Limit| ; Top of Stack

Image\$\$ARM_LIB_STACK\$\$ZI\$\$Limit 就是我們要找的內(nèi)容了,因?yàn)榇a里會(huì)自動(dòng)拼接上最后的 $$Limit,所以 CMB_CSTACK_BLOCK_NAME 的值應(yīng)該是 Image\$\$ARM_LIB_STACK\$\$ZI。

CMB_CODE_SECTION_NAME 的值在分散加載文件里尋找,分散加載文件可以點(diǎn)擊 MDK的 Options -> Linker 選項(xiàng)面板里的 Edit... 按紐打開

我們可以找到這樣一段代碼

ER_IROM1 m_text_start m_text_size ; load address = execution address { * (RESET,+FIRST) * (InRoot$$Sections) .ANY (+RO) }

保存有 .ANY (+RO) 的 SECTION 名字就是我們要找的值,所以,CMB_CODE_SECTION_NAME 的值為 ER_IROM1。

開啟C99

CmBacktrace 的使用需要 C99 的支持,使用 MDK 的開發(fā)者可以在 Options -> C/C++面板中勾選 C99 Mode選項(xiàng)。

使用IAR的開發(fā)者,可以在 Options -> C/C++ Compiler 中選擇 C99。

使用 GCC 進(jìn)行編譯的用戶,在編譯配置中增加-std=c99即可 。

確定初始化參數(shù)

在使用 CmBacktrace 之前需要先調(diào)用下初始化函數(shù),函數(shù)原型如下:

void cm_backtrace_init(const char *firmware_name, const char *hardware_ver, const char *software_ver)

CmBacktrace 的初始化函數(shù)需要 3 個(gè)參數(shù),第一個(gè)參數(shù)是固件名字,第二個(gè)參數(shù)是硬件版本,第三個(gè)參數(shù)是軟件版本。這三個(gè)參數(shù)會(huì)在發(fā)生 hard fault時(shí)打印出來,firmware_name需要填寫生成的固件名稱,錯(cuò)誤填寫會(huì)導(dǎo)致在使用 addr2line 時(shí)無法找到文件。hardware_ver和software_ver建議填寫真實(shí)的軟硬件版本號(hào),方便后期調(diào)試和維護(hù)。在 cmb_port.c 文件中,我們可以看到 RT-Thread 已經(jīng)將 rt_cm_backtrace_init 函數(shù)進(jìn)行了自動(dòng)初始化,默認(rèn)的三個(gè)參數(shù)分別是rtthread,1.0,1.0,開發(fā)者需要按照實(shí)際情況進(jìn)行更改。

使用示例

CmBacktrace 提供了一個(gè)測(cè)試函數(shù),提供除零測(cè)試和執(zhí)行非對(duì)齊訪問的測(cè)試。當(dāng)做完上面的準(zhǔn)備工作后,開發(fā)者可以直接將工程編譯,下載進(jìn)板子里,進(jìn)行測(cè)試,判斷 CmBacktrace 是否正常工作。

CmBacktrace 導(dǎo)出到 finsh shell 中的測(cè)試函數(shù)命令為cmb_test,輸入 cmb_test DIVBYZERO 就是進(jìn)行除零測(cè)試,輸入 cmb_test UNALIGNED 就是執(zhí)行非對(duì)齊訪問的測(cè)試。

我們看下運(yùn)行完除零測(cè)試的結(jié)果

msh />cmb_test DIVBYZERO thread pri status sp stack size max used left tick error -------- --- ------- ---------- ---------- ------ ---------- --- tshell 20 ready 0x00000100 0x00001000 23% 0x00000009 000 phy 30 suspend 0x0000006c 0x00000200 30% 0x00000001 000 tcpip 10 suspend 0x000000b4 0x00000800 17% 0x00000014 000 etx 12 suspend 0x00000088 0x00000400 13% 0x00000010 000 erx 12 suspend 0x00000088 0x00000400 13% 0x00000010 000 mmcsd_de 22 suspend 0x00000090 0x00000400 49% 0x00000013 000 tidle 31 ready 0x00000054 0x00000100 32% 0x00000018 000 main 10 suspend 0x00000064 0x00000800 35% 0x00000012 000 Firmware name: rtthread-imxrt, hardware version: 1.0, software version: 1.0 Fault on thread tshell ===== Thread stack information ===== addr: 80002ad0 data: 00000012 addr: 80002ad4 data: 6002ae58 addr: 80002ad8 data: 80001a40 addr: 80002adc data: 6000b575 addr: 80002ae0 data: 80001a40 addr: 80002ae4 data: 80001a49 addr: 80002ae8 data: 00000000 addr: 80002aec data: 00000000 addr: 80002af0 data: 00000000 addr: 80002af4 data: 00000000 addr: 80002af8 data: 00000000 addr: 80002afc data: 00000000 addr: 80002b00 data: 00000000 addr: 80002b04 data: 00000000 addr: 80002b08 data: 20000c7c addr: 80002b0c data: 00000012 addr: 80002b10 data: 80001a40 addr: 80002b14 data: 20000c7c addr: 80002b18 data: 00000001 addr: 80002b1c data: deadbeef addr: 80002b20 data: deadbeef addr: 80002b24 data: deadbeef addr: 80002b28 data: deadbeef addr: 80002b2c data: 60019ffb addr: 80002b30 data: 00000001 addr: 80002b34 data: 0000000d addr: 80002b38 data: 00000000 addr: 80002b3c data: 60015a7b addr: 80002b40 data: 23232323 ==================================== =================== Registers information ==================== R0 : 0000000a R1 : 00000000 R2 : 0000004f R3 : 80808000 R12: 01010101 LR : 6000c5ad PC : 6000c5c8 PSR: 41000000 ============================================================== Usage fault is caused by Indicates a divide by zero has taken place (can be set only if DIV_0_TRP is set) Show more call stack info by run: addr2line -e rtthread-imxrt.axf -a -f 6000c5c8 6000c5a9 6002ae54 6000b571 60019ff7 60015a77

CmBacktrace 首先打印出了發(fā)生 hard falut 時(shí)的所有線程信息,接著打印了固件名字和軟硬件版本號(hào),再打印了錯(cuò)誤是發(fā)生在 tshell 這個(gè)線程里面的(因?yàn)槲覀兪窃?tshell 這個(gè)線程里調(diào)用的除零測(cè)試函數(shù)),緊接著打印的是線程的棧信息和寄存器信息。最后兩行信息是最重要的,倒數(shù)第二行介紹了發(fā)生故障的原因,是因?yàn)槌阍斐傻?。最后一行提示如果需要獲取函數(shù)調(diào)用棧,需要在 addr2line 中運(yùn)行 CmBacktrace 給出的參數(shù)。

在使用addr2line 之前我們要先確認(rèn)保存了工程對(duì)象文件的文件夾位置。使用mdk的開發(fā)者,可以在 Options -> Output 面板中查看,設(shè)置對(duì)象文件的保存路徑

使用IAR的開發(fā)者,可以在 Options -> General Options 面板的Output選項(xiàng)中查看和設(shè)置。

我們將 run:后面的所有內(nèi)容都復(fù)制下來,然后進(jìn)入保存了工程生成的對(duì)象文件的文件夾,打開env,將剛剛復(fù)制的內(nèi)容粘貼上去,按下回車,錯(cuò)誤現(xiàn)場(chǎng)的函數(shù)調(diào)用棧就會(huì)輸出出來,我們看下剛剛進(jìn)行除零測(cè)試時(shí)的函數(shù)調(diào)用棧的信息

> addr2line -e rtthread-imxrt.axf -a -f 6000c5c8 6000c5a9 6002ae54 6000b571 60019ff7 60015a77 0x6000c5c8 cmb_test D:\rt-thread\bsp\imxrt1052-evk/packages\CmBacktrace-v1.2.0\/cmb_port.c:87 0x6000c5a9 cmb_test D:\rt-thread\bsp\imxrt1052-evk/packages\CmBacktrace-v1.2.0\/cmb_port.c:82 0x6002ae54 FSymTab$$Base ??:? 0x6000b571 msh_get_cmd D:\rt-thread\bsp\imxrt1052-evk/..\..\components\finsh\/msh.c:312 0x60019ff7 msh_exec D:\rt-thread\bsp\imxrt1052-evk/..\..\components\finsh\/msh.c:335 0x60015a77 finsh_thread_entry D:\rt-thread\bsp\imxrt1052-evk/..\..\components\finsh\/shell.c:613

我們可以看到,CmBacktrace 不僅僅定位出了是 cmb_port.c里第87行產(chǎn)生的問題,還打印出了函數(shù)調(diào)用邏輯關(guān)系,方便開發(fā)者進(jìn)行 BUG 修復(fù)。

常見問題

使用前必須確認(rèn)自己的 MCU 是 ARM Cortex-M0(+)/M3/M4/M7 架構(gòu),其他架構(gòu)暫不支持。

使用前要確定 CMBCSTACKBLOCKNAME 和 CMBCODESECTIONNAME 兩個(gè)宏的宏定義,如果定義錯(cuò)誤,CmBacktrace會(huì)無法正確使用。

初始化時(shí)要輸入正確的固件名稱,不然使用 addr2line 時(shí)會(huì)提示找不到文件

當(dāng)線程的棧被寫穿時(shí),CmBacktrace 無法正常使用。

聲明:本文內(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)投訴
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5294

    瀏覽量

    119816
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10804

    瀏覽量

    210833
  • 仿真器
    +關(guān)注

    關(guān)注

    14

    文章

    1014

    瀏覽量

    83591

原文標(biāo)題:一波“HardFault異常”正在接近 ,學(xué)會(huì)了這套路,今晚吃雞!-【周四RTOS專欄】

文章出處:【微信號(hào):elecfans,微信公眾號(hào):電子發(fā)燒友網(wǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    請(qǐng)問有人使用cmBacktrace工具嗎?

    \cmBacktrack_project_test\cmbackTrace\online_gprs/src\main.c:520x080002ff__rt_entry_main通過 工具定位出來的是 main.c
    發(fā)表于 12-24 08:59

    如何在RT-Thread中使CmBacktrace

    本文描述了 RT-Thread 中使CmBacktrace。
    發(fā)表于 03-30 07:01

    如何使用STM32HAL庫去移植CmBacktrace?

    CmBacktrace是什么?為什么選擇CmBacktrace?CmBacktrace如何去使用?如何使用STM32HAL庫去移植CmBacktrace?
    發(fā)表于 07-01 10:40

    CmBacktrace是什么?主要特性是什么

    說明:本文來自armink大佬的CmBacktrace庫文檔。CmBacktrace: ARM Cortex-M 系列 MCU 錯(cuò)誤追蹤庫0、CmBacktrace 是什么CmBacktrac
    發(fā)表于 01-25 07:01

    CmBacktrace打印hardfault信息時(shí)提示棧溢出是何原因?如何解決

    平臺(tái)的example初始移植一開始按照demo里給的方式,先初始化Cmbacktrace,然后注冊(cè)異常鉤子函數(shù),鉤子函數(shù)里執(zhí)行cm_backtrace_fault函數(shù),然后另外一個(gè)線程里執(zhí)行除零操作
    發(fā)表于 07-05 11:18

    一步步介紹CmBacktrace的相關(guān)知識(shí)和使用方法

    了 什么是 CmBacktrace,然后介紹了使用 CmBacktrace 要做的準(zhǔn)備工作,接著介紹了 RT-Thread中使
    發(fā)表于 10-26 15:44

    RT-Thread編程指南

    RT-Thread編程指南——RT-Thread開發(fā)組(2015-03-31)。RT-Thread做為國內(nèi)有較大影響力的開源實(shí)時(shí)操作系統(tǒng),本文是RT-Thread實(shí)時(shí)操作系統(tǒng)的編程指南
    發(fā)表于 11-26 16:06 ?0次下載

    RT-Thread用戶手冊(cè)

    RT-Thread用戶手冊(cè)——本書是RT-Thread的編程手冊(cè),用于指導(dǎo)RT-Thread實(shí)時(shí)操作系統(tǒng)環(huán)境下如何進(jìn)行編 程。
    發(fā)表于 11-26 16:16 ?0次下載

    RT-Thread全球技術(shù)大會(huì):KconfigRT-Thread中的工作機(jī)制

    RT-Thread全球技術(shù)大會(huì):KconfigRT-Thread中的工作機(jī)制 ? ? ? ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 14:49 ?1493次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會(huì):Kconfig<b class='flag-5'>在</b><b class='flag-5'>RT-Thread</b>中的工作機(jī)制

    RT-Thread全球技術(shù)大會(huì):RT-Thread上編寫測(cè)試用例

    RT-Thread全球技術(shù)大會(huì):RT-Thread上編寫測(cè)試用例 ? ? ? ? ? 審核編輯:彭靜
    的頭像 發(fā)表于 05-27 16:28 ?1438次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會(huì):<b class='flag-5'>在</b><b class='flag-5'>RT-Thread</b>上編寫測(cè)試用例

    RT-Thread全球技術(shù)大會(huì):RT-Thread中使用棧幀來調(diào)試程序

    百問網(wǎng)科技CTO韋東山,RT-Thread全球技術(shù)大會(huì)大會(huì)中,以RT-Thread中使用棧幀來調(diào)試程序?yàn)橹黝}進(jìn)行了介紹。
    的頭像 發(fā)表于 05-28 09:33 ?1789次閱讀
    <b class='flag-5'>RT-Thread</b>全球技術(shù)大會(huì):<b class='flag-5'>在</b><b class='flag-5'>RT-Thread</b><b class='flag-5'>中使</b>用棧幀來調(diào)試程序

    RT-Thread學(xué)習(xí)筆記 RT-Thread的架構(gòu)概述

    RT-Thread 簡(jiǎn)介 作為一名 RTOS 的初學(xué)者,也許你對(duì) RT-Thread 還比較陌生。然而,隨著你的深入接觸,你會(huì)逐漸發(fā)現(xiàn) RT-Thread 的魅力和它相較于其他同類型 RTOS
    的頭像 發(fā)表于 07-09 11:27 ?4458次閱讀
    <b class='flag-5'>RT-Thread</b>學(xué)習(xí)筆記 <b class='flag-5'>RT-Thread</b>的架構(gòu)概述

    RT-Thread文檔_RT-Thread 簡(jiǎn)介

    RT-Thread文檔_RT-Thread 簡(jiǎn)介
    發(fā)表于 02-22 18:22 ?5次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> 簡(jiǎn)介

    RT-Thread文檔_RT-Thread SMP 介紹與移植

    RT-Thread文檔_RT-Thread SMP 介紹與移植
    發(fā)表于 02-22 18:31 ?9次下載
    <b class='flag-5'>RT-Thread</b>文檔_<b class='flag-5'>RT-Thread</b> SMP 介紹與移植

    基于RT-Thread Studio學(xué)習(xí)

    前期準(zhǔn)備:從官網(wǎng)下載 RT-Thread Studio,弄個(gè)賬號(hào)登陸,開啟rt-thread學(xué)習(xí)之旅。
    的頭像 發(fā)表于 05-15 11:00 ?3775次閱讀
    基于<b class='flag-5'>RT-Thread</b> Studio學(xué)習(xí)