在源模式下调试

如果可以分析代码的源,而不是反汇编的二进制文件,则调试应用程序会更容易。

如果源语言为 C、C++或程序集,WinDbg、CDB 和 KD 可以在调试中使用源代码。

编译要求

若要使用源调试,必须在生成二进制文件时) 编译器或链接器 (.pdb 文件创建符号文件。 这些符号文件显示调试器二进制指令如何对应于源行。

此外,调试器必须能够访问实际的源文件,因为符号文件不包含实际的源文本。

如果可能,编译器和链接器不应优化代码。 如果代码已优化,则源调试和访问本地变量更加困难,有时几乎是不可能的。 如果使用生成实用工具作为编译器和链接器,请将 MSC_OPTIMIZATION 宏设置为 /Od /Oi 以避免优化。

查找符号文件和源文件

若要在源模式下进行调试,调试器必须能够找到源文件和符号文件。 有关详细信息,请参阅源路径

开始源调试

每当调试器具有当前正在调试的线程的适当符号和源文件时,调试器都可以显示源信息。

如果使用调试器启动新的用户模式应用程序,则 Ntdll.dll 加载应用程序时会发生初始中断。 由于调试器无权访问 Ntdll.dll 源文件,因此此时无法访问应用程序的源信息。

若要将程序计数器移动到应用程序的开头,请将入口点处的断点添加到二进制文件。 在 “调试器命令”窗口中,键入以下命令。

bp main
g

然后加载应用程序,并在输入main函数时停止。 当然, (可以使用任何入口点,而不仅仅是 main.)

如果应用程序引发异常,它会中断调试器。 此时可以使用源信息。 但是,如果使用 CTRL+CCTRL+BREAK 或调试发出中断 |Break 命令,调试器会创建新线程,因此看不到源代码。

到达具有源文件的线程后,可以使用“调试器命令”窗口执行源调试命令。 如果使用 WinDbg,则会显示 “源”窗口 。 如果已通过单击“文件”菜单上的“打开源文件”打开了“源”窗口,则 WinDbg 通常会为源创建新窗口。 可以在不影响调试过程的情况下关闭上一个窗口。

WinDbg GUI 中的源调试

如果使用 WinDbg,只要程序计数器位于调试器具有其源信息的代码中,就会立即显示“源”窗口。

WinDbg 为你或 WinDbg 打开的每个源文件显示一个“源”窗口。 有关此窗口的文本属性的详细信息,请参阅 源 Windows

然后,可以单步执行应用程序或执行到断点或游标。 有关单步执行和跟踪命令的详细信息,请参阅 控制目标

如果处于源模式,则单步执行应用程序时,相应的“源”窗口将移动到前台。 由于还有在应用程序执行期间调用的 Microsoft Windows 例程,因此当此类调用发生时,调试器可能会将 反汇编窗口 移动到前台 (,因为调试器无权访问这些函数) 的源。 当程序计数器返回到已知的源文件时,相应的“源”窗口将变为活动状态。

在应用程序中移动时,WinDbg 会在“源”窗口和“反汇编”窗口中突出显示你的位置。 还突出显示了设置断点的行。 源代码根据语言分析进行着色。 如果已选择“源”窗口,可以使用鼠标将鼠标悬停在符号上来计算它。 有关这些功能以及如何控制这些功能的详细信息,请参阅 源 Windows

若要在 WinDbg 中激活源模式,请使用 l+t 命令,单击调试菜单上的源模式,或单击源模式上的按钮。 当源模式处于活动状态时, ASM 指示器在状态栏上显示为不可用。

在源模式下单步执行函数时,可以查看或更改任何局部变量的值。 有关详细信息,请参阅 读取和写入内存

调试器命令窗口中的源调试

如果使用 CDB,则没有单独的“源”窗口。 但是,在单步执行源时,仍可以查看进度。

在 CDB 中执行源调试之前,必须通过发出 .lines (切换源行支持) 命令或通过使用 -lines 命令行选项启动调试器来加载源行符号。

如果执行 l+t 命令,则所有程序单步执行一次一个源行。 使用 l-t 一次执行一个程序集指令。 如果使用 WinDbg,此命令的效果与在“调试”菜单上选择或清除“源模式”或使用工具栏按钮的效果相同。

l+s 命令在提示符处显示当前源行和行号。 如果只想查看行号,请改用 l+l

如果使用 l+ol+s,则在单步执行程序时仅显示源行。 程序计数器、反汇编代码和寄存器信息处于隐藏状态。 通过这种显示,可以快速单步执行代码并查看源。

可以使用 lsp (Set Source Line number) 命令指定单步执行应用程序时显示的源行数。

以下命令序列是单步执行源文件的有效方法。

.lines        enable source line information
bp main       set initial breakpoint
l+t           stepping will be done by source line
l+s           source lines will be displayed at prompt
g             run program until "main" is entered
pr            execute one source line, and toggle register display off
p             execute one source line 

由于 ENTER 重复上一个命令,因此现在可以使用 Enter 键单步执行应用程序。 每个步骤都会显示源行、内存偏移量和程序集代码。

有关如何解释反汇编显示的详细信息,请参阅 在程序集模式下调试

显示程序集代码时,正在访问的任何内存位置将显示在行的右端。 可以使用 d* (显示内存) e* (输入值) 命令查看或更改这些位置的值。

如果必须查看每个程序集指令以确定偏移量或内存信息,请使用 l-t 逐步执行程序集指令,而不是源行。 仍可显示源行信息。 每个源行对应于一个或多个程序集指令。

所有这些命令在 WinDbg 和 CDB 中都可用。 可以使用命令从 WinDbg 的 “调试器命令”窗口 而不是“源”窗口查看源行信息。

源行和偏移量

还可以通过使用表达式计算器来确定对应于特定源行的偏移量来执行源调试。

以下命令显示内存偏移量。

? `[[module!]filename][:linenumber]` 

如果省略 文件名,调试器将搜索对应于当前程序计数器的源文件。

调试器以十进制数形式读取 亚麻小数 ,除非在它前面添加 0x ,而不考虑当前的默认基数。 如果省略 亚麻,则表达式的计算结果为对应于源文件的可执行文件的初始地址。

仅当 .lines 命令或 - lines 命令行选项已加载源行符号时,CDB 才会理解此语法。

此方法非常通用,因为无论程序计数器指向何处,都可以使用它。 例如,使用此方法,可以使用以下命令提前设置断点。

bp `source.c:31` 

有关详细信息,请参阅 源行语法 和使用 断点

源模式下的单步执行和跟踪

在源模式下调试时,单个源行上可以有多个函数调用。 不能使用 pt 命令来分隔这些函数调用。

例如,在以下命令中, t 命令逐步进入 GetTickCountprintf,而 p 命令将逐步执行这两个函数调用。

printf( "%x\n", GetTickCount() );

如果要在跟踪到其他调用时单步执行某些调用,请使用 .step_filter (设置步骤筛选器) 来指示要单步执行哪些调用。

可以使用 _step_filter 筛选出框架函数 (,例如 Microsoft 基础类 (MFC) 或活动模板库 (ATL) 调用) 。