Debugging Tools for Windows |
bp、bu和bm命令设置一个或多个软断点(software breakpoints)。可以组合位置、条件和选项来设置各种不同类型的软断点。
用户模式
[~Thread] bu[ID] [Options] [Address [Passes]] ["CommandString"]
[~Thread] bm [Options] SymbolPattern [Passes] ["CommandString"]
内核模式
bu[ID] [Options] [Address [Passes]] ["CommandString"]
bm [Options] SymbolPattern [Passes] ["CommandString"]
调试器在创建断点时指派ID,但是之后可以通过br (Breakpoint Renumber)命令来改变它。在其他调试器命令中使用ID来引用断点。要显示断点的ID,可以使用bl (Breakpoint List)命令。
在命令中使用ID时,不能在命令(bp 或bu)和ID号之间加入空格。
ID 参数总是可选的。如果不指定ID,调试器使用第一个可用的断点号。内核模式下只能设置32个断点。用户模式下可以设置任意多个断点。但是哪种情况下对ID号的值都没有限制。如果使用中括号([])将ID括起来,ID可以包含任意表达式。该语法的详细信息,查看数值表达式语法。
这个功能使得可以对具有相同名字但是不同参数列表的重载函数设置断点。例如, bm /( myFunc 同时在myFunc(int a)和myFunc(char a)上设置断点。如果没有"/(",对myFunc 设置的断点会失败,因为这样不能确定断点设置到哪一个myFunc 上。
默认情况下,断点在第一次执行断点位置的代码时被激活。这种默认情况和把Passes 设置为1是一样的。要使得断点在程序至少执行该代码一次之后才激活,可以将这个值设置为2或更大。例如,值为2时,使得断点在第二次执行到该代码时被激活。
该参数创建一个在每次执行断点处的代码时被减少1的计数器。要查看Passes 计数器的初始值和当前值,使用bl (Breakpoint List)。
Passes 仅当程序响应g (Go)命令并执行通过断点时才减少。单步或跟踪(tracing)通过它是不会减少的。当Passes 到达1时,可以通过清除并重设断点来重置它。
CommandString 中的调试器命令可以包含参数。可以使用标准C控制字符(如\n 和\")。二级引号(\")中的分号被当作引号中的字符串的一部分。
CommandString命令仅当程序响应g (Go)命令并执行通过断点时才会执行。单步或跟踪(tracing)执行断点处的命令时是不会触发的。
任何在中断后恢复程序运行的命令(如g 或t)都会结束命令列表的执行。
模式 | 用户模式、内核模式 |
目标 | 仅活动目标 |
平台 | 所有 |
bp、bu和bm 命令设置新断点,但是它们有不同的特点:
使用bp命令时,断点位置始终被转换成地址。如果bp 断点设置的代码被移动了,该断点仍然保持在相同位置并且可能指向不同的代码或者非法位置。
相反的,bu 断点始终和命令指定的符号化的断点位置关联(一般是符号加上一个可选的偏移)。这种关联在符号的值改变或者包含该位置的模块加载或卸载之后仍然保持。
使用bp 设置的断点会保持到使用bc (Breakpoint Clear)命令或WinDbg的Breakpoints 对话框移除为止。但是,因为这些断点指向的是一个地址,bp 断点在包含所引用的位置的模块卸载之后就不再有效了。
bu 设置的断点会保存在WinDbg工作空间中,但是bp 设置的断点不会保存。
当使用鼠标在WinDbg的反汇编窗口或源码窗口中设置断点时,调试器创建bu断点。
bm 在想使用包含通配符的符号模板来设置断点时很有用。bm SymbolPattern 语法和使用x SymbolPattern然后对搜索结果使用bu 是一样的。例如,要在Myprogram 模块中所有以字符串"mem"开头的符号上设置断点,可以使用如下命令。
4: 0040d070 MyProgram!memcpy
5: 0040c560 MyProgram!memmove
6: 00408960 MyProgram!memset
由于bm命令设置软断点(不是处理器断点),它会自动避开数据位置,以避免破坏数据。
但是,当使用bp 和bm /a时要小心。这些命令可以在数据段中设置软断点。调试器在代码上设置软断点时,会将处理器指令替换为中断指令。但是当调试器在数据段设置软断点时,会把数据替换为中断指令。这种中断指令会破坏数据。只有在只当作代码进行执行的数据上设置软件断点才是安全的。要在数据段设置断点,使用ba (Break on Access)命令。该命令可以设置数据断点而不是软件断点。
要在例如C++公有类这样的任意文本上设置断点,或者在operator new 函数上设置断点,需要将表达式括在园括号中。例如,使用bp (??MyPublic) 或bp (operator new)。
要在MASM表达式类型的任意文本上设置断点,使用bu @!"text"。要使用C++语法文本设置断点,对C++兼容的符号使用bu @@c++(text)。
Bp、bu和bm命令通过将处理器命令替换为中断指令来设置软断点。要调试只读代码或不能改变的代码,使用ba e 命令,e用于设置执行访问。
如果单个逻辑代码行跨越了多个物理行,断点设置在语句或调用的最后一个物理行上。如果调试器在要求的位置不能设置断点,则会将断点放到下一个可用的位置上。
如果指定了Thread,断点设置在指定线程上。例如,~*bp在所有线程上设置断点, ~#bp在产生当前异常的线程上设置,而 ~123bp 在线程123上设置。~bp 和~.bp 命令都在当前线程设置断点。
在内核模是下调试多处理器系统时,使用bp 或ba (Break on Access)设置的断点会应用到所有处理器。例如,如果当前处理器是3,并且输入bp MemoryAddress来在 MemoryAddress上设置了断点。任何执行到该地址的处理器(不止是处理器3)都会产生断点陷阱。
下面的例子说明了如何使用不bp命令。这个命令在MyTest 函数后面12字节位置处设置断点。该断点忽略前6次对指定代码的执行,但是第7次执行该代码时会中断下来。
下面的命令在RtlRaiseException 上设置断点,显示eax寄存器并显示符号MyVar 的值,然后继续。
关于如何使用断点、其他断点命令和控制断点的方法、如何在内核调试器下在用户空间设置断点的更多信息,查看使用断点。关于设置条件断点的更多信息,查看设置条件断点。