Debugging Tools for Windows
|
如果可以分析源代码而不是反汇编二进制代码,调试程序会更加容易一些。
当源代码是
C
、
C++
或汇编语言时,
WinDbg
、
CDB
和
KD
可以在调试中使用它们。
编译的要求
要进行源码调试,必须让编译器或链接器在构建二进制文件时生成符号文件
(
.pdb
文件
)
。这些符号文件保存了二进制指令和源码行之间的对应关系。
另外,调试器必须能够访问源码文件,因为符号文件中并不包含实际的源代码文本。
如果这些都满足,编译器和链接器还不能对代码进行优化。如果代码经过优化,在源码调试时访问局部变量会变得很困难,有时候几乎是不可能的。如果使用
Build
实用程序作为编译器和链接器,可以将
MSC_OPTIMIZATION
宏设置为
/Od /Oi
来避免优化。
定位符号文件和源码文件
在源码模式下调试,调试器必须能够找到源码文件和符号文件。更多信息,查看
设置路径和加载文件
。
开始源码调试
只要调试器拥有当前被调试线程的正确的符号和源码文件,就可以显示源码信息。
如果使用调试器启动一个新的用户模式程序,在
Ntdll.dll
加载程序时初始断点就会触发。由于调试器不能访问
Ntdll.dll
的源码文件,所以这时不能访问应用程序的源码信息。
要将程序计数器移动到程序的开始位置,可以在二进制代码入口点设置断点。在
调试器命令窗口
输入下面的命令。
bp main
g
之后,程序会被加载起来并在进入
main
函数时停止。
(
当然,可以使用任何入口点,而不仅仅是
main
。
)
如果程序抛出一个异常,它会中断到调试器中。这时源码信息是可用的。但是,如果通过
CTRL+C
、
CTRL+BREAK
或
Debug | Break
命令来中断,调试器创建了一个新线程,所以不能看到源代码。
当到达具有源码文件的线程时,在调试器命令窗口中就可以执行源码调试命令了。如果使用
WinDbg
,
Source
窗口
会出现。如果已经通过点击
File
菜单的
Open Source File
打开了源码窗口,
在
WinDbg GUI
中进行源码调试
如果使用
WinDbg
,当程序计数器运行到调试器拥有源码信息的代码时,一个源码窗口会出现。
WinDbg
为用户或它自己打开的每个源文件显示一个源码窗口。关于该窗口的文本属性的更多信息,查看
Source
窗口
。
之后可以单步执行程序、执行到断点或执行到光标。关于单步和跟踪命令的更多信息,查看
控制目标
。
源码模式调试时,如果单步执行程序,合适的源码窗口会移动到前台。因为应用程序执行中也会调用到一些
Microsoft Windows
函数,这时调试器可能会将
反汇编窗口
移 到前台
(
因为调试器不能访问这些函数的源码
)
。当程序计数器又返回到已知的源码文件,相关的源码窗口又会被激活。控制应用程序执行时,
WinDbg
将源码 窗口和汇编窗口中所在的位置用绿色高亮。设置了断点的行为红色
(
启用的断点
)
、黄色
(
禁用的断点
)
或紫色
(
如果当前程序计数器是断点位置
)
。源代码会根据 对语言的分析进行着色。如果已经选中了源码窗口,则可以将鼠标移动到符号上来查看它的值。关于这些特性的信息以及如何控制它们,查看
Source
窗口
。
在
WinDbg
中激活源码调试,可以使用
L+t
命令、点击
Debug
菜单的
Source Mode
或在工具栏点击
Source mode on
按钮
(
)
。
源码模式激活时,状态栏的
ASM
指示器会变为灰色。
源码模式下单步执行某个函数时,可以查看或修改它的任何局部变量的值。更多信息,查看
读写内存
。
调试器命令窗口中的源码调试
如果使用
CDB
,则没有单独的源码窗口。但是,在单步执行源码时还是可以查看运行的情况。
使用
CDB
源码调试之前,必须通过
.lines (Toggle Source Line Support)
命令加载源码行符号,或者使用
-lines
命令行选项
启动调试器。
如果使用了
l
l+t
命令,则每次单步执行一行源码。使用
L-t
来一次执行一条汇编指令。如果使用
WinDbg
,该命令和选中或清除
Debug
菜单上的
Source Mode
或使用工具栏菜单的效果一样。
l+s
命令在提示符显示当前的代码行和行号。如果只想显示行号,使用
l+l
。
如果使用
l+o
和
l+s
,在单步执行时只会显示源码行。程序计数器、汇编码和寄存器信息都不会显示。这种显示类型使得可以快速通过源码来单步调试而不会看到除了源码之外的东西。
用
lsp (Set Number of Source Lines)
命令来指定单步或者执行程序时显示的源码行数。
下面的命令序列是一种单步执行源码文件的有效方式。
.lines
启用源码行信息
bp main
设置初始断点
l+t
按源码行进行单步
l+s
命令窗口中显示源码行
g
运行程序,直到
"main"
函数
pr
执行一行源码,并将寄存器切换为不显示
p
执行一行源码
因为
ENTER
会重复最后一条命令,所以现在可以通过
ENTER
键来单步调试程序了。每一步都会有源码行、内存偏移和汇编代码显示出来。
关于反汇编显示的更多信息,查看
汇编模式调试
。
当显示汇编代码时,在每行右边末尾会显示出任何访问到的内存位置。用
d* (Display Memory)
和
e* (Enter Values)
命令来查看或修改这些位置的值。
如果需要查看每条汇编代码来确认偏移或内存信息,使用
l-t
来以汇编指令单步而不是用源码。源码行信息仍然可以显示出来。每行源码和一条或多条汇编指令对应。
所有这些命令在
WinDbg
和
CDB
中都可用。可以使用这些命令来在
WinDbg
的
调试器命令窗口
查看源码,而不是在源码窗口中。
源码行和偏移
使用表达式求值器来确定和指定源码行关联的偏移位置也可以进行源码调试。
下面的命令显示一个内存偏移。
? `
[[
module
!
]
filename
][
:
linenumber
]
`
如果省略
filename
,调试器会搜索和当前程序计数器位置符合的代码。
不管当前使用的基数是什么,如果没有添加
0x
前缀,调试器认为
linenumber
是
10
进制数。如果省略了
linenumber
,表达式的值为和源码文件关联的可执行文件初始地址。
CDB
中只有在使用了
.lines
命令或
-lines
命令行选项来加载源码行符号时才能识别该语法。
该技术非常有用,因为不管当前的程序计数器指向什么地方都可以使用。例如,可以使用下面这样的命令来预先设置断点。
bp `source.c:31`
源码模式下的单步和跟踪
以源码模式调试时,单行代码种可能有多个函数调用。不能使用
p
和
t
来分开这些调用。
例如,在下面的命令中,
t
命令会单步进入
GetTickCount
和
printf
,而
p
命令会单步步过两个调用。
printf( "%x\n", GetTickCount() );
如果在跟踪进入其他调用时想步过某个调用,用
.step_filter
(Set Step Filter)
来指定步过哪些调用。
可以使用
_step_filter
来跳过框架函数
(
例如,对微软基本类库
(Microsoft Foundation Classes,MFC)
或活动模板库
(ATL)
的调用
)
。
© 2008 Microsoft Corporation
Send feedback on this topic
Debugging Tools for Windows
August 24, 2008
翻译:NetRoc
Build machine: CAPEBUILD