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”表示堆栈的顶部进行编号。数字增加会使时间倒回。
您可以使用 up
和 down
命令在帧列表中导航:
[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