在源模式下调试
如果可以分析代码的源,而不是反汇编二进制文件,则调试应用程序会更容易。
如果源语言为 C、C++ 或程序集,则 WinDbg、CDB 和 KD 可以在调试中使用源代码。
编译要求
若要使用源调试,必须在生成二进制文件时让编译器或链接器创建符号文件 (.pdb 文件) 。 这些符号文件显示调试器二进制指令与源行的对应方式。
此外,调试器必须能够访问实际的源文件,因为符号文件不包含实际的源文本。
如果可能,编译器和链接器不应优化代码。 如果代码已优化,则源调试和对局部变量的访问更加困难,有时几乎是不可能的。 如果使用生成实用工具作为编译器和链接器,请将MSC_OPTIMIZATION宏设置为 /Od /Oi 以避免优化。
查找符号文件和源文件
若要在源模式下调试,调试器必须能够查找源文件和符号文件。 有关详细信息,请参阅 源代码。
开始源调试
每当调试器具有当前正在调试的线程的正确符号和源文件时,调试器都可以显示源信息。
如果使用调试器启动新的用户模式应用程序,Ntdll.dll加载应用程序时将发生初始中断。 由于调试器无权访问Ntdll.dll源文件,因此此时无法访问应用程序的源信息。
若要将程序计数器移动到应用程序的开头,请在入口点处将断点添加到二进制文件。 在 “调试器命令”窗口中,键入以下命令。
bp main
g
然后加载应用程序,并在输入 主 函数时停止。 当然, (可以使用任何入口点,而不仅仅是 main.)
如果应用程序引发异常,它将中断到调试器中。 此时提供源信息。 但是,如果使用 CTRL+C、 Ctrl+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+o 和 l+s,则在单步执行程序时仅显示源行。 程序计数器、反汇编代码和注册信息被隐藏。 这种显示使你能够快速单步执行代码并查看源。
可以使用 lsp (“设置源行数”) 命令指定在单步执行应用程序时显示多少个源行。
以下命令序列是逐步执行源文件的有效方法。
.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,否则调试器将布劳姆伯读为十进制数,而不考虑当前的默认弧度。 如果省略 了 linenumber,表达式的计算结果为对应于源文件的可执行文件的初始地址。
仅当 .lines 命令或 -line 命令行选项已加载源行符号时,CDB 才会理解此语法。
此方法非常多才多艺,因为无论程序计数器指向何处,都可以使用它。 例如,通过此方法,可以使用以下命令提前设置断点。
bp `source.c:31`
源模式下的单步执行和跟踪
在源模式下调试时,单个源行上可以有多个函数调用。 不能使用 p 和 t 命令分隔这些函数调用。
例如,在以下命令中, t 命令会同时执行 GetTickCount 和 printf,而 p 命令将执行这两个函数调用。
printf( "%x\n", GetTickCount() );
如果要在跟踪到其他调用时单步执行某些调用,请使用 .step_filter (设置步骤筛选器) 来指示要单步执行哪些调用。
可以使用 _step_filter 筛选出框架函数 (,例如,Microsoft Foundation Classes (MFC) 或 Active Template Library (ATL) 调用) 。