透過 VSCode 的 launch.json
直接啟動 gdb 雖然很方便,但如果你想在 gdb 運行時對其功能進行更深入、更靈活的魔改,不論是直接在 gdb 中添加或修改命令,或者僅僅透過 launch.json
傳遞參數,都難以滿足需求。最有效率的方法是「寫程式」來包裝並啟動一個 gdb 進程,讓外部程式可以根據需求自定義與 gdb 之間的互動。Python 是實現這種包裝的理想語言,因為它具有非常豐富的 gdb 支持 (gdb Python API)
這篇文章不會教你如何配置 VSCode 中的 C/C++ extension 配置方法,而主要在描述如何在 gdb 不直接呼叫
source <xxx>.py
的情況下,使用 python 寫的函式,並且與 VSCode 的launch.json
整合,讓使用者有能夠使用 VSCode 漂亮除錯介面的客製化 gdb。
我們透過下面的例子來看如何自己編寫一個透過 python 包裝的 gdb 吧!
在開始前,你應該先你安裝了 gdb 和確認 gdb 的組態 (config) 包含了 python 相關的功能。可以使用以下命令確認:
請注意只有在 gdb 的 process 中的 python 才能 import gdb
。因此要區分 gdb_launcher.py
(負責啟動 gdb),還有 gdb_extension.py
(跟 gdb 模組有關的客製擴充功能)
首先,建立一個 C 檔案 test.c
:
並用 gcc 編譯:
接著,新建一個 python 檔案,名稱叫做 my_gdb.py
,添加以下的內容:
當寫完後,提升該檔案的執行權限 (否則用 VSCode 呼叫會有問題):
最後將 VSCode 中 launch.json
的內容修改如下,a.out
換成你要除錯的可執行檔名稱:
此時,點擊運行按鈕你就可以看到跟先前 gdb 一樣的運行畫面!
到這邊,你已經會使用 VSCode 呼叫經過包裝的 gdb 了,接下來呢?
VSCode 採用的是 Debug Adapter Protocol 為 UI 資訊和 Debug Adapter 中間的橋梁,而 Debug Adapter 則是為了應付各種語言擁有不同介面的除錯器 (debugger)。理論上每種 debugger 如果要使用 VSCode 的除錯介面都要有自己的 Debug Adapter。
當我們按下開始除錯時, VSCode 會根據使用者提供的 launch.json
尋找 debugger 的路徑,有可能是原生的 (e.g., /usr/bin/gdb
),也有可能是經過包裝的,藉由 debug 結束時的輸出我們能一窺 VSCode 的關鍵參數:
關鍵參數包含了
miDebuggerPath
: debugger 或 debugger launcher 路徑。--interpreter=mi
: 指定使用 debugger 的 MI 模式,這會讓 debugger 的輸出變成 machine oriented text,例如以 ~
開頭表示是 debugger 的輸出…。--tty
: 指定 debugger 中要儲存的程式的 STDOUT。通常會是 pseudo terminal (pty) 的形式,例如 /dev/pty/0
。0<...
: 重定位標準輸入到一個暫存檔中。1>...
: 重定位標準輸出到一個暫存檔中。這裡比較 tricky,因為我發現使用 ssh 遠端除錯時,VSCode 會把輸出調整到一個 pty
,且該數字大部分是 --tty
參數再加上 1。但注意僅限 ssh 遠端時,在本地使用他還是會輸出到暫存檔中。經過測試,只要能寫入到該暫存檔中後,便能被寫到 debug console 上。且格式不要求是 MI 格式。
所以在 gdb launcher 中,如果有任何資訊要打到 debug console 上,使用 print(..., flush=true)
就會立刻出現,沒有 flush 可能無法正確顯示(因為該進程之後會阻塞)。而如果你有其他的 script 也想知道怎麼輸出到這個 session 的 debug console 中,可以使用:
總結以上,做到以下事情後,藉由 gdb launcher 開啟的 gdb 就能正常在 VSCode 介面運作:
STDIN
、STDOUT
繼承會傳遞給 gdb (先前 Popen
達成了這件事情)--tty
、--interpreter=mi
setupCommands
也能正常傳入,debugger launcher 應該完整的 pass 其他參數給 gdb。os.ttyname(x)
,因為在本地端 VSCode 啟動的 debug (launcher) 不會是一個 pty,因此會報錯。commit: cb104ee
藉由引入上方的 commit 並搭配以下的 launch.json,你便能在 編譯好 qtest
的情況下,在 VSCode 中開始 debug 程序,並透過以下方法使用客製化功能 (e.g., container_of
):
啟動後你應該會在 debug console 中看到:
我們在 qtest 中輸入以下,並斷點在 q_ascend
:
接著回到 debug console 輸入:
注意事項
chmod +x
)。-exec <your gdb cmd>
,這樣才會被傳遞給 gdb (或說 gdb 的 STDIN)。