使用 zxdb 时,您可以控制线程的执行,以帮助您进行调试。 在调试时,您可以通过以下方式控制执行:
线程
线程是进程中的执行单元。它表示可以独立执行的单个指令序列。
如需了解如何在 zxdb 中通过线程控制执行,请参阅 线程。
堆栈帧
堆栈帧是调用函数时分配的调用堆栈的一部分。它存储函数执行所需的信息,例如:
- 局部变量:在函数内声明的变量。
- 参数:传递给函数的值。
- 返回地址:函数完成后要返回的代码中的位置。
如需了解如何在 zxdb 中通过堆栈帧控制执行,请参阅 堆栈帧。
线程
在 zxdb 中,一个 thread 是一个 名词,您可以将其与 zxdb
动词一起使用。
如需列出当前进程中的线程,请执行以下操作:
thread
# State Koid Name
▶ 1 Blocked 1323 initial-thread
2 Running 3462 worker-thread
在某些情况下,您可能会注意到某个线程被标记为 Blocked,这意味着该线程在系统调用中停止。通常,当您调试异步应用时,这可能也表示等待时间。
线程控制命令仅适用于已暂停的线程,而不适用于已阻塞或正在运行的线程。您可以通过多种方式暂停线程:
pause 线程
例如,如需使用 pause 命令暂停线程 2,请执行以下操作:
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
当线程暂停时,zxdb 会显示当前源代码位置。如果线程处于系统调用中(如上例所示),则源代码位置会解析为生成系统调用的汇编语言宏文件中的位置。
如果您在没有任何其他上下文的情况下运行 pause,则 zxdb 会暂停当前连接的所有进程的所有线程。
例如:
pause
508 const zx_port_packet_t* packet))
509
▶ 510 BLOCKING_SYSCALL(port_wait, zx_status_t, /* no attributes */, 3, (handle, deadline, packet),
511 (_ZX_SYSCALL_ANNO(use_handle("Fuchsia")) zx_handle_t handle, zx_time_t deadline,
512 zx_port_packet_t* packet))
🛑 $elf(SYSCALL_zx_port_wait) + 0x7 • syscalls.inc:510
continue 线程
暂停线程并开始调试问题后,您可能需要 continue 线程。继续是指恢复执行,直到程序正常完成。
例如,如需 continue 线程 1,请执行以下操作:
thread 1 continue
如果您在没有任何其他上下文的情况下运行 continue,则 zxdb 会继续所有已连接进程的所有线程。
例如:
continue
单步执行线程
当线程暂停时,您可以控制其执行。您可以使用以下任何命令:
finish(fi)退出函数并在调用后立即停止。
finishnext(n)前进到下一行,跳过函数调用。
nextnexti前进到下一条指令,但跳过目标架构的调用指令。
nextiss列出当前行的函数调用,并进入所选调用。这会自动完成任何首先发生的其他调用。
ss 1 std::string::string 2 MyClass::MyClass 3 HelperFunctionCall 4 MyClass::~MyClass 5 std::string::~string quit >step(s)前进到下一行代码。如果函数调用发生在下一行之前,则会进入该函数,并且执行会在该函数的开头停止。
您还可以提供实参子字符串来匹配特定的函数调用。 系统会跳过不包含实参子字符串的函数名称,并且 只会进入匹配的函数。
step [zxdb] step MyFunctionstepi准确前进一条机器指令。
stepiuntil(u)给定行位置后,继续执行线程,直到执行到达该位置。例如,如需运行到当前文件的第
45行,请执行以下操作:until 45您还可以运行到执行返回到给定堆栈帧:
frame 2 until
堆栈帧
堆栈帧是函数调用。当一个函数调用另一个函数时,系统会创建一个新帧。列出线程的帧会返回调用堆栈。
如需列出当前线程中的堆栈帧,请执行以下操作:
frame
▶ 0 fxl::CommandLineFromIterators<const char *const *>() • command_line.h:203
1 fxl::CommandLineFromArgcArgv() • command_line.h:224
2 main() • main.cc:174
使用堆栈帧时,0 表示堆栈的顶部,表示执行结束。堆栈的底部(即最高的堆栈帧编号)表示执行开始。
浏览堆栈帧
您可以使用 up 和 down 命令浏览帧列表。
例如,使用 up 从当前帧 0 浏览到帧 1:
up
1 fxl::CommandLineFromIterators<const char *const *>() • command_line.h:204
例如,使用 down 从当前帧 1 浏览到帧 0:
[zxdb] down
0 fxl::CommandLineFromIteratorsFindFirstPositionalArg<const char *const *>() • command_line.h:185
您还可以使用带有帧编号的 frame 命令浏览到特定帧:
frame 1
使用 backtrace 获取更多详细信息
在某些情况下,您可能需要查看堆栈帧未提供的其他地址信息。backtrace 命令与 frame 相同,但会提供更详细的地址信息以及函数参数。
如需列出当前线程中的堆栈帧,但包含更多详细信息,请使用 backtrace:
backtrace
▶ 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 查看源代码
每个堆栈帧都有一个代码位置。使用 list 命令查看源代码。
您可以列出特定堆栈帧的指令指针周围的代码。
例如,如需 list 堆栈帧 3 的指令指针周围的源代码,请执行以下操作:
frame 3 list
当您在没有上下文的情况下使用 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;
list 的其他用例
此外,您还可以使用 list 列出特定内容:
函数
使用 list 列出函数:
list MyClass::MyFunc
文件
使用 list 列出特定文件:
list --all myfile.cc:1
带行号的文件
使用 list 列出具有特定行号的特定文件:
list foo.cc:43