嵌入式安卓開發使用LLDB進行斷點除錯C/C++程式碼

任侠平生愿發表於2024-11-19

GDB or LLDB?

較新的安卓NDK已經沒有包括gdbserver了,而且安卓官網也說了,後續不會支援gdb了。我自己之前費了很大的功夫,去交叉編譯一個gdbserver,但最後用起來一大堆莫名其妙的問題。所以還是使用LLDB吧。

獲取相應的工具

https://developer.android.google.cn/ndk/downloads
這裡下載NDK,直接下載最新版就好(太舊的安卓版本可以適當降低ndk的版本?)。解壓之後在裡面找到對應平臺的lldb-server,將這個二進位制檔案adb push進去就行了。

生成帶有除錯資訊的程式或者庫

需要新增除錯資訊,即在Android.mk或者bp中新增LOCAL_CFLAGS += -g,或者透過在ndk-build命令列上傳遞NDK_DEBUG=1。或者在cppflags裡新增"-g","-O0"選項。然後編譯即可。注意這裡無論是so庫,還是可執行檔案,只要是想斷點除錯的原始碼都必須要附帶除錯資訊。

啟動lldb-server

lldb-server platform --server --listen *:12345
這裡比較需要注意的是,儘量在一個可讀檔案系統並且有較大許可權的裡執行,因為lldb與lldb-server連線時,有可能需要將一些可執行二進位制檔案push進去,並執行,如果檔案系統不對的話,有可能會出現無論怎麼樣chmod +x都無法新增執行許可權(比如sdcard)。可以試試cache資料夾。

CodeLLDB外掛

搜尋下載vscode外掛 CodeLLDB。

launch.json

進入vscode除錯介面,點選建立一個launch.json檔案,已有launch.json檔案的話,可以點選小齒輪,編譯它。
例子如下

{

 "configurations": [
 {
     "name": "Remote launch",
     "type": "lldb",
     "request": "attach",
     "program": "out/soong/.intermediates/external/libhiddroid/test/test_demo/android_arm64_armv8-a/unstripped/test_demo", // Local path.
     "initCommands": [
         "platform select remote-android", // For example: 'remote-linux', 'remote-macosx', 'remote-android', etc.
         "platform connect connect://172.20.11.154:12345",
         "settings set target.inherit-env false", // See note below.
         "platform process list"
     ],
     "pid": "5262",
     "env": {
         "PATH": "...", // See note below.
     },
 }
 ],



}

開始除錯

然後點選綠色小三角就可以進行打斷點除錯了。
推薦直接使用attach,因為就算直接除錯可執行二進位制檔案,也可以多開一個終端執行它,還可以方便輸入資訊來響應程式,然後找到pid,進行attach即可。
attach成功後,就可以開始除錯了。可執行二進位制內的符號一般是直接載入好的,(沒有的話可以在除錯控制檯執行file 原始碼.cpp)。但其連結的動態庫,需要手動file命令來載入符號。你也可以將這些file命令新增進initCommands裡。

BUG

事情一般不會過於順利。
如果你使用LLDB除錯時,發現基本全都是彙編程式碼,即使是使用了file命令,也沒辦法看見c/c++程式碼,打斷點也停不下來,那說明編譯出來的檔案除錯資訊出問題了。

dwarf版本

如果報的錯有關dwarf版本的話,一般可能是dwarf版本過高,lldb/gdb無法支援什麼的。只要下的nkd比較新,一般不會報這種錯。這裡可以使用objdump --dwarf=info 二進位制檔案來檢視dwarf的一些資訊。也可以新增一些flag比如-gdwarf-4來限制dwarf版本。(記得,參與連結編譯的都要加這個)。但一般還是推薦更新LLDB工具,儘量使用高版本的dwarf。

除錯資訊不對勁

使用objdump -g 二進位制檔案來檢視除錯資訊。如果輸出的內容非常多,甚至溢位終端的螢幕,那說明一般沒問題,如果比較少,而且內容看起來資訊熵很小,那多半出問題,這種情況可能會導致除錯時只能看到彙編程式碼。
這種情況首先就是去排查是否新增了-g -O0等等flag。可以對編譯的工具鏈新增-v引數,讓每條編譯指令都答應出來。或者編譯專案時,太難去找哪條編譯指令的話,可以嘗試新增一些必定會報錯的flag。比如-jjjjjjjjjjjjjjjjjjjjjj,這樣就可以看看有沒有這些引數。
在確定有這些引數,而且過後沒有什麼流程去strip的話,那就可以懷疑一下,編譯使用的工具鏈了。有些廠商會使用一些自己魔改過的編譯鏈工具,如果編譯的原始碼比較少的話,你可以使用上述方法擷取出命令自行替換工具鏈。編譯檔案多的話……我暫時也想不到什麼好辦法。

自己自行替換了工具鏈,進行編譯、連結(連結的命令可以新增必定會報錯的LDFLAGS,擷取出來)後,使用objdump -g 二進位制檔案檢視,如果資訊很多的話,一般就沒問題了。

相關文章