GDB 不会立即中断程序

MrD*_*MrD 5 c linux gdb signals i386

在调试大型 C 应用程序时,我看到以下奇怪的行为gdb: 我总是可以按 中断程序Ctrl+C

^C
Program received signal SIGINT, Interrupt.
0x76f58964 in select () at ../sysdeps/unix/syscall-template.S:81
81      in ../sysdeps/unix/syscall-template.S
(gdb)
Run Code Online (Sandbox Code Playgroud)

但是,在程序运行足够长的时间后(例如 > 1 天),我再也不能轻易中断程序了。当试图用 中断程序时Ctrl+Cgdb只显示

^C
Program received signal SIGINT, Interrupt.
Run Code Online (Sandbox Code Playgroud)

并挂在那里几分钟到几个小时。如果花费的时间超过几分钟,我通常会打开另一个终端并gdb手动终止才能继续。

问题:这是预期的行为gdb吗?我可以设置一个选项来避免这种情况吗?

更多细节:

  • 该应用程序是FTLhttps://github.com/pi-hole/FTL
  • 它是多线程使用 pthreads
  • 在点击 后的等待时间内Ctrl+CgdbCPU 处于 100%。

编辑:更多细节

perf record -p $(pidof gdb)gdb被冻住的时候跑了大约 10 秒钟。perf report返回:

90,82%  gdb      gdb                [.] find_thread_ptid                                                                                                   
 9,13%  gdb      gdb                [.] ptid_equal                                                                                                         
 0,02%  gdb      gdb                [.] iterate_over_threads                                                                                               
 0,01%  gdb      [kernel.kallsyms]  [k] run_timer_softirq                                                                                                  
 0,01%  gdb      gdb                [.] 0x0016a9a4                                                                                                         
 0,00%  gdb      gdb                [.] 0x0015a480                                                                                                         
 0,00%  gdb      gdb                [.] 0x0016a998                                                                                                         
 0,00%  gdb      gdb                [.] is_exited
Run Code Online (Sandbox Code Playgroud)

几分钟后,gdb完成并运行info threads它仍然只显示三个线程(和以前一样):

(gdb) info threads
  Id   Target Id         Frame 
  3    Thread 0x764b8460 (LWP 10114) "socket listener" 0x76f60260 in accept () at ../sysdeps/unix/syscall-template.S:81
  2    Thread 0x76cb8460 (LWP 10113) "loganalyzer" 0x76f58964 in select () at ../sysdeps/unix/syscall-template.S:81
* 1    Thread 0x76e65000 (LWP 10098) "pihole-FTL" 0x76f58964 in select () at ../sysdeps/unix/syscall-template.S:81
Run Code Online (Sandbox Code Playgroud)

Emp*_*ian 0

gdb 只是显示...并挂在那里几分钟到几个小时。

猜测:您的程序创建了线程,但没有正确加入和终止线程。

您可以通过运行程序几个小时、用 中断它并Control-C发出info threads命令来确认或反驳这一点。

在 Linux 上,线程只是碰巧共享虚拟内存和文件描述符(以及控制终端)的进程。当您点击时Control-C,只有一个线程接收到SIGINT

在默认all-stop模式下,GDB 会(由内核)收到一个线程有待处理的SIGINT. 然后,GDB 需要停止进程的所有其他线程,这可能会花费相当长的时间。

不仅如此,GDB 可能必须重复此操作几次:当线程运行时,它们可能创建了新线程,现在也必须停止这些线程。