簡單介紹利用 OpenOCD+JTAG 來調試一個demo程序的步驟和說明。
2017.01.18 by chenwu
前提條件:
已經理解並完成《ESP32調試環境搭建》。
步驟
1. 串口線連接好 ESP-WROVER-KIT 和 PC,並將開關調至 ON.
2. 將本目錄下的 hello_world_main.c 覆蓋 esp-idf/examples/01_hello_world/main/hello_world_main.c 文件
3. 進入example目錄(設當前shell 為 shell A):
$ cd ~/esp/esp-idf/examples/01_hello_world
1
4. 編譯程序並燒入ESP32
$ make flash
1
5. 新建一個shell,並進入 openOCD 目錄(設當前shell 為 shell B):
$ cd ~/esp/openocd-esp32
1
6. OpenOCD和程序通訊:這步 操作之間必須連貫,不能停頓太多。(否則程序會執行到末尾,無法調試)
6.1 將ESP-WROVER-KIT開關從 ON -> OFF -> ON
6.2 shell B 啟動openocd:
$ sudo ./src/openocd -s ./tcl -f ./esp32.cfg
1
or [esp32.cfg 如果更新,則使用下面]
$ cp ../esp-idf/docs/esp32.cfg ./ ; sudo ./src/openocd -s ./tcl -f ./esp32.cfg
1
7. shell A 啟動gdb:
$ xtensa-esp32-elf-gdb -ex 'target remote localhost:3333' ./build/hello-world.elf
1
shell A端gdb調試一些說明
大概可以仿照如下調試:
b hello_task //設置好斷點
display /i $pc //設置好顯示下一條彙編
c // 執行到斷點處
n // 執行一條源碼
n // 執行一條源碼
s // 進入函數調用
ni // 執行一條彙編
ni // 執行一條彙編
p i // 輸出 i 值
bt // 輸出 棧
1
2
3
4
5
6
7
8
9
10
常用調試命令小結:
斷點相關:
b hello_task // 設置hello_task函數處斷點
b *hello_task+9 // 設置hello_task後 +9 偏移地址處的彙編為斷點(不是hello_task後的第九條彙編)
b +10 // 設置當前行 + 10 行處斷點(源碼+10行)
b a.c:10 // 設置 a.c文件的第十行(源碼)處斷點
info breakpoints // 顯示斷點處信息
b 20 // 設置 當前文件第20行 斷點,如果設置 b hello_world_main.c:20 則就是設置hello_world_main.c中第20行斷點
b 28 if i == 2 // 條件斷點,第28行中,如果i==2,則觸發斷點
d // 刪除所有斷點
d 1 // 刪除1號斷點 : 斷點按照順序編號,1號斷點就是第一個斷點
watch i // 當 當前行的i值發生改變後,會觸發斷點
1
2
3
4
5
6
7
8
9
10
執行相關:
c // 或continue // 執行程序,直到斷點處或者該線程結束
q // 退出 gdb
n // 單步執行一條源碼,如果遇到一條函數調用,不進入函數
s // 單步執行一條源碼,如果遇到一條函數調用,則進入函數
ni // 單步執行一條彙編,如果遇到一條函數調用,不進入函數
si // 單步執行一條彙編,如果遇到一條函數調用,則進入函數
finish // 跳出當前函數
1
2
3
4
5
6
7
源碼相關:
list // 顯示當前行前後的源碼
list app_main // 顯示源碼 app_main函數後一段
list 20 // 顯示源碼的第20行後一段
list 20,40 // 顯示 源碼的第20-40行
1
2
3
4
顯示相關:
display /i $pc // 執行後,每次單步後會顯示下一條彙編指令
p i // 或 print i // 輸出變量i的值
bt // 或 where // 顯示函數調用棧
bt full // 顯示函數調用棧的詳細信息
x /3uh buf // 表示從內存地址buf讀取內容,h表示以雙字節為一個單位,3表示三個單位,u表示按十六進制顯示
x /s buf // 顯示從buf開始的字符串
whatis i // 顯示變量i類型
1
2
3
4
5
6
7
佈局相關:
layout asm // 顯示彙編代碼
layout regs // 顯示寄存器
layout src // 顯示源碼 ,結合list使用
layout prev // 切換到上一個佈局
layout next // 切換到下一個佈局
1
2
3
4
5
線程和進程:
info threads // 查看線程
thread i // 切換到線程號為 i 的線程
info inferiors // 查看進程
inferior i // 切換到進程號為 i 的進程
mon reset // 重置cpu,程序重新執行
1
2
3
4
5
查看其他調試命令:
help all
help
1
2
靜態調試-反彙編
我們更加方便的調試,我們可以反彙編二進制文件,這樣更加清楚的顯示所有彙編代碼並查找分析編輯。
生成彙編代碼步驟:(前提已經編譯完成)
1. 進入hello-world目錄:
$ cd ~/esp/esp-idf/examples/01_hello_world
1
2. 拷貝 elf 文件:
$ cp ./build/hello-world.elf ./
1
3. 生成彙編文件:
$ xtensa-esp32-elf-objdump -S hello-world.elf > compile_info.txt
1
[4] 我們在gdb調試時候,可以看到執行位置的地址。在彙編文件compile_info.txt中查找該地址,就可以分析。
注意:
1. 運行 sudo ./src/openocd -s ./tcl -f ./esp32.cfg 中如果不能啟動,出現如下錯誤
Error: couldn’t bind tcl to socket: Address already in use
則證明 剛剛啟動的 進程未被終止。
解決辦法:
a).查看當前活動進程
netstat為顯示網絡相關信息 a(all:默認顯示所有,如果加了其他選項此項不生效) n(number:以數字形式顯示) t(僅僅顯示tcp連接),p(process:顯示該項是由哪個程序建立起來的)
$ sudo netstat -antp
1
b). 強制殺死它(假設進程號為3560,-9為強制殺死)
$ sudo kill -9 3560
1
2. make flash失敗
確保串口連接正常, ll /dev/ttyUSB*
應該可以看到兩個設備 ttyUSB0 ttyUSB1.如果不是,則 重置ESP-WROVER-KIT開關:從 ON-> OFF -> ON 或者 重新插拔串口線。
3. gdb啟動後出現如下錯誤:
0x00000000 in ?? ()
或者 openOCD收到如下錯誤:
Error: Error allocating memory for 1073433568 threads
解決辦法:
重新擦寫flash (flash由於上次沒有擦除乾淨)
---------------------
閱讀更多 LilyGO 的文章