如何在 Linux 上使用 gdbserver 進行遠端偵錯

最後更新: 14/01/2026
作者: 艾薩克
  • gdbserver 作為 GDB 的遠端代理,透過 TCP 或串口控制另一台機器上的進程。
  • 要進行遠端偵錯,關鍵是要使用以下方式編譯: 符號使用合適的 gdb 並正確配置符號和字體路徑。
  • gdbserver 提供單進程模式和多進程模式,還可以與 WinDbg 和 QEMU 集成,用於核心偵錯。
  • --debug、sysroot 和值大小限制等選項有助於診斷問題並穩定會話。

使用 gdbserver 進行遠端偵錯

如果你用 C 或 C++ 編程 Linux 你從來沒接觸過 gdbserver你錯過了遠端調試進程最實用的工具之一,無論是在伺服器、嵌入式系統,還是虛擬機器或WSL中。 gdbserver並非什麼「神奇」的工具,也並非專家專屬,它只是一個與gdb通訊並控制目標程序執行的小程式。

核心思想非常簡單。在運行要偵錯的二進位檔案的機器上( 目標)你啟動 gdbserver;在你的工作電腦上( 主持人你可以啟動支援 gdb 協定的 gdb 或 WinDbg。兩者都透過 TCP 或串口連接,連接後你可以設定斷點、檢查變數、查看堆疊,或者像在自己的機器上運行程式一樣,逐步追蹤程式的執行過程。

gdbserver是什麼?什麼時候適合使用它?

什麼是 gdbserver

gdbserver 是 GNU gdb 的遠端偵錯“代理”它的功能非常具體:它在被分析程式運行的機器上運行,控制該進程(或多個進程),並透過遠端連接與位於另一台機器(或同一台機器)上的 gdb 用戶端通訊。

在日常使用中,gdbserver 通常用於兩種典型場景。調試運行於嵌入式環境(路由器、精簡版 Linux 開發板、裝置)中的軟體 物聯網等等)以及在遠端 Linux 機器上調試進程,在這些機器上,擁有包含所有庫和符號的「胖」gdb 並不方便,或者根本不可能。

在實際應用中,gdbserver 處理諸如以下任務: 讀取和寫入進程寄存器和內存,控製程式執行(繼續、暫停、單步執行),管理斷點,並使用 GDB 遠端協定將所有這些資料傳送到 gdb。這種理念與 OpenOCD 等工具非常相似,後者充當 gdb 和程式之間的橋樑。 硬件 外部的,差別在於 gdbserver 運行在與二進位檔案運行相同的系統上。

如果你來自這樣的環境 Windows 了解這一點也很有意思。 像 WinDbg 這樣的偵錯器可以與 Linux 上的 gdbserver 通信,因此您可以使用 WinDbg 透過 gdb 協定提供的遠端偵錯支援來調試 Linux 上的用戶進程,該協議是 Microsoft 在最新版本中整合的。

使用 gdb 和 gdbserver 進行偵錯的基本要求

使用 gdbserver 的要求

在開始遠端偵錯之前,您需要了解主機/目標之間的關係。。 “ 目標 這是運行待調試程式和執行 gdbserver 的機器; 主持人 你將在這台機器上運行 gdb(或 WinDbg),並將原始程式碼以及(最好是)偵錯符號放在這台機器上。

最基本的起點是用符號編譯二進位檔。在 GCC 或 g++ 中,這是透過標誌來實現的。 -g通常建議同時停用優化功能(例如使用…) -O0這樣,偵錯器就能更準確地顯示變數、巨集和程式碼結構。對於特定的宏,您可以使用更高的偵錯級別,例如: -g3.

主機端需要相容版本的 gdb 使用目標架構。若要偵錯 MIPS、ARM 或其他架構的嵌入式系統,必須使用對應交叉工具鏈的 gdb(例如)。 arm-none-eabi-gdb o gdb-multiarch)如有必要,配置架構和位元組序 命令set arch y set endian.

關於連線方式,gdbserver 支援兩種主要類型。串行鏈路(在嵌入式硬體中非常常見,透過 UART)和 TCP/IP 協議,當目標設備位於同一網路或可透過網路存取的 Linux 機器時,TCP/IP 協定最為方便。在這兩種情況下,命令都透過 gdb 執行。 target remote 連線到 gdbserver 公開的端點。

啟動 gdbserver 的方式:單進程模式和多進程模式

gdbserver 執行模式

gdbserver 可以透過兩種主要方式運作。 當我們談到使用者模式偵錯時:可以直接與單一進程關聯,或作為「進程伺服器」允許列出和附加到不同的系統進程。

單一進程模式 啟動 gdbserver 時,需要指定主機、連接埠以及要執行的程式。在 Linux 桌面機器上,一個簡單的例子是這樣的:

命令: gdbserver localhost:3333 foo

透過該命令,gdbserver 啟動二進位。 foo 他一直監聽著3333端口。在遠端 gdb 連線之前,程式會保持停止狀態;當 gdb 連線時,程式才會停止運作。 target remote localhost:3333破碎過程開始由破碎機控制。

在多進程模式(進程伺服器)下,可以使用該選項。 --multi在這種情況下,gdbserver 不會直接啟動任何程序,而只是監聽傳入的連接,並允許客戶端(gdb 或 WinDbg)管理要建立或附加到哪個進程:

  Google推出 Gemini Code Assist:免費的人工智慧程式設計助手

命令: gdbserver --multi localhost:1234

在 Linux 上使用 WinDbg 時,這種多模式尤其有趣。因為可以直接從 WinDbg 列出遠端系統上的進程,查看進程 ID (PID)、使用者和命令列,並附加到您感興趣的進程,這與使用進程伺服器的方式類似。 dbgsrv.exe 在Windows中。

使用 gdbserver 和 gdb 進行遠端偵錯的逐步指南

讓我們用一個非常典型的例子來具體說明。:使用 gdbserver 在同一台機器(主機和目標匹配)上調試一個簡單的應用程序,以模擬遠端場景。

首先,你需要寫並編譯一個小程式。例如,一個簡單的循環,用於列印計數器:

命令: gcc -g foo.c -o foo

關鍵在於旗幟。 -g這會將必要的偵錯資訊新增至二進位檔案中,以便 gdb 可以顯示程式碼行、變數名稱、類型等。在「真正的」交叉編譯環境中,您可以使用交叉編譯工具鏈進行編譯,然後將二進位檔案及其相依性複製到目標位置。

下一步是在目標系統上啟動 gdbserver。如果主機和目標是同一台機器,則:

命令: gdbserver localhost:3333 foo

你會看到類似這樣的消息 「進程 foo 已建立;進程 ID = XXXX;正在監聽連接埠 3333」。這表示 gdbserver 已建立該進程,並正在等待 gdb 連線。如果您的系統需要更高的權限(例如,附加到系統進程),則可能需要使用下列命令執行該命令。 sudo但是,在授予許可時保持謹慎總是明智的。 送至脫硫裝置。

在主機上,啟動 gdb 並指定本機可執行檔。 (與目標系統上運行的程式相同,或帶有符號的完全相同的副本):

命令: gdb foo

進入 gdb 後,您可以使用以下命令建立遠端連線::

命令: target remote localhost:3333

此時,gdb 從本地二進位檔案載入符號。它與 gdbserver 同步,並接管 gdbserver 下實際運行的進程。之後的流程與通常流程相同:執行諸如此類的命令 break 設定突破點, continue, step, next, print 為了檢查變量, backtrace 查看電池等情況。

使用 gdbserver 連線到正在執行的進程

你並不總是想從頭開始啟動程式。通常,你對加入一個已經運行的流程感興趣(例如,一個 httpd路由器(系統守護程式或生產服務)。

典型的做法是使用該選項 --attach 來自 gdbserver傳遞監聽埠和目標進程的 PID。例如,在已複製了針對其架構編譯的 gdbserver 的路由器上,您可以這樣做:

命令: gdbserver localhost:3333 --attach <pid_de_httpd>

在主機端,您將使用支援路由器架構的 gdb 版本。例如 gdb-multiarch預先配置架構和位元組序:

命令: set arch mips
set endian big

然後指定包含符號的本機檔案。 遠端二進位(例如) file httpd)並且,如有必要,您可以使用以下命令告訴 gdb 二進位檔案在目標上的實際運作位置: set remote exec-file /usr/bin/httpd最後,和以前一樣,你連結到:

命令: target remote 192.168.0.1:3333

一旦連接您可以為特定函數設定斷點(例如)。 break checkFirmware),繼續執行,讓程式的正常流程(例如,從 Web 介面上傳韌體)觸發斷點。

在 Linux 上使用 WinDbg 和 gdbserver

近年來,微軟在 WinDbg 中加入了對調試 Linux 進程的支援。 使用 gdbserver 作為後端。此功能適用於您在 Windows 系統下工作,但程式碼運行在 Linux(包括 WSL)上的場景。

使用 gdbserver 透過 WinDbg 偵錯特定的 Linux 進程流程大致如下:首先,使用類似這樣的指令在 Linux 機器上找到目標行程。 ps -A (例如 python3 然後,在目標系統上啟動 gdbserver(前提是目標系統正在運作):

命令: gdbserver localhost:1234 python3

如果環境需要,您可能需要使用 sudo gdbserver ...採取與以往相同的安全預防措施。當 gdbserver 顯示“正在監聽連接埠 1234”後,在 WinDbg 中轉到“檔案 / 連接到遠端偵錯器”,並指定以下類型的連接字串:

命令: gdb:server=localhost,port=1234

WinDbg 使用一個小型 gdb 協定「驅動程式」與 gdbserver 通訊。 而且,一旦連線建立,它就會停留在那個點。 開機 進程。從那裡,您可以使用其堆疊視窗、模組、記憶體、斷點以及諸如以下的命令 k 查看電池或 lm 列出模組(請注意,某些命令需要 PE 格式而不是 ELF 格式,因此在某些情況下可能會顯示奇怪的資料)。

gdbserver 和 WinDbg 進程伺服器

除了單一進程情況外,WinDbg 還可以連接到充當進程伺服器的 gdbserver。 使其運作方式更類似於處理遠端 Windows 進程的方式。在此模式下,gdbserver 將以以下方式啟動: --multi 且不包含相關流程:

  在 iPhone 上啟動低電量模式的最佳方法

命令: sudo gdbserver --multi localhost:1234

在 WinDbg 中,選擇“檔案 / 連接到進程伺服器” 您可以重複使用連接字串 gdb:server=localhost,port=1234連線啟動後,您可以列出可用的 Linux 進程,並附加到您想要的進程,甚至可以啟動新進程。

需要注意一個細微之處。WinDbg 會根據 gdbserver 連線時是否已附加到某個進程來區分「進程伺服器」和「單一目標」。如果您在 gdbserver 附加到某個進程後關閉了 WinDbg,然後嘗試重新連接,則 WinDbg 可能不會將其識別為進程伺服器,您可能需要重新啟動 gdbserver。

結束進程伺服器會話通常情況下,只需在執行 gdbserver 的控制台中按下 CTRL+D 並停止 WinDbg 的偵錯即可。在某些極端情況下,如果出現同步問題,則可能需要完全關閉偵錯器並從頭開始重新啟動 gdbserver。

遠端調試中的符號和原始碼管理

遠端偵錯便利的關鍵之一在於符號和字型部分的完美解析。如果沒有符號,瀏覽堆疊或在特定函數上設定斷點就會變得非常痛苦。

在經典的 gdb + gdbserver 場景中,最好在主機上保留一份帶有符號的可執行檔副本。 (未剝離符號表)和原始碼樹。 gdb 不要求遠端二進位包含符號表;只要你用 gdb 載入的本機檔案包含符號表即可。 file 在偏移級別上匹配遠端可執行檔。

在 WinDbg 和 Linux 偵錯領域,也出現了像 DebugInfoD 這樣的服務。它透過 HTTP 公開符號和字體。 WinDbg 可以使用特殊類型的路徑。 DebugInfoD*https://debuginfod.elfutils.org.sympath 如在 .srcpath 按需下載 DWARF 符號和 Linux ELF 二進位原始碼。

以 WSL 為例,使用者代碼位於 C:\Users\Bob\你可以透過 WinDbg 來判斷:

命令: .sympath C:\Users\Bob\
.srcpath C:\Users\Bob\

如果您還想對系統二進位檔案使用 DebugInfoD,:

命令: .sympath+ DebugInfoD*https://debuginfod.elfutils.org
.srcpath+ DebugInfoD*https://debuginfod.elfutils.org

在這種配置下,當您檢查堆疊或進入 libc 函數時,WinDbg 可能會嘗試下載對應的 DWARF 符號,如果伺服器也公開了程式碼,則會非常詳細地顯示原始程式碼,儘管 Windows 工具鏈內部對 ELF 和 DWARF 的處理方式與對 PE 和 PDB 的處理方式不同,它並不會「原生」地處理 ELF 和 DWARF。

實際範例:使用 gdbserver 和 WinDbg 偵錯 C++ 程式

一個示例性的例子是一個小型 C++ 應用程序,它可以向螢幕上輸出問候語。,在 WSL 中編譯並帶有調試符號。想像一下一個程序,它預留了一個 std::array<wchar_t, 50> 並將較長的消息複製到其中,導致文字被截斷,並出現字元缺失。 ???? 最後

用類似這樣的工具編譯之後:

命令: g++ DisplayGreeting.cpp -g -o DisplayGreeting

你針對該二進位檔啟動 gdbserver:

命令: gdbserver localhost:1234 DisplayGreeting

在 WinDbg 中,您可以使用字串進行連線。 gdb:server=localhost,port=1234 會話建立並配置好符號和字體路徑後,您就可以設定斷點了。 DisplayGreeting!main你可以用 dx greeting 檢查本地數組並查看其大小(50 個位置),然後在記憶體標籤或變數視圖中直觀地檢查問候語是如何被截斷的。

這個例子的妙處在於它表明,即使 WinDbg 不完全支援所有 ELF/DWARF 格式,也能達到不錯的效果。使用 gdbserver 作為遠端後端,您可以相當輕鬆地遍歷堆疊、檢查類型、按函數名稱設定斷點以及瀏覽 C++ 程式碼。

使用 qemu 和 gdb 調試 Linux 內核

gdbserver 不僅可以在使用者模式下使用;在內核模式下也有非常強大的應用場景。尤其是在將 QEMU 與調試支援結合使用時。雖然這裡「gdbserver」的角色是由 QEMU 自身的選項實現的,但方法是一樣的:一端運行待調試的系統並打開一個 gdb 端口;另一端可以是 gdb 或支援遠端協議的調試器。

要調試內核,需要使用特定的調試選項進行編譯。:啟用調試資訊的生成(CONFIG_DEBUG_INFO),GDB 核心腳本(CONFIG_GDB_SCRIPTS)以及核心自身的調試模式(CONFIG_DEBUG_KERNEL此外,在停用連結期間刪除符號的選項也很重要,例如「連結期間剝離彙編器產生的符號」。

編譯後您將得到一個二進位文件 vmlinux “未剝離”你將使用 gdb 中的那個。你還需要一個基本的 initramfs,你可以用類似這樣的指令來產生它:

命令: mkinitramfs -o ramdisk.img

然後使用調試參數啟動 QEMU一個典型的例子包括選項 -gdb tcp::1234 開啟一個與 gdb 相容的遠端端點,並且 -S 這樣虛擬機器就會從一開始就處於暫停狀態。你還可以指定內核。 -kernel vmlinux中, -initrd ramdisk.img記憶與 -m 512 通常情況下,你會將控制台重定向到 ttyS0 從頭到尾管理一切 終端.

  如何在 Windows 11 上將 Edge 更新至最新版本:完整逐步指南

QEMU 被扣留等待 gdb從主機啟動 gdb,指向 vmlinux 你與…聯繫 target remote localhost:1234從那裡你可以設定早期斷點,例如 hb start_kernel並透過諸如此類的命令來控制執行。 c (繼續)按 CTRL+C 再次暫停。

gdb 和 gdbserver 的最新變化和細微差別

在像 Red Hat Enterprise Linux 8 這樣的現代發行版中,gdb 和 gdbserver 有一些值得注意的變化。尤其是如果您是從以前的版本升級而來,或者有分析偵錯器輸出的腳本。

一方面,gdbserver 現在使用 shell 啟動「底層」進程。與 gdb 類似,這允許在命令列中進行變數擴展和替換。如果出於任何原因需要停用此功能,RHEL 8 中提供了相應的設置,可以恢復到先前的模式。

有些內容已被刪除或更改。:為使用以下方式編譯的 Java 程式提供調試支持 gcjHP-UX XDB 相容模式,例如: set remotebaud (已替換為 set serial baud)或與某些舊格式的相容性 stabs此外,線程編號不再是全域的,而是按“較低”線程編號,並且顯示為 inferior_num.thread_num以及一些新的便利變量,例如 $_gthread 指稱全域標識符。

另一個相關的新功能是調整 max-value-size這限制了 gdb 可以分配多少記憶體來顯示值的內容。預設值為 64 KiB,因此嘗試列印大型陣列或龐大的結構體可能會導致「值過大」的警告,而不是顯示所有可用記憶體。

此外,gdb 處理方式也進行了調整。 sysroot預設值現在是 target:這意味著對於遠端進程,它會先嘗試在目標系統上尋找庫和符號。如果您希望它優先使用本地符號,則應該運行 set sysroot 出發前,先選擇你有興趣的路線。 target remote.

關於命令歷史記錄,目前使用的環境變數是 GDBHISTSIZE 而不是 HISTSIZE這樣,您可以微調在偵錯會話中輸入的命令的保留時間,而不會幹擾使用行讀取庫的其他應用程式的行為。

使用 gdbserver 的工作流程技巧和故障排除

為了擁有舒適的工作流程,有一些模式往往非常有效。 在為嵌入式系統或遠端伺服器開發程式時,第一步是盡可能自動化符號編譯和二進位檔案部署到目標平台。這樣,您始終可以知道正在運行的是哪個版本的可執行文件,並且主機上隨時可以獲得符號文件副本。

在崩潰核心較多的環境中,學習如何在批次模式下使用 gdb 是值得的。帶有如下旗幟 --batch, --ex y -x 自動對一系列核心啟動命令,並從腳本中處理它們的回溯資訊(例如在 蟒蛇這樣可以快速篩選出重複出現的問題,按堆疊追蹤將故障分組等等。

當遠端連線出現問題時,此選項 --debug gdbserver 是你最好的朋友例如,如果您使用下列命令啟動進程伺服器:

命令: gdbserver --debug --multi localhost:1234

gdbserver 控制台將顯示詳細的運行追蹤資訊。 在遠端協定層面,這包括傳入的資料包、格式錯誤、斷開連線問題等。當 gdb 伺服器突然斷開連線、進程在設定斷點後立即崩潰,或偵錯 GUI 發送 gdbserver 無法理解的內容時,這非常有用。

在諸如 TP-Link 路由器之類的環境中,您可以將 gdbserver 附加到關鍵進程,例如 httpd某些斷點很容易導致競態條件或看門狗機制觸發進程終止,尤其是在偵錯器中進程「卡住」過久的情況下。在這種情況下,可能需要調整阻塞的訊號、控制的線程,並在必要時修改系統配置(例如超時時間、硬體看門狗機制),以允許更長的偵錯會話。

熟練使用 gdbserver 需要結合多個部分。使用合適的符號進行編譯,為架構選擇正確的 gdb,配置符號和原始檔案路徑,理解 gdbserver 的兩種主要模式(單進程和多進程),並且不要害怕從該模式下拉取程式碼。 --debug 當連接出現異常時,有了這些基礎,從你的電腦調試運行在遠端 Linux 系統、路由器或帶有自訂核心的虛擬機器上的應用程式就變得非常輕鬆,而且極其有用。