前面章节中,我们已经接触了很多调试命令,如 runr)、continuec)、nextn)等,借助它们即可操控 GDB 调试目标程序。有些读者可能已经注意到,这些调试命令在执行过程中,是无法使用其它 GDB 调试命令的,换句话说,只有当一个调试命令执行结束后,(gdb) 命令提示符才会出现,我们才能执行下一个调试命令。

事实上,对于某些调试命令,GDB 调试器提供有 2 种执行方式:

  • 同步执行:“一个一个”的执行,即必须等待前一个命令执行完毕,才能执行下一个调试命令。
  • 后台执行:又称“异步执行”,即当某个调试命令开始执行时,(gdb) 命令提示符会立即出现,我们无需等待前一个命令执行完毕就可以继续执行下一个调试命令。

以后台(异步)的方式执行一个调试命令,其语法格式如下:

  1. (gdb) command&

其中,command 表示就是要执行的调试命令。command 和 & 之间不需要添加空格。

显然,通过在目标命令的后面添加一个 & 字符,即可使该命令以后台的方式执行。例如,continue 命令的异步执行版本为 continue& 或者 c&

下表罗列了支持后台执行的一些常用的调试命令。

调试命令 含 义
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模式》一节给出的多线程程序为例:

  1. (gdb) l
  2. 1 #include <stdio.h>
  3. 2 #include <pthread.h>
  4. 3
  5. 4 static void *thread1_job()
  6. 5 {
  7. 6 printf("this is 1\n");
  8. 7 }
  9. 8 static void *thread2_job()
  10. 9 {
  11. 10 printf("this is 2\n");
  12. (gdb)
  13. 11 }
  14. 12
  15. 13 int main()
  16. 14 {
  17. 15 pthread_t tid1,tid2;
  18. 16 pthread_create(&tid1, NULL, thread1_job, NULL);
  19. 17 pthread_create(&tid2, NULL, thread2_job, NULL);
  20. 18 pthread_join(tid1,NULL);
  21. 19 pthread_join(tid2,NULL);
  22. 20 printf("this is main\n");
  23. (gdb)
  24. 21 return 0;
  25. 22 }
  26. (gdb) b 6
  27. Breakpoint 1 at 0x11b1: file main.c, line 6.
  28. (gdb) set non-stop on <-- non-stop 模式调试程序
  29. (gdb) r
  30. Starting program: ~/demo/main.exe
  31. [Thread debugging using libthread_db enabled]
  32. Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
  33. [New Thread 0x7ffff7d9f700 (LWP 57816)]
  34. [New Thread 0x7ffff759e700 (LWP 57817)]
  35. this is 2
  36. Thread 2 "main.exe" hit Breakpoint 1, thread1_job () at main.c:6
  37. 6 printf("this is 1\n");
  38. (gdb) [Thread 0x7ffff759e700 (LWP 57817) exited]
  39. (gdb) info threads
  40. Id Target Id Frame
  41. * 1 Thread 0x7ffff7da0740 (LWP 57812) "main.exe" (running)
  42. 2 Thread 0x7ffff7d9f700 (LWP 57816) "main.exe" thread1_job () at main.c:6
  43. (gdb)

可以看到,当以 non-stop 模式调试程序时,由于我们仅在第 6 行代码处打上了断点,因此启动程序中,仅存在 2 个线程(1 个线程执行完毕后结束了),并且 1 号线程是一直在后台执行着的。

借助 interrupt 命令,我们可以将 1 号线程暂停执行:

  1. (gdb) interrupt
  2. (gdb)
  3. Thread 1 "main.exe" stopped.
  4. ......
  5. (gdb) info threads
  6. Id Target Id Frame
  7. * 1 Thread 0x7ffff7da0740 (LWP 57812) "main.exe" ......at pthread_join_common.c:145
  8. 2 Thread 0x7ffff7d9f700 (LWP 57816) "main.exe" hread1_job () at main.c:6
  9. (gdb)

可以看到,1 号线程停止了运行。

注意,在 all-stop 模式下,interrupt 命令作用于所有线程,即该命令可以令整个程序暂停执行;而在 non-stop 模式下,interrupt 命令仅作用于当前线程。 如果想另其作用于所有线程,可以执行 interrupt -a 命令。