2008-10-19 94 views
137

我一直在想,調試器是如何工作的?特別是可以「附加」到已經運行的可執行文件。我知道編譯器會將代碼翻譯成機器語言,但那麼調試器如何「知道」它所連接的是什麼?調試器如何工作?

+4

Eli的文章已經轉移到http://eli.thegreenplace.net/2011/01/23/how-debuggers-work-part-1 – Oktalist 2014-09-04 16:35:00

+0

@Oktalist這篇文章很有趣,但只是談論API級別的抽象在Linux上進行調試。我猜想OP想要更多地瞭解底層。 – smwikipedia 2017-04-28 08:04:13

回答

74

調試器工作方式的細節將取決於您正在調試的內容以及操作系統是什麼。對於Windows上的本地調試,您可以在MSDN上找到一些詳細信息:Win32 Debugging API

用戶通過名稱或進程ID告訴調試程序要附加到哪個進程。如果它是一個名稱,那麼調試器將查找進程ID,並通過系統調用啓動調試會話;在Windows下,這將是DebugActiveProcess

一旦連接,調試器將進入一個事件循環,就像任何UI一樣,但不是來自窗口系統的事件,操作系統將根據正在調試的進程中發生的事件生成事件 - 例如發生異常。見WaitForDebugEvent

調試器能夠讀寫目標進程的虛擬內存,甚至可以通過操作系統提供的API調整其寄存器值。請參閱適用於Windows的debugging functions列表。

調試器能夠使用符號文件中的信息將地址轉換爲源代碼中的變量名稱和位置。符號文件信息是一組獨立的API,並不是操作系統的核心部分。在Windows上,這是通過Debug Interface Access SDK

如果您正在調試託管環境(.NET,Java等),該進程通常看起來類似,但細節不同,因爲虛擬機環境提供調試API而不是基礎OS。

+3

這個問題可能聽起來很愚蠢,但如果程序內部的特定地址已達到,操作系統如何跟蹤。例如。在地址0x7710cafe處設置一個缺省點。當指令指針改變操作系統(或者可能是CPU)將不得不將指令指針與所有斷點地址進行比較,還是我誤會了?這個怎麼用 ..? – displayname 2014-01-23 17:09:21

+2

@StefanFalk我寫了[答案](http://stackoverflow.com/a/21746853/119527),它解決了一些較低級別的細節(在x86上)。 – 2014-02-13 06:31:12

1

我的理解是,當您編譯應用程序或DLL文件時,無論它編譯爲包含代表函數和變量的符號。

當您有一個調試版本時,這些符號比它的發佈版本更詳細,因此允許調試器爲您提供更多信息。將調試器附加到進程時,它會查看當前正在訪問哪些函數,並從此處解析所有可用的調試符號(因爲它知道編譯文件的內部結構是什麼樣子,它可以確定可能存在於內存中的內容,內容包括整數,浮點數,字符串等)。就像第一張海報所說的那樣,這些信息以及這些符號的工作方式在很大程度上取決於環境和語言。

9

如果你使用的是Windows操作系統,爲這個偉大的資源將是 「微軟.NET和Microsoft Windows調試應用程序」 由約翰·羅賓斯:

(或即使是舊版本:"Debugging Applications"

本書有關於調試器如何工作的章節,其中包括一些簡單(但工作)的調試器的代碼。

因爲我不熟悉Unix/Linux調試的細節,所以這些東西可能根本不適用於其他操作系統。但我猜想,作爲一個非常複雜主題的介紹,概念 - 如果不是細節和API - 應該「移植」到大多數任何操作系統。

23

在Linux中,調試進程從ptrace(2)系統調用開始。 This article有一個很好的教程,介紹如何使用ptrace來實現一些簡單的調試結構。

3

瞭解調試的另一個重要來源是Intel CPU手冊(英特爾®64和IA-32架構 軟件開發人員手冊)。在3A卷的第16章中,介紹了調試的硬件支持,例如特殊異常和硬件調試寄存器。以下是該章節中的內容:

T(陷阱)標誌,TSS - 當嘗試 被設置爲切換到其TSS中設置了T標誌的任務時,生成調試異常(#DB)。

我不確定Window或Linux是否使用此標誌,但閱讀該章節非常有趣。

希望這可以幫助別人。

44

據我瞭解:

有關的x86軟件斷點,調試器取代了指令與CCint3)的第一個字節。這是在Windows上使用WriteProcessMemory完成的。當CPU達到該指令並執行int3時,這會導致CPU產生調試異常。操作系統收到此中斷,意識到正在調試進程,並通知調試程序進程該中斷點已被命中。

命中斷點並且進程停止後,調試器查找其斷點列表,並用最初存在的字節替換CC。調試器在EFLAGS中設置TF, the Trap Flag(通過修改CONTEXT),並繼續該過程。陷阱標誌使CPU在下一條指令中自動生成單步異常(INT 1)。

當被調試的進程下一次停止時,調試器再次用CC取代斷點指令的第一個字節,並且過程繼續。

我不確定這是否完全如何由所有調試器實現,但我已經編寫了一個Win32程序,該程序管理使用此機制進行調試。完全沒用,但教育。