前面章节中,我们已经接触了很多调试命令,如 run(r)、continue(c)、next(n)等,借助它们即可操控 GDB 调试目标程序。有些读者可能已经注意到,这些调试命令在执行过程中,是无法使用其它 GDB 调试命令的,换句话说,只有当一个调试命令执行结束后,(gdb) 命令提示符才会出现,我们才能执行下一个调试命令。
事实上,对于某些调试命令,GDB 调试器提供有 2 种执行方式:
- 同步执行:“一个一个”的执行,即必须等待前一个命令执行完毕,才能执行下一个调试命令。
- 后台执行:又称“异步执行”,即当某个调试命令开始执行时,(gdb) 命令提示符会立即出现,我们无需等待前一个命令执行完毕就可以继续执行下一个调试命令。
以后台(异步)的方式执行一个调试命令,其语法格式如下:
(gdb) command&
其中,command 表示就是要执行的调试命令。command 和 & 之间不需要添加空格。
显然,通过在目标命令的后面添加一个 '&' 字符,即可使该命令以后台的方式执行。例如,continue 命令的异步执行版本为continue& 或者c&。
表 1 罗列了支持后台执行的一些常用的调试命令。
表 1 GDB支持后台执行的调试命令
调试命令 |
含 义 |
run(r) |
启动被调试的程序。有关此命令的具体用法,读者可阅读《GDB run 命令》一节。 |
attach |
调试处于运行着的的程序。 |
step |
单步调试程序。有关此命令的具体用法,可阅读《GDB单步调试程序》一节。 |
stepi |
执行一条机器指令。 |
next(n) |
单步调试程序。有关此命令的具体用法,可阅读《GDB单步调试程序》一节。 |
nexti |
执行一条机器指令,其与 stepi 命令的区别,类似于 step 和 next 命令的区别。 |
continue |
继续执行程序。 |
finish |
结束当前正在执行的函数。有关此命令的用法,可阅读《GDB断点调试》一节。 |
until(u) |
快速执行完当前的循环体。有关此命令的用法,可阅读《GDB单步调试程序》一节。 |
注意,并非所有的调试命令都支持异步执行。如果目标调试命令不支持后台执行的形式,当我们尝试使用“命令名+&”的方式执行该命令时,GDB 调试器会提示类似“Function "&" not defined.”的错误信息。
后台执行命令异步调试程序的方法,多用于 non-stop 模式中。虽然 all-stop 模式中也可以使用,但在前一个异步命令未执行完毕前,仍旧不能执行其它命令。
GDB interrupt命令:暂停后台线程执行
对于在后台处于执行状态的线程,可以使用 interrupt 命令将其中断。以调试《GDB non-stop模式》一节给出的多线程程序为例:
(gdb) l
1 #include <stdio.h>
2 #include <pthread.h>
3
4 static void *thread1_job()
5 {
6 printf("this is 1\n");
7 }
8 static void *thread2_job()
9 {
10 printf("this is 2\n");
(gdb)
11 }
12
13 int main()
14 {
15 pthread_t tid1,tid2;
16 pthread_create(&tid1, NULL, thread1_job, NULL);
17 pthread_create(&tid2, NULL, thread2_job, NULL);
18 pthread_join(tid1,NULL);
19 pthread_join(tid2,NULL);
20 printf("this is main\n");
(gdb)
21 return 0;
22 }
(gdb) b 6
Breakpoint 1 at 0x11b1: file main.c, line 6.
(gdb) set non-stop on <-- 以 non-stop 模式调试程序
(gdb) r
Starting program: ~/demo/main.exe
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff7d9f700 (LWP 57816)]
[New Thread 0x7ffff759e700 (LWP 57817)]
this is 2
Thread 2 "main.exe" hit Breakpoint 1, thread1_job () at main.c:6
6 printf("this is 1\n");
(gdb) [Thread 0x7ffff759e700 (LWP 57817) exited]
(gdb) info threads
Id Target Id Frame
* 1 Thread 0x7ffff7da0740 (LWP 57812) "main.exe" (running)
2 Thread 0x7ffff7d9f700 (LWP 57816) "main.exe" thread1_job () at main.c:6
(gdb)
可以看到,当以 non-stop 模式调试程序时,由于我们仅在第 6 行代码处打上了断点,因此启动程序中,仅存在 2 个线程(1 个线程执行完毕后结束了),并且 1 号线程是一直在后台执行着的。
借助 interrupt 命令,我们可以将 1 号线程暂停执行:
(gdb) interrupt
(gdb)
Thread 1 "main.exe" stopped.
......
(gdb) info threads
Id Target Id Frame
* 1 Thread 0x7ffff7da0740 (LWP 57812) "main.exe" ......at pthread_join_common.c:145
2 Thread 0x7ffff7d9f700 (LWP 57816) "main.exe" hread1_job () at main.c:6
(gdb)
可以看到,1 号线程停止了运行。
注意,在 all-stop 模式下,interrupt 命令作用于所有线程,即该命令可以令整个程序暂停执行;而在 non-stop 模式下,interrupt 命令仅作用于当前线程。 如果想另其作用于所有线程,可以执行 interrupt -a 命令。