bp、bu、bm(设置断点)
bp、bu 和 bm 命令设置一个或多个软件断点。 可以组合位置、条件和选项来设置不同类型的软件断点。
User-Mode
[~Thread] bp[ID] [Options] [Address [Passes]] ["CommandString"]
[~Thread] bu[ID] [Options] [Address [Passes]] ["CommandString"]
[~Thread] bm [Options] SymbolPattern [Passes] ["CommandString"]
Kernel-Mode
bp[ID] [Options] [Address [Passes]] ["CommandString"]
bu[ID] [Options] [Address [Passes]] ["CommandString"]
bm [Options] SymbolPattern [Passes] ["CommandString"]
参数
线程
指定该断点应用于的线程。 有关语法详细信息,请参阅 线程语法。 只能在用户模式下指定线程。 如果未指定线程,断点将应用于所有线程。
ID
指定标识断点的十进制数。
调试器创建断点时分配 ID ,但可以使用 br (Breakpoint Renumber ) 更改它。 可以使用 ID 在 稍后的调试器命令中引用断点。 若要显示 断点的 ID ,请使用 bl (Breakpoint List) 命令。
在命令 中使用 ID 时,请不要在命令名称 bp (bu) ID 号之间键入空格。
ID 参数始终是可选的。 如果未指定 ID,调试器将使用第一个可用的断点号。 在内核模式下,只能设置 32 个断点。 在用户模式下,可以设置任意数目的断点。 在任一情况下,对 ID 号的值没有限制。 如果将 ID 括在 [] (方括号) ,则 ID 可以包含任何表达式。 有关语法详细信息,请参阅 数值表达式语法。
选项
指定断点选项。 可以指定以下任意数目的选项,但如下所示:
/1
创建"单次"断点。 触发此断点后,将从断点列表中删除该断点。
/pEProcess
(内核模式) 指定与此断点关联的进程。 EProcess 应为 EPROCESS 结构的实际地址,而不是 PID。 只有在此过程的上下文中遇到断点时,才触发断点。
/tEThread
(内核模式) 指定与此断点关联的线程。 EThread 应为 ETHREAD 结构的实际地址,而不是线程 ID。 只有在此线程的上下文中遇到断点时,才触发断点。 如果使用 /pEProcess 和 /tEThread,可以按任意顺序输入它们。
/cMaxCallStackDepth
仅在调用堆栈深度小于 MaxCallStackDepth 时激活断点。 不能将此选项与 /C 一起使用。
/CMinCallStackDepth
仅在调用堆栈深度大于 MinCallStackDepth 时激活断点。 不能将此选项与 /c 一起使用。
/a
(仅针对 bm) 设置所有指定位置的断点,无论断点位于数据空间还是代码空间中。 由于数据断点可能导致程序失败,因此请仅在已知安全的位置使用此选项。
/d
(仅针对 bm) 将断点位置转换为地址。 因此,如果移动代码,断点将保留在同一地址,而不是根据 SymbolPattern 进行设置。 使用 /d 可避免在加载或卸载模块时重新评估对断点所做的更改。
/(
(仅针对 bm) SymbolString 定义的符号字符串中包含参数列表信息。
此功能使你能够在名称相同但参数列表不同的重载函数上设置断点。 例如,bm / ( myFunc 在 myFunc (int a ) 和 myFunc (字符 上设置) 。 如果没有"/ (",在 myFunc 上设置的断点将失败,因为它不会指示断点用于哪个 myFunc 函数。
/w dx 对象表达式 基于 dx 对象表达式返回的布尔值设置条件断点。 参数是一个数据模型 (dx) 表达式,其计算结果为 true (匹配条件 - 中断) 或 false (与条件不匹配 – 不中断) 。
此示例基于 localVariable 的值设置条件断点。
bp /w "localVariable == 4" mymodule!myfunction
此示例演示如何使用 JavaScript 设置断点。
bp /w "@$scriptContents.myFunc(localVariable)" @rip
有关调试器对象的信息,请参阅 dx (显示调试器对象模型表达式) 。
有关条件断点详细信息,请参阅 设置条件断点。
地址
指定设置断点的指令的第一个字节。 如果省略 Address,则使用当前指令指针。 有关语法的详细信息,请参阅地址和地址范围语法。
通过
指定激活断点时执行传递的编号。 调试器将跳过断点位置,直到达到指定的传递。 " 传递"的值 可以是任何 16 位或 32 位值。
默认情况下,断点在应用程序首次执行包含断点位置的代码时处于活动状态。 对于"传递",此默认情况等效于值为 1。 若要仅在应用程序至少执行代码一次后激活断点,请输入值 2 或更多。 例如,值 2 在代码第二次执行时激活断点。
此参数创建一个计数器,每次通过代码时,该计数器将进行减减。 若要查看传递计数器的初始值和当前 值,请使用bl (断点列表) 。
仅在应用程序执行断点后响应 g (Go 命令时,传递) 减。 如果要逐行执行代码或跟踪,则计数器不会减减。 当 传递计数器达到1 时,只有清除并重置断点才能重置它。
CommandString
指定每次遇到指定次数的断点时执行的命令列表。 必须将 CommandString 参数括 在引号中。 使用分号分隔多个命令。
CommandString 中的调试器命令可以包含参数。 可以使用标准 C 控制字符 (如\n 和 \") 。 包含在二级引号中的分号 (\") 解释 为嵌入的引号字符串的一部分。
只有在应用程序执行以响应 g (Go 命令时到达断点时,才 (CommandString) 命令。 如果要逐行执行代码或跟踪,则不执行这些命令。
在断点设置后恢复程序执行的任何 (如 g 或 t) 命令列表的执行结束。
SymbolPattern
指定模式。 调试器尝试将此模式匹配到现有符号,并设置所有模式匹配项的断点。 SymbolPattern 可以包含各种通配符和说明符。 有关此语法详细信息,请参阅 字符串通配符语法。 由于这些字符与符号匹配,因此匹配不区分大小写,并且单个前导下划线 (_) 任何数量的前导下划线。
环境
模式 |
用户模式、内核模式 |
目标 |
仅实时调试 |
平台 |
全部 |
其他信息
有关如何使用断点、其他断点命令和控制断点的方法以及如何从内核调试器在用户空间中设置断点的示例,请参阅 使用断点。 有关条件断点详细信息,请参阅 设置条件断点。
备注
bp、bu 和 bm 命令设置新的断点,但它们具有不同的特征:
bp (Set Breakpoint) 命令在命令中指定的断点位置的地址处设置新的断点。 如果调试器在设置断点时无法解析断点位置的地址表达式,则 bp 断点将自动转换为 一个基断 点。 使用 bp 命令创建在卸载模块时不再处于活动状态的断点。
" 设置 (断 点"命令) 设置延迟 断 点或 未解析断 点。 在 命令 中指定的断点位置的符号引用上设置一个基断点 (该断点不在地址) 上,并且每当解析具有引用的模块时都会激活该断点。 有关这些断点详细信息,请参阅未解析的断点 (未 解析) 。
bm (设置符号断) 命令在与指定模式匹配的符号上设置新的断点。 此命令可以创建多个断点。 默认情况下,匹配模式后, bm 断点与 bu 断点相同。 也就是说, bm 断点是在符号引用上设置的延迟断点。 但是,bm /d 命令会创建一个或多个 bp 断点。 每个断点在匹配位置的地址上设置,不跟踪模块状态。
如果不确定使用什么命令来设置现有断点,请使用 .bpcmds (Display Breakpoint Commands) 列出所有断点以及用于创建断点的命令。
bp 断点和 连接 断点有 三个主要区别 :
bp 断点位置始终转换为地址。 如果模块更改移动设置了 bp 断点的代码,断点将保留在同一地址。 另一方面, bu 断点仍与符号值相关联 (通常为符号加上已使用的偏移) ,即使其地址发生更改,它仍跟踪此符号位置。
如果在 加载 的模块中找到了 bp 断点地址,并且该模块稍后被卸载,则断点将从断点列表中删除。 另一方面, 重复 卸载和加载后,连接断点仍然存在。
使用 bp 设置的 断点不会 保存在 WinDbg 工作区中。 使用 bu 设置的断 点 保存在工作区中。
若要 在 断点的符号模式中使用通配符,bm 命令非常有用。 bmSymbolPattern 语法等效于使用 x SymbolPattern,然后在每个结果中使用 bu。 例如,若要在 Myprogram 模块中以字符串"mem"开头的所有符号上设置断点,请使用以下命令。
示例
0:000> bm myprogram!mem*
4: 0040d070 MyProgram!memcpy
5: 0040c560 MyProgram!memmove
6: 00408960 MyProgram!memset
由于 bm 命令将软件断点 (处理器断点) ,因此在设置断点时会自动排除数据位置,以避免损坏数据。
使用 bp 或 bm /a 命令时,可以指定数据 地址而不是程序 地址。 但是,即使指定了数据位置,这些命令也创建软件断点,而不是处理器断点。 如果软件断点放置在程序数据而不是可执行代码中,则可能会导致数据损坏。 因此,只有在确定存储在该位置的内存将用作可执行代码而不是程序数据时,才应在数据位置使用这些命令。 否则,应改为使用 ba (Break on Access) 命令。 有关更多详细信息,请参阅 (ba Breakpoints) 。
若要详细了解如何在由更复杂的语法指定的位置(如 C++ 公共类的成员)或包含其他受限制字符的任意文本字符串上设置断点,请参阅断点 语法。
如果单个逻辑源行跨越多个物理行,则断点在语句或调用的最后一个物理行上设置。 如果调试器无法在请求的位置设置断点,它会将断点置于下一个允许的位置。
如果指定 Thread,则指定线程上设置断点。 例如, ~*bp 命令在所有线程上设置断点,~ #bp 在导致当前异常的线程上设置断点,~ 123bp 在线程 123 上设置断点。 ~bp 和~.bp 命令都在当前线程上设置断点。
在内核模式下调试多处理器系统时,使用 bp 或 ba (Break on Access 设置) 适用于所有处理器。 例如,如果当前处理器为 3,并且键入 bp MemoryAddress 以将断点置于 MemoryAddress。 在地址处执行的任何处理器 (处理器 3) 会导致断点陷阱。
bp、bu 和 bm 命令通过用中断指令替换处理器指令来设置软件断点。 若要调试无法更改的只读代码或代码,请使用 ba e 命令,其中 e 表示仅执行访问。
以下命令设置一个断点,该断点超过 函数 MyTest 的开头 12 个字节。 对于前六个通过代码的传递,将忽略此断点,但在第七次通过代码时停止执行。
0:000> bp MyTest+0xb 7
以下命令在 RtlRaiseException 处设置断点,显示 eax 寄存器,显示 符号 MyVar 的值,然后继续。
kd> bp ntdll!RtlRaiseException "r eax; dt MyVar; g"
以下两个 bm 命令设置了三个断点。 执行命令时,显示的结果不会区分使用 /d 开关创建的断点和没有它创建的断点。 . bpcmds (Display Breakpoint Commands) 可用于区分这两种类型。 如果断点是由不带 /d 开关的 bm 创建的,则 .bpcmds 显示将断点类型指示为 bu,后跟括在 @!"标记 ((指示它是文本符号而不是数值表达式或寄存器) )中的计算符号。 如果断点是由 bm 使用 /d 开关创建的, 则 .bpcmds 显示将断点类型指示为 bp。
0:000> bm myprog!openf*
0: 00421200 @!"myprog!openFile"
1: 00427800 @!"myprog!openFilter"
0:000> bm /d myprog!closef*
2: 00421600 @!"myprog!closeFile"
0:000> .bpcmds
bu0 @!"myprog!openFile";
bu1 @!"myprog!openFilter";
bp2 0x00421600 ;