使用断点

断点会在代码执行时停止执行。如需创建断点,请使用 break 命令并为其指定断点位置。

例如,如需在 main 函数上创建断点,请使用以下代码:

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

成员函数

您可以在特定命名空间或类中指定成员函数或函数:

break my_namespace::MyClass::MyFunction
[zxdb] break ::OtherFunction

来源和行

您还可以指定要中断的源文件和行号:

break mymain.cc:22

行号

您可以指定当前帧的当前源文件中的行号。在浏览代码时,这非常有用:

break 23

内存地址

您可以指定内存地址:

break 0xf72419a01

表达式

您可以指定一个表达式,如需详细了解 zxdb 中的表达式,请参阅评估表达式。使用 * 作为前缀会将后续的输入视为一个表达式,该表达式会求值为特定地址。在使用硬件断点时,这非常有用。

break --type=write *&foo

列出断点

如需查看所有断点,请使用 breakpoint

breakpoint
  # scope  stop enabled type     #addrs hit-count location
▶ 3 global all  false   software      1         0 machine.h:7

移除断点

如需移除特定断点,请将该断点编号作为 breakpoint <index> rm 的上下文。

例如,如需清除 breakpoint 3,请执行以下命令:

breakpoint 3 rm
Removed Breakpoint 3 enabled=false @ machine.h:7

清除断点

如需移除特定位置的所有断点,您无需指定索引:

clear

当您创建断点或在断点上停止时,该断点会自动成为默认断点。每当您在不指定索引的情况下运行 clear 时,该命令都会清除您触发的最新断点。

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

停用断点

例如,如需停用断点 3,请执行以下操作:

breakpoint 3 disable
Disabled Breakpoint 3 enabled=false @ machine.h:7
   35   static constexpr SizeType InitialStackPointer(SizeType base, SizeType size) {
   36     // Stacks grow down on most machines.
 ◯ 37     return (base + size) & -kStackAlignment<SizeType>;
   38   }
   39 };

如需停用当前断点,请执行以下操作:

disable
Disabled Breakpoint 2 enabled=false @ main.rs:5
   24
   25 enum Services {
 ◯ 26     ComponentRunner(frunner::ComponentRunnerRequestStream),
   27     StarnixManager(fstarnixrunner::ManagerRequestStream),
   28     AttributionProvider(fattribution::ProviderRequestStream),

启用断点

停用断点后,您可能需要重新启用已停用的断点。

例如,如需启用断点 3,请执行以下命令:

breakpoint 3 enable
Enabled Breakpoint 3 @ machine.h:7
   35   static constexpr SizeType InitialStackPointer(SizeType base, SizeType size) {
   36     // Stacks grow down on most machines.
 ◉ 37     return (base + size) & -kStackAlignment<SizeType>;
   38   }
   39 };

设置和获取断点属性

您还可以使用 getset 命令修改断点属性。

例如,如需从断点 4 检索 location 属性,请执行以下操作:

breakpoint 4 get location
location (locations)

  The location (symbol, line number, address, or expression) where this
  breakpoint will be set. See "help break" for documentation on how to specify.

location = machine.h:7

例如,如需将断点 4location 属性设置为 machine.h:8,请执行以下操作:

breakpoint 4 set location = machine.h:8
Set breakpoint 4 location = machine.h:8

条件断点

您还可以将断点配置为具有条件。条件是计算结果为 truefalse 的表达式。设置条件后,除非此条件为 true,否则断点不会触发停止。

例如,如果您要调试 cobalt.cm 组件,请执行以下操作:

例如,如需添加 main.cc:352 的条件断点位置,请执行以下操作:

  [zxdb] b main.cc:352 if command_line.has_argv0 == false
  Created Breakpoint 1 condition="command_line.has_argv0 == false" @ ../../src/myapp/bin/app/main.cc:352
    351   }
  ◉ 352   inspector.Health().Ok();
    353   loop.Run();
    354   FX_LOGS(INFO) << "Cobalt will now shut down.";

硬件数据断点

在 zxdb 中,硬件断点会作为一种断点而非单独的监视点进行公开。

处理器可设置为在读取或写入特定地址时中断执行。这对于跟踪内存损坏很有用。

当您为 break 命令的 type 属性使用以下任一值时,便可以创建硬件断点。

  • execute
  • write
  • read-write

例如,如需设置类型为 execute 的断点,请使用以下代码:

break --type=execute myfile.rs:123

watch 与使用 break --type=read-write 相同。请参阅 watch 命令

watch 命令

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

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

如果您对栈上的变量执行 watch 操作,并且没有人再触碰它,那么当栈内存被重复使用时,您通常会在程序的其他部分看到该变量。如果您遇到意外的断点命中,请检查执行是否仍在预期的帧中。

程序化断点

在某些情况下,您可能需要捕获代码中的特定条件。为此,您可以在代码中插入硬编码断点。

Clang 具有以下内置功能:

__builtin_debugtrap();

如果 zxdb 已附加到进程,则会像遇到常规断点一样停止。然后,您可以在此处执行 stepcontinue。如果调试程序尚未附加,这将导致崩溃。