Android 使用 gdb 搭配 Visual Studio Code 遠端除錯教學

本篇 ShengYu 介紹 Android 使用 gdb 與 gdbserver 以及搭配 Visual Studio Code(VS Code) 來遠端除錯,gdb 可以透過網路對遠端的程式進行除錯,需要遠端執行 gdbserver 以及搭配本地端 gdb 一起使用,而 gdbserver 是 server 的角色,而 gdb 是 client 的角色,一旦 gdb 連上遠端的 gdbserver 後,之後就使用 gdb 進行除錯,跟平常的 gdb 使用上沒有差異,我的桌機環境為 Ubuntu 16.04,

以下 Android 使用 gdb 搭配 Visual Studio Code 遠端除錯教學內容大概分為這幾部分,

  • adb forward 轉發通訊埠
  • Android 下 gdb 與 gdbserver 使用方法
  • VS Code 遠端偵錯設定
  • VS Code 錯誤排除

adb forward 轉發通訊埠

adb forward 將 PC 的 port 20001 對應到 Android Device 的 port 20002,

1
adb forward tcp:20001 tcp:20002

可以使用 adb forward --list 檢查目前的轉發列表。

Android 下 gdb 與 gdbserver 使用方法

將編譯好的執行檔推到 Android Device,假設這個執行檔名稱叫 samplehello,在編譯時要確保有 -g 選項以及 -O0 不使用最佳化,以便提供足夠的偵錯資訊,

gdb 與 gdbserver 不用自己編譯,直接拿 Android 預編譯好的執行檔即可,以 NDK r13b 為例的話,也可以使用最新的 NDK,要注意的是 NDK r24 就移除 gdb/gdbserver 改用 lldb 了,所以 NDK r24 之後的版本改用 lldb,
gdb 執行檔路徑如下,

1
2
3
android-ndk-r13b-windows-x86_64.zip -> android-ndk-r13b/prebuilt/windows-x86_64/bin/gdb.exe
android-ndk-r13b-linux-x86_64.zip -> android-ndk-r13b/prebuilt/linux-x86_64/bin/gdb
android-ndk-r13b-darwin-x86_64.zip -> android-ndk-r13b/prebuilt/darwin-x86_64/bin/gdb

gdbserver 執行檔路徑如下,gdbserver 是在 Android Device 端執行的程式,視你要除錯的執行檔類型選擇對應架構的 gdbserver,

1
2
3
4
5
6
android-ndk-r13b-windows-x86_64.zip -> android-ndk-r13b/prebuilt/android-arm/gdbserver/gdbserver
android-ndk-r13b-windows-x86_64.zip -> android-ndk-r13b/prebuilt/android-arm64/gdbserver/gdbserver
android-ndk-r13b-linux-x86_64.zip -> android-ndk-r13b/prebuilt/android-arm/gdbserver/gdbserver
android-ndk-r13b-linux-x86_64.zip -> android-ndk-r13b/prebuilt/android-arm64/gdbserver/gdbserver
android-ndk-r13b-darwin-x86_64.zip -> android-ndk-r13b/prebuilt/android-arm/gdbserver/gdbserver
android-ndk-r13b-darwin-x86_64.zip -> android-ndk-r13b/prebuilt/android-arm64/gdbserver/gdbserver

或者使用 Android BSP / AOSP source code 裡附帶的也可以,預編譯好的 gdb 與 gdbserver 就在 prebuilts 目錄下。

Android Device 端
在 Android Device 端執行 gdbserver 或 gdbserver64,假使要除錯的執行檔 (samplehello) 是 64bit 架構的就使用 gdbserver64,反之使用 gdbserver,使用錯誤的話到時 gdb 端會顯示錯誤訊息,執行 gdbserver 後面參數加上 <ip:port> 監聽的ip位址與port通訊埠以及要偵錯的執行檔路徑,這邊範例使用 port 20002,

1
2
3
gdbserver64 :20002 /vendor/bin/samplehello
# or
gdbserver64 127.0.0.1:20002 /vendor/bin/samplehello

gdbserver 要使用 attach 的方式的話,後面接上程式的 pid 即可,

1
gdbserver64 :20002 --attach <pid>

PC 端
在 PC 端執行 gdb,後面參數接上執行檔(debug 版本,no striped),這裡使用 codebase 預編譯好的 gdb,執行 gdb 後使用 target remote <ip:port> 來連上遠端的 gdbserver,這邊範例是連上本地端的 port 20001,因為稍早的 adb forward 設定會將 PC 本地端的 port 20001 轉發到 Android Device 遠端的 port 20002,使得 Android Device 上的 gdbserver 收到連線請求,

1
2
3
4
./prebuilts/gdb/linux-x86/bin/gdb ./out/target/product/<product_name>/symbols/vendor/bin/samplehello
(gdb) target remote :20001
# or
(gdb) target remote 127.0.0.1:20001

一般 gdb 除錯時是使用 r 開始執行程式。不過遠端除錯時,遠端的 gdbserver 已經 run 了,所以 gdb 要用 c 來繼續執行,不能用 r。

以下為 gdb 常用的指令,
r:run 開始執行
c:continue 繼續執行
b samplehello.cpp:14:設定中斷點
info b:印出目前設定的中斷點
bt:backtrace 印出程式呼叫的堆疊
q:quit 離開

確定基本的 gdbserver 與 gdb 都可以正常地遠端偵錯後,我們就來開始進行 VS Code 遠端偵錯的設定吧!

VS Code 遠端偵錯設定

VS Code 的 .vscode/launch.json 設定檔資訊如下,其中重點是 miDebuggerServerAddress 要設定對,例如本範例的 PC 本地端 port 20001 (轉發到 Android Device 遠端的 port 20002),miDebuggerPath 是 gdb 執行檔的路徑,最後是 program 要除錯的執行檔路徑,

.vscode/launch.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Remote GDB",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/out/target/product/<product_name>/symbols/vendor/bin/samplehello",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"miDebuggerServerAddress": "localhost:20001",
"miDebuggerPath": "${workspaceFolder}/prebuilts/gdb/linux-x86/bin/gdb"
//"miDebuggerPath": "/opt/android-ndk-r13b/prebuilt/linux-x86_64/bin/gdb"
}
]
}

VS Code 錯誤排除

如果在除錯的過程中逐步執行發現跳不到原始碼遇到 Could not load source ... 'SourceRequest' not supported 這樣的錯誤訊息的話,可能就是找不到原始碼的路徑,可能就是因為執行檔跟原始碼擺放路徑不同,解決方式就是在 launch.json 使用 sourceFileMap 將正確的路徑對應好,再次啟動就可以正確找到了~~

類似的狀況與解法可以在medium這篇vscode-cpptools issues這兩篇中發現。

其他參考
Android Debugging with Visual Studio Code - General and Gameplay Programming - Tutorials - GameDev.net
https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/android-debugging-with-visual-studio-code-r4820/
GDBServer on Android
https://appleapplecat.pixnet.net/blog/post/32464205
Using Debuggers | Android Open Source Project 官方最新文件
https://source.android.google.cn/devices/tech/debug/gdb
Debugging with GDB | Android Open Source 很舊的文件
https://wladimir-tm4pda.github.io/porting/debugging_gdb.html
(在 Android 6 及更低版本,gdbclient 的 shell 腳本,Android 6 以上是 gdbclient.py 的 python 腳本)
使用GDB在VS Code調試Android C/C++代碼(無需Android源碼)_陳六生的博客-CSDN博客
https://blog.csdn.net/u011057800/article/details/108094858
(launch.json 使用 ${env:ANDROID_NDK} 取得環境變數的設定值)

相關主題
Android adb forward 通訊埠轉發用法教學
macOS 使用 VS Code Debugger 除錯