控制 zxdb 中的线程执行

Threads

如需列出当前进程的线程(请参阅上面的“交互模型”了解详情):

[zxdb] thread
  # State   Koid Name
▶ 1 Blocked 1323 initial-thread
  2 Running 3462 worker-thread

通常,当您附加到进程时,线程会“阻塞”,这意味着它在系统调用时停止。对于异步程序来说,这通常是某种类型的等待。

大多数线程控制和自检命令仅在线程挂起(而非阻塞或运行)时有效。线程在某个断点处停止或崩溃时将被挂起。您可以使用 pause 命令显式挂起线程:

[zxdb] thread 2 pause
🛑 syscalls-x86-64.S:67
   65 m_syscall zx_port_create 60 2 1
   66 m_syscall zx_port_queue 61 2 1
 ▶ 67 m_syscall zx_port_wait 62 3 0
   68 m_syscall zx_port_cancel 63 3 1
   69 m_syscall zx_timer_create 64 3 1

当线程暂停时,调试程序将显示当前源代码位置。通常情况下,线程位于一个系统调用中,该调用将解析为生成系统调用的汇编语言宏文件中的位置,如上例所示。

在没有上下文的情况下单独运行 pause 会暂停当前连接的所有进程的所有线程:

[zxdb] pause

使用 continue 取消暂停线程。与之前一样,没有上下文的 continue 将恢复所有线程:

[zxdb] continue

或继续特定会话:

[zxdb] thread 1 continue

堆栈帧

堆栈帧是一个函数调用。当一个函数调用另一个函数时,系统会创建一个新的嵌套帧。列出线程帧可以告诉您调用堆栈。您只能在线程挂起时看到堆栈帧(请参阅上面的“使用线程”)。

列出当前线程的堆栈帧(f 缩写同样适用)。

[zxdb] frame
▶ 0 fxl::CommandLineFromIterators<const char *const *>() • command_line.h:203
  1 fxl::CommandLineFromArgcArgv() • command_line.h:224
  2 main() • main.cc:174

要选择给定帧作为默认帧,请执行以下操作:

[zxdb] frame 2

帧使用“0”表示堆栈的顶部进行编号。数字增加会使时间倒回。

您可以使用 updown 命令在帧列表中导航:

[zxdb] up
  1 fxl::CommandLineFromIterators<const char *const *>() • command_line.h:204

[zxdb] down
  0 fxl::CommandLineFromIteratorsFindFirstPositionalArg<const char *const *>() • command_line.h:185

如需了解更多背景信息,您可以使用 backtrace 命令。这与 frame 相同,但提供了更详细的地址信息和函数参数。此命令可以缩写为 bt

[zxdb] bt
▶ 0 fxl::CommandLineFromIteratorsFindFirstPositionalArg<const char *const *>() • command_line.h:185
      IP = 0x10f982cf2ad0, BP = 0x66b45a01af50, SP = 0x66b45a01af38
      first = (const char* const*) 0x59f4e1268dc0
      last = (const char* const*) 0x59f4e1268dc8
      first_positional_arg = (const char* const**) 0x0
  1 fxl::CommandLineFromIterators<const char *const *>() • command_line.h:204
      IP = 0x10f982cf2ac0, BP = 0x66b45a01af50, SP = 0x66b45a01af40
      first = <'first' is not available at this address. >
      last = <'last' is not available at this address. >
...

每个堆栈帧都有一个代码位置。使用 list 命令查看源代码。它本身会列出当前堆栈帧的指令指针周围的源代码:

[zxdb] list
   183 inline CommandLine CommandLineFromIteratorsFindFirstPositionalArg(
   184     InputIterator first, InputIterator last,
 ▶ 185     InputIterator* first_positional_arg) {
   186   if (first_positional_arg)
   187     *first_positional_arg = last;

您还可以列出其他堆栈帧的当前指令指针周围的代码:

[zxdb] frame 3 list

或者,您也可以列出特定内容,例如函数:

[zxdb] list MyClass::MyFunc

文件/行号:

[zxdb] list foo.cc:43

或整个文件:

[zxdb] list --all myfile.cc:1

单步调试线程

当线程挂起(请参阅上文的“线程”)时,您可以控制其执行:

next / n:前进到下一行,越过函数调用。

[zxdb] n

step / s:前进到下一行。如果一个函数调用发生在下一行之前,该函数会进入,并会在其开头停止执行。您还可以提供一个参数,该参数是与特定函数调用匹配的子字符串。系统将跳过不包含此子字符串的函数名称,只有匹配的函数会进入:

[zxdb] s
[zxdb] s MyFunction

ss:列出当前行上的函数调用并单步进入选定的调用,自动完成首先发生的所有其他调用。

[zxdb] ss
  1 std::string::string
  2 MyClass::MyClass
  3 HelperFunctionCall
  4 MyClass::~MyClass
  5 std::string::~string
  quit
>

finish / fi:退出函数,并在调用后立即停止。

[zxdb] finish

until / u:在给定位置(与断点相同,见上文)后,线程会继续执行,直到达到该位置。例如,要运行到当前文件的第 45 行,请使用以下命令:

[zxdb] u 45

jump:将指令指针移动到新地址。

[zxdb] jump 22  // Line number
[zxdb] jump 0x87534123  // Address

如需在执行返回到给定堆栈帧之前运行,请使用以下命令:

[zxdb] frame 2 until