在 zxdb 中使用断点

断点会在执行某些代码时停止执行。如需创建断点,请使用 break 命令(简称 b)并为其指定位置:

[zxdb] break main
Breakpoint 3 (Software) on Global, Enabled, stop=All, @ main
   180
 ◉ 181 int main(int argc, char**argv) {
   182     fbl::unique_fd dirfd;

位置可以用多种不同的方式表示。

  • 简单的函数名称。这会将函数与任何命名空间中的名称进行匹配:

    [zxdb] break main
    
  • 成员函数或特定命名空间或类中的函数:

    [zxdb] break my_namespace::MyClass::MyFunction
    [zxdb] break ::OtherFunction
    
  • 源文件 + 行号(以冒号分隔):

    [zxdb] break mymain.cc:22
    
  • 当前帧的当前源文件中的行号(在步进时很有用):

    [zxdb] break 23
    
  • 内存地址:

    [zxdb] break 0xf72419a01
    
  • 表达式:添加“*”前缀会将以下输入视为计算结果为地址的表达式。这种方式最常与硬件断点一起使用。

    [zxdb] break --type=write *&foo
    

如需列出所有断点,请运行以下命令:

[zxdb] breakpoint

如需清除特定断点,请提供该断点索引作为清除命令的上下文(请参阅上面的“交互模型”)。以下是我们使用的 breakpoint (bp) 的缩写:

[zxdb] bp 2 clear

或者,您也可以清除当前断点:

[zxdb] clear

每当您创建或停止某个断点时,该断点都会自动成为默认断点,因此 clear 始终会清除您刚刚遇到的断点。

clear 也可以接受可选位置,就像 break 命令一样。这样一来,它会尝试清除该位置的所有断点,并忽略默认的断点上下文。

GDB 用户注意事项:delete <index> 会映射到 bp <index> clear,而 clear <number> 在 GDB 和 zxdb 中的行为相同。

您也可以启用或停用断点:

[zxdb] disable
[zxdb] bp 4 enable

其他属性可通过“get”和“set”命令进行修改。

[zxdb] bp 1 set location = Frobulator::GetThing

条件断点

断点可以有条件,该条件是计算结果为 true 或 false 的表达式。除非条件为 true,否则断点不会触发停止。例如,假设某个源文件

    7 void do_loop(int n) {
    8   for (int i = 0; i < n; i++) {
 ▶  9     std::cout << "Hello world!" << std::endl;
   10   }
   11 }

可以设置一个仅在最后一次迭代时停止的断点。

b 9 if i == n - 1

硬件数据断点(“监视点”)

可以对处理器进行设置,使其在读取或写入特定地址时中断执行。这对于跟踪内存损坏特别有用。通过在断点命令的“类型”中指定“写入”“执行”或“读写”来创建硬件断点(与其他某些调试程序不同,硬件断点公开为断点类型,而不是单独的“监视点”概念)。

[zxdb] break --type=read-write --size=4 0x12345670

作为一种快捷方式,“watch”命令将获取变量的内容或表达式的结果,并在其范围内设置数据写入断点:

[zxdb] watch i
[zxdb] watch foo[5]->bar

注意:

  • CPU 仅支持有限数量的硬件监视点,通常约为 4 个。

  • 监视点范围的大小上限为 1、2、4 或 8 个字节,并且地址大小必须是该大小的偶数倍。

  • 与 GDB 不同,“watch”会对表达式求值一次,并在结果中设置一个断点。而不会重新评估表达式。在上面的示例中,它会在“bar”发生变化时触发,但在 foo[5] 更改为指向其他“bar”时则不会触发。

  • 如果您观察到堆栈上的某个变量且无人触及该变量,则经常会看到当重复使用堆栈内存时,该变量在程序的其他部分命中。如果您遇到意外的断点命中,请检查执行是否仍在预期帧中。

程序化断点

如果您想捕获某些特定条件,可以在代码中插入硬编码断点。Clang 具有内置代码(在 GCC Zircon 版本中无法运行):

__builtin_debugtrap();

如果调试程序已连接到进程,它将像遇到正常断点一样停止。您可以从该步骤中继续操作,也可以继续操作。如果尚未连接调试程序,将导致崩溃。