1、背景
在嵌入式開發中,我們經常遇到的一個問題是:寫代碼一個不小心,就制造了一個bug,C語言中bug的威力大家也心知肚明——可以直接把系統搞掛!
即大家常見的系統死機、系統重啟等等;而問題的來源或者根因,又常常使得我們束手無策,只好采用“列印”大法,一遍遍的加printf,
而每次改代碼又要經歷痛苦的“編譯-燒寫-運行-復現”這個程序,不知不覺,一天過去了,bug還沒解,
所以我們經常想,要是系統能直接告訴我們bug在哪、是什么錯誤導致的就好了,直接改代碼分分鐘搞定,可以節省很多開發時間!
這也是我們常用一些仿真器(如JLINK)的原因,系統掛死后可以掛上仿真器,查看PC在哪,通過bt查看呼叫堆疊等來幫助我們定位,
而這又對硬體有了一定的要求——要能支持仿真器連接,有時還要開發者折騰一下環境,
我們的HaaS100雖然也支持硬體連接仿真器(參考上一篇帖子:HaaS100開發除錯系列 之 如何使用J-Link仿真器除錯代碼),
這里我們告知大家一個更方便定位系統例外死機的方法——AliOS Things的診斷除錯組件,
2、診斷除錯組件簡介
診斷除錯包含的內容很多,前面我們介紹過一些除錯命令,參見文章《一文輕松入門HaaS100診斷除錯系統》,
本文我們重點介紹的是AliOS Things的診斷除錯組件是怎么幫助解決代碼bug的,
診斷除錯組件可以縮短bug定位時間,
如果一個bug出現導致系統例外后,用戶可以不用連仿真器、不用加列印、不用打開gdb單步除錯的情況下,可以快速找到bug原因,
或者幫助用戶指出可能的例外點,進而修復以節省開發時間,
舉例說明:
- 代碼中訪問了非法記憶體(比如:在不可寫的地址處寫了資料,如訪問了0地址)導致系統奔潰,AliOS Things診斷除錯組件可以記錄訪問非法記憶體時的pc值,告訴用戶掛在了哪一行;
- 代碼跑飛了(pc=0),AliOS Things診斷除錯組件記錄了函式呼叫的堆疊,并根據堆疊向上回溯可以找到A->B->C的函式呼叫程序,與仿真器中bt命令類似;
- 用戶記憶體申請時malloc 失敗,AliOS Things診斷除錯組件可以記錄用戶此時申請了多少記憶體、此時系統還有多少記憶體可以供申請、用戶是在哪個任務中申請的記憶體、從系統啟動開始記憶體的申請情況等資訊,這些資訊可以幫助開發者定位是否有記憶體泄漏的情況,
- ......
AliOS Things的診斷除錯組件可以干很多事,后面我們會陸續推出文章來介紹,
今天我們只看一個問題——bug產生了,系統例外掛死了,那么AliOS Things會做哪些事呢?
簡單一句話回答,輸出重要的log幫助大家定位問題,這也是AliOS Things的診斷除錯組件最重要的部分,
3、AliOS Things的例外log到底是啥樣
直接上HaaS100輸出的log
!!!!!!!!!! Exception !!!!!!!!!!
========== Regs info ========== 例外現場暫存器資訊
R0 0x00000000
R1 0x34027F20
R2 0x34027F30
R3 0x340251B4
R4 0xFFFFFFFF
R5 0x00000000
R6 0x2C0D2C72
R7 0x00000001
R8 0x2C0D2C86
R9 0x2C0D236B
R10 0x00000000
R11 0x00000000
R12 0x0000C000
LR 0x1C5D6CC3
PC 0x1C5D6CC2
xPSR 0x61000000
SP 0x34025118
EXC_RET 0xFFFFFFBC
EXC_NUM 0x00000006
PRIMASK 0x00000000
FLTMASK 0x00000000
BASEPRI 0x00000000
CFSR 0x01000000
HFSR 0x00000000
MMFAR 0xE000ED34
BFAR 0xE000ED38
AFSR 0x00000000
========== Stack info ========== 例外現場堆疊資訊
stack(0x34025118): 0x34027D20 0x340251B4 0x00000000 0x34022F98
stack(0x34025128): 0x00000000 0x34682380 0x1C5D6BBD 0x00000005
stack(0x34025138): 0x00000006 0x1C5D621F 0x00000003 0x2C0D2A0C
stack(0x34025148): 0x340230C4 0x00000013 0x34682280 0x00000000
stack(0x34025158): 0x000000F7 0x00000005 0x00000003 0x00000000
stack(0x34025168): 0x00000000 0x00000000 0x00000001 0x34682380
stack(0x34025178): 0x34022F98 0x0000000B 0x34022FA8 0x00000000
stack(0x34025188): 0x000000F6 0x00000001 0x2C0D294D 0x1C5D63D3
stack(0x34025198): 0x00000000 0x2C0D1BD0 0x00000000 0x0D000000
stack(0x340251A8): 0x78300070 0x66666666 0x66666666 0x00003100
stack(0x340251B8): 0x00000000 0x00000000 0x00000000 0x00000000
stack(0x340251C8): 0x00000000 0x00000000 0x00000000 0x00000000
stack(0x340251D8): 0x00000000 0x00000000 0x00000000 0x00000000
stack(0x340251E8): 0x00000000 0x00000000 0x00000000 0x00000000
stack(0x340251F8): 0x00000000 0x00000000 0x00000000 0x00000000
stack(0x34025208): 0x00000000 0x00000000 0x00000000 0x00000000
========== Call stack ========== 堆疊回溯資訊,可以得出函式呼叫程序
backtrace : 0x1C5D6CC2
backtrace : 0x1C5D621C
backtrace : 0x1C5D63CE
backtrace : ^task entry^
========== Heap Info ========== 系統此時的記憶體資訊,可以看出記憶體申請了多少,還剩多少
---------------------------------------------------------------------------
[HEAP]| TotalSz | FreeSz | UsedSz | MinFreeSz | MaxFreeBlkSz |
| 0x00680000 | 0x0065A300 | 0x00025D00 | 0x00659E20 | 0x0065A300 |
---------------------------------------------------------------------------
========== Task Info ========== 系統當前任務狀態資訊,可以看出任務堆疊是否過小
--------------------------------------------------------------------------
TaskName State Prio Stack StackSize (MinFree)
--------------------------------------------------------------------------
dyn_mem_proc_task PEND 0x00000006 0x2004B938 0x00000400(0x0000035C)
idle_task RDY 0x0000003D 0x2004BE0C 0x00001000(0x00000F94)
DEFAULT-WORKQUEUE PEND 0x00000014 0x2004F1E8 0x00000C00(0x00000B7C)
timer_task PEND 0x00000005 0x2004D0D8 0x00002000(0x00001F48)
main SLP 0x00000021 0x2015A000 0x00005000(0x000044C4)
transq_msg PEND 0x0000001F 0x3469A4C4 0x00001000(0x00000680)
apps_recover SLP 0x00000021 0x2004A588 0x00001000(0x00000F64)
temp_main SLP 0x00000021 0x346A15D8 0x00001000(0x00000F80)
main_task SLP 0x00000020 0x34002668 0x00020000(0x0001F6C4)
cli RDY 0x0000003C 0x340232D0 0x00002000(0x0000180C)
ulog PEND 0x0000003C 0x34026890 0x00000C00(0x00000A58)
========== Queue Info ========== AliOS Things kernel queue使用資訊
-------------------------------------------------------
QueAddr TotalSize PeakNum CurrNum TaskWaiting
-------------------------------------------------------
======== Buf Queue Info ======== AliOS Things kernel buf queue使用資訊
------------------------------------------------------------------
BufQueAddr TotalSize PeakNum CurrNum MinFreeSz TaskWaiting
------------------------------------------------------------------
0x2004FDE8 0x000001E0 0x00000000 0x00000000 0x000001E0 timer_task
0x34025420 0x00001400 0x00000000 0x00000000 0x00001400 ulog
=========== Sem Info =========== AliOS Things kernel semphore使用資訊
--------------------------------------------
SemAddr Count PeakCount TaskWaiting
--------------------------------------------
0x2004CF60 0x00000000 0x00000000 dyn_mem_proc_task
0x2004F1B8 0x00000000 0x00000000 DEFAULT-WORKQUEUE
0x340023A0 0x00000001 0x00000001
0x34002478 0x00000000 0x00000000
0x340025D0 0x00000001 0x00000001
0x34682C34 0x00000000 0x00000000
0x34682C58 0x00000000 0x00000000
0x340275B0 0x00000000 0x00000000
!!!!!!!!!! dump end !!!!!!!!!!
3.1、Log分析
上面的log是在HaaS100上產生系統例外后,由AliOS Things輸出的log,log可以分為:
- 例外現場暫存器:跟arch相關的通用暫存器和一些特殊暫存器資訊;
- 例外堆疊資訊:產生例外的任務的堆疊資訊;
- 堆疊回溯資訊:產生例外的呼叫堆疊,類似仿真器中的bt命令,這個是例外log中最重要的部分;
- 記憶體資訊:系統此時的記憶體狀態,對于定位一些記憶體泄漏問題比較有用;
- 任務資訊:系統當前的任務狀態資訊,對于定位任務堆疊溢位問題比較有用;
- 內核資訊:包含了kernel 中的queue、buf_queue 和 sem狀態,
log中所示的記憶體包含了很多內核相關的內容,后續我們也會推出文章來介紹AliOS Things的內核,
3.2、如何打開診斷除錯組件
用戶只需要在aos.mk里包含debug組件,重新編譯燒錄上電即可,
$(NAME)_COMPONENTS += debug
3.3、如何產生一個系統例外
理論上任何一個系統例外后,都會出現類似上面的log,如果開發者對產生系統例外感興趣,可以使用下面的簡單方法:
m 0xffffffff 1
即使用系統提供的cli 命令,改寫系統位于0xfffffff出的記憶體值為1,地址0xfffffff在HaaS100上為不可寫的區域,改寫這個值可以觸發系統例外,列印出上面的log,
使用cli命令的方法可以參考另外一篇文章《一文輕松入門HaaS100診斷除錯系統》
3.4、呼叫堆疊的價值
呼叫堆疊的資訊輸出是AliOS Things診斷除錯組件的核心,我們通過上面的命令產生例外后,使用toolchain自帶的arm-none-eabi-addr2line 命令對上面log中的call stack呼叫堆疊中的地址進行決議,使用方法是:
arm-none-eabi-addr2line -pfiCe xxx.elf addr
以log中輸出的call stack地址為例:
./build/compiler/gcc-arm-none-eabi/Linux64/bin/arm-none-eabi-addr2line -pfiCe out/debug_demo@haas100/binary/debug_demo@haas100.elf 0x1C5D6CC2 0x1C5D621C 0x1C5D63CE
可以決議出呼叫堆疊所對應的代碼位置,如:
pmem_cmd at /workspace/hass/AliOS-Things/core/cli/cli_default_command.c:224
proc_onecmd at /workspace/hass/AliOS-Things/core/cli/cli.c:173
(inlined by) cli_handle_input at /workspace/hass/AliOS-Things/core/cli/cli.c:290
cli_main at /workspace/hass/AliOS-Things/core/cli/cli.c:781
我們可以清楚看到發生例外的函式呼叫程序,并且指出了函式代碼的路徑和行號,
cli_main -- > proc_onecmd ---> pmem_cmd
4、筆者的話
大家有沒有覺得,通過這個方法定位Bug,讓例外發生的位置一目了然,我們快速找到這行代碼后修改,分分鐘解決了這個Bug,又可以開心的繼續干活了!
不過,AliOS Things診斷除錯組件只是盡可能的幫助大家節省解Bug的時間,而有些Bug的產生并不會導致系統例外,但會給系統埋下不穩定的伏筆,這個時候再好的診斷工具也沒用了,
大家還是要多修煉寫代碼內功,不產生bug才是我們的追求!
5、開發者技術支持
如需更多技術支持,可加入釘釘開發者群

更多技術與解決方案介紹,請訪問阿里云AIoT首頁https://iot.aliyun.com/
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/240118.html
標籤:其他
下一篇:12.19-12.26任務總結
