杰理可視化SDK--系統死機異常調試
- 系統異常原因
- 杰理SDK異常調試準備工作
- 杰理SDK系統異常定位
- 異常代碼示例1
- 異常代碼示例2
在使用杰理可視化SDK進行軟件開發時,往往會遇到一些系統異常問題,系統異常是指芯片在運行代碼時,由于軟件或硬件狀態出錯,當錯誤狀態未在硬件或軟件程序設計覆蓋的容錯范圍,就會引起系統處于未知狀態的異常。異常的結果是觸發了“系統復位”或者進入“系統異常中斷函數”。本篇文章介紹了使用杰理SDK定位系統運行過程中出現死機異常的一些方法。
系統異常原因
常見的系統異常原因主要有以下原因:
- CPU內部觸發的異常
程序跑飛:CPU運行到程序非指定地址軟件流程,該異常通常由一些沒有正確初始化的函數指針變量引起。
除0異常:CPU在除法運算中除數為0,就會觸發除0異常。
非對齊內存訪問:CPU運行WORD字節內存訪問指令時,尋址寄存器不是4對齊的值,或者運行HALF-WORD內存訪問指令時,尋址寄存器不是2對齊的值,就會觸發非對齊內存訪問異常。
堆棧溢出:當CPU的堆棧超出所設定的限制范圍時,就會出現堆棧溢出異常,該異常通常與任務用到的堆棧大于配置的堆棧大小引起。 - 內存相關異常
讀寫非法內存地址:當CPU讀寫到非法的內存地址,非法內存地址主要包括:空白地址,只讀地址、程序員使用MPU保護的內存地址。該異常主要由于buff野指針引起,或者動態申請內存在free buff后,還在訪問buff的數據。 - 外設觸發的異常
看門狗超時:系統由于長時間沒有清看門狗導致的系統異常,該問題常見原因是CPU負載過高,長時間沒有進idle任務,或者在某個軟件流程死循環,導致系統沒有清看門狗。
杰理SDK異常調試準備工作
-
可視化配置工具配置打印異常信息
在“板級配置”->“調試串口”選項中打開“打印異常信息”。
-
生成lst文件
.lst文件是由ELF (Executable and Linkable Format) 文件通過objdump工具反匯編得到的列表文件。通過objdump命令生成的.lst文件可以顯示源代碼對應的匯編指令,這在軟件調試和死機問題定位時非常有用。
SDK默認不會生成.lst文件,需要手動修改download的腳本代碼自動調用objdump來生成lst文件,這里是修改SDK目錄下download.c文件(SDK/cpu/brxx/tools),修改如下圖,表示將使用sdk.elf文件生成sdk.lst文件。
上面修改后每次編譯工程代碼,tools目錄下會生成一個sdk.lst文件。
lst文件它通常包含了由軟件生成的各種信息的列表, 是由objdump工具反匯編得到, 它包含了比.map文件更詳細的調試信息,如每條指令的地址等。 在出現問題時提供重要的調試線索。 例如通過查看棧幀結構和在.lst文件中查找特定寄存器的地址,開發者可以快速定位到問題所在。
杰理SDK系統異常定位
異常代碼示例1
如下程序中在其中的一個函數中插入了一段死循環。
當程序運行到這個位置時,可以看到程序日志打印中刷屏打印timer_no_response最后死機。如下圖
具體來說timer_no_response是由于某個定時器沒有響應而導致。需要排查是否是程序中的某個函數運行占用了太大CPU資源沒有釋放導致定時器的處理沒有能正常運行響應導致,從而導致系統崩潰死機。
這里我們可以借助lst文件和死機打印時的backtrace,定位到造成異常死機的位置。
這里我們看RETS和RETI寄存器
RETI(Return from Interrupt):這是中斷返回指令的寄存器,它將堆棧中保存的程序計數器的地址取出并送回PC,使程序從主程序的中斷處繼續執行。需要注意的是RETI所在位置的指令未被執行。
RETS(Return from Subroutine):這是從子程序返回的指令,通常用在非中斷的子程序調用中。它的主要作用是將堆棧中的返回地址彈出到程序計數器(PC),以便程序可以繼續執行調用子程序之后的下一條指令。
根據上面RETI信息排查到代碼action_a2dp_play_next()函數中出現的問題,即定位到了異常代碼的位置。
異常代碼示例2
如下代碼中演示了空指針引用造成的系統異常。如下圖代碼中定義了一個指向函數的指針,并將其初始化為NULL。接下來,我們嘗試通過調用ptr()來執行該空函數指針,但由于ptr是空指針,因此調用了之后會導致程序崩潰并死機。
從耳機運行日志log中發現當代碼運行到這段程序的時候發生了死機。
由前面的方法查看lst文件和RETS寄存器可以定位到出問題代碼發生在
action_enter_low_latency_mode()函數中。