WinDbg 设置断点

在windbg中,断点设置的地址形式有好多种,可以是以下几种:
1.虚拟地址:即给出直接地址,如 12345678
2.函数偏移量:如DriverEntry+5c.
3.源代码+行数 :`[[Module!]Filename][:LineNumber]`
4.对C++可以对模块中的某个类的方法设置断点:
 
设置断点语法:
         
1:无条件设置断点:   bp  Address
  例如:
    kd> bp 0040108c
    kd> bp main+5c
    kd> bp `source.c:31` 
    kd> bp MyClass::MyMethod 
    kd> bp MyClass__MyMethod 
    kd> bp @@( MyClass::MyMethod )
 
2:设置有条件断点
  
kd>  bp  Address  "j ( Condition ) ' OptionalCommands '; 'gc' " kd> bp  Address  ".if ( Condition ) { OptionalCommands } .else {gc}"

这两种设断点语法是等价的。

 

bp,bu,bm 的区别:

bu:Set Unresolved Breakpoint


bp 和bu的区别:
 1:bp是立即生效,且马上被转化为内存中的某个地址,如果调式模块被改变,bp指向的地址不会变,而bu只是和symbol文件相关联,模块改变的时候,指向的symbol的offset或者plus是不变的
 2: bp指定的断点在模块unload之后从bl列表中删除,而bu的断点是永远存在的。
 3:在windbg的可视源码或者可视的反汇编代码中所设的断点都是bu模块的断点
bm:Set Symbol Breakpoint
 使用bm设置断点支持正则表达式的模式匹配,所以可以使用他来设置多个断点
 如果正则表达式被匹配的话,他的效果将和bu设置的是一样的
 例如:
    0:000> bm dbgtest!*main*
 1: 00413530 @!"dbgtest!wmain"
 2: 00411810 @!"dbgtest!__tmainCRTStartup"
 3: 004117f0 @!"dbgtest!wmainCRTStartup"
 使用bp和bm /a的风险:
  当wndbg在设置软件断点在代码段的时候,windbg将程序指令替换为断点指令,但是当断点设置在数据段的时候,将会将程序数据替换为断点指令,从而 导致数据被修改,因此在设置断点在数据段的时候,推荐使用 ba(ba (Break on Access).)指令
 
 
控制断点的方法

使用下面一些方法来控制或显示断点:

每个断点都有一个关联的10进制数字称为断点ID 。该数字在各种命令中用于指定断点。

未定断点:BU vs. BP

如果一个断点是设置在某个还未加载的函数名上,则称为延迟虚拟未定 断点。 (这些术语可交替使用。) 未定断点没有被关联到任何具体被加载的模块上。每当一个新的模块被加载时,会检查该函数名。如果这个函数出现,调试器计算虚拟断点的实际位置并启用它。

使用bu 设置的断点自动被认为是未定断点。如果断点在一个已加载模块中,则会启用并正常生效。但是,如果模块之后被卸载并重新加载,这个断点不会消失。而使用bp 设置的断点会立即绑定到某个地址。

bpbu 断点有以下三个主要的不同点:

当在WinDbg 反汇编窗口 源码窗口 中使用鼠标设置断点时,调试器创建的是bu 断点。

初始断点

当调试器启动一个新的目标程序时,初始断点在主映像和所有静态加载的DLL被加载、DLL初始化例程被调用之前自动触发。

调试器附加到一个已存在的用户模式程序时,初始断点立即触发。

-g 命令行选项使得WinDbg或CDB跳过初始断点。在这时可以自动执行命令。更多信息,查看 控制异常和事件

如果想启动新调试目标并在实际的程序即将开始执行的时候中断下来,就不要使用-g 选项。应该让初始断点被触发。当调试器激活之后,在mainwinmai 函数上设置断点并使用g (Go) 命令。之后所有初始化过程都会运行并且程序在main函数即将执行时停止。

关于内核模式的自动断点的更多信息,查看崩溃和重起目标机

断点中的地址

断点支持几种地址语法,包括虚拟地址、函数偏移和源码行号。例如,可以使用下面的方法之一来设置断点:

0:000> bp 0040108c
0:000> bp main+5c
0:000> bp `source.c:31`

关于这些语法的更多信息,查看数值表达式语法 源码行语法 ,以及各个命令的主题。

断点的数量

在内核模式下,最多可以使用32个断点。在用户模式下,可以使用任意数量的断点。

数据断点的数量由目标处理器架构决定。

方法的断点

如果要在MyClass 类的MyMethod 方法上设置断点,可以使用两种不同语法:

    • 用MASM表达式语法,可以用双冒号或者双下划线来指定一个方法。

      0:000> bp MyClass::MyMethod  
      0:000> bp MyClass__MyMethod  

    • 用C++表达式语法,必须用双冒号指定方法。

      0:000> bp @@( MyClass::MyMethod )  

如果要使用更复杂一些的断点命令,应该使用MASM表达式语法。表达式语法的更多信息,查看表达式求值

用户空间和系统空间

每个用户模式应用程序在虚拟内存0x00000000 到0x7FFFFFFF 的地址称为用户空间

当WinDbg或CDB在小于0x80000000的地址上下断时,断点是在单个进程的指定的用户空间的地址设置。用户模式调试时,当前进程决定了虚拟地址的意义。更多信息,查看控制进程和线程

在内核模式,可以使用bpbuba 命令和Breakpoints 对话框在用户空间设置断点。必须首先使用.process /i (或在一些内核空间的函数上的指定进程的断点)来将目标切换成当前进程上下文 ,并使用该进程上下文 来指定拥有目标地址空间的用户模式进程。

用户模式的断点总是和设置该断点时进程上下文为激活状态的进程关联起来。如果有用户模式调试器在调试该进程,而还有一个内核模式调试器在调试进程运行的机器,即使断点由内核调试器设置,它中断时也是进入用户模式调试器。这时可以从内核模式调试器中断系统,或使用.breakin (Break to the Kernel Debugger) 命令来将控制权交给内核调试器。

注意   如果目标机运行在Microsoft Windows NT 4.0上,则不能使用内核调试器在用户空间中设置断点。

断点伪寄存器(Pseudo-Registers)

如果在某个表达式中想引用某个断点的地址,可以使用一个$bp Number 语法的伪寄存器 Number 是断点ID。关于该语法的更多信息,查看伪寄存器语法

设置断点时的风险

当使用内存地址或符号加偏移的方式设置断点时,一定不能将断点设置到一条指令的中间。

例如,有下面一段汇编代码。

770000f1 5e               pop     esi
770000f2 5b               pop     ebx
770000f3 c9               leave
770000f4 c21000           ret     0x10
770000f7 837ddc00         cmp     dword ptr [ebp-0x24],0x0

前三条指令只有1个字节长。但是第四条指令有3字节长。(包含在0x770000F4,0x770000F5, 和0x770000F6三个地址的字节)如果要在该指令上使用bpbuba 设置断点,则必须将地址指定为0x770000F4 。

如果使用ba 命令在0x770000F5 地址设置了断点,处理器将在该位置设置断点。但是 该断点永远不会被触发,因为处理器认为0x770000F4 才是这条指令的实际地址。

如果使用bpbu 命令在 0x770000F5 设置断点,调试器在这个位置会写入断点。但是由于调试器使用如下方法设置断点,它可能造成目标运行错误:

    • 调试器保存0x770000F5 地址的内容,并用一条断点指令写入该地址。
    • 如果用调试器显示这段内存的内容,并不会显示被写入的断点指令,而是显示那里原来"应该是"的内容。即调试器显示原来的内存,或者断点设置之后该内存被修改的内容。
    • 如果使用BC 命令删除断点,调试器将断点位置的内存恢复成原始值。

当在0x770000F5设置断点时,调试器保存它的值并写入断点指令。但是当程序运行时到达0x770000F4 时,会将它视为一条多字节指令的第一个字节。处理器将0x770000F4、0x770000F5可能还有后面的一些字节当作一条指令。这会产生各种非正 常的行为。

因此,当使用bpbuba 命令设置断点时,要确定断点在合适的地址上。如果使用WinDbg图形界面来添加断点就不用在意这样的情况,因为它会自动选择正确的地址。

断点命令

可以在断点中包含一条命令用于在断点触发时自动执行。

也可以包含一条用于执行的命令字符串。但是,其中任何恢复程序执行的命令(例如gt )都会终止命令列表的执行。

例如下面的命令在MyFunction+0x47 中断,写入一个dump文件并恢复执行。

0:000> bu MyFunction+0x47 ".dump c:/mydump.dmp; g"  

注意   如果正在从内核调试器控制用户模式调试器,不要在命令字符串中使用g (Go) 。串口的速度可能跟不上该命令,并且不能再中断到CDB中。关于这种情况的更多信息,查看从内核调试器控制用户模式调试器

@!"<chars>"

@!" <chars> " 语法用于在MASM求值器中进行转义,使得符号解析支持任意文本。必须以@!" 开始并以引号(" )结束。如果不使用该语法,则在MASM表达式的符号名中不能使用空格、大于小于号(<, >)和其他特殊字符。模板和重载是符号中需要这种引号的主要原因。也可以使用如下的@!"<chars>" 语法来设置bu 命令。

0:000> bu @!" ExecutableName !std::pair<unsigned int,std::basic_string<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> > >::operator="

这个例子中,ExecutableName 是一个可执行文件的名字。

这种转义语法在C++中比C中更加有用(例如重载的操作符),因为C函数名中不会存在空格(或特殊字符)。但是,该语法在托管代码中也同样重要,因为.NET Framwork中非常多的使用重载。

条件断点

可以设置仅在特定条件下被触发的断点。关于这类断点的更多信息,查看设置条件断点

Windbg(Windows Debugger)是微软官方提供的一款强大的调试工具,主要用于分析和调试Windows系统下的应用程序。设置断点是调试过程中的重要步骤,它允许你在程序执行到特定行或代码块时暂停,以便查看和修改变量值、检查调用堆栈等。 以下是设置断点的基本步骤: 1. **打开Windbg**:首先,你需要打开Windbg,可以通过“开始”菜单搜索或直接运行`cdb.exe`(命令行版)或`windbg.exe`(图形界面版)。 2. **加载目标模块**:如果你知道要调试的应用程序的进程ID(PID)或进程名,使用`!process`命令加载它。例如:`.reload /f <进程名>` 或 `~pid <进程ID>`。 3. **找到源代码位置**:在加载了目标模块后,使用`lm`(list modules)命令查看模块信息,然后找到你想要设置断点的源代码行号,通常文件路径会出现在模块信息中。 4. **设置断点**:使用`bp`命令加上模块路径和行号,例如:`bp <模块路径>\function_name + line_number`。你也可以使用符号文件(.pdb)的相对路径来设置断点,如:`bp !function_name`。 5. **断点选项**:如果需要,你可以添加条件、步进等选项,例如设置只在满足某个条件时触发断点,用`b`命令后跟条件表达式,如 `b function_name(line_number) condition`。 6. **启动调试**:最后,启动你要调试的进程,Windbg会在设置断点处停止程序执行。 相关问题: 1. Windbg除了断点还有哪些调试功能? 2. 如何在Windbg中单步执行代码? 3. 如何查看断点列表和管理已设置断点
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值