【问题标题】:GDB not interrupting program immediatelyGDB 不会立即中断程序
【发布时间】:2018-03-12 04:39:51
【问题描述】:

在调试大型 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)

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

^C
Program received signal SIGINT, Interrupt.

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

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

更多细节:

  • 应用程序是FTL (https://github.com/pi-hole/FTL)
  • 它是多线程的,使用pthreads
  • 在点击Ctrl+C 后的等待时间内,gdb 处于 100% CPU。

编辑:更多细节

我在 gdb 被冻结时运行了大约 10 秒 perf record -p $(pidof gdb)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

几分钟后,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

【问题讨论】:

  • 文件signal.c 似乎与它处理SIGINT 信号的方式有些不一致。这可能与观察到的问题有关

标签: c linux gdb signals i386


【解决方案1】:

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

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

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

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

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

不仅如此,GDB 还可能不得不重复多次:在线程运行时,它们可能创建了新线程,现在也必须停止。

【讨论】:

  • 至少有一个线程存在于进程的整个生命周期(监听套接字上的传入连接)。只要进程正在运行,该线程就永远不会终止。我希望gdb 也“只是”停止这个线程(无论它现在在哪里)。有趣的是,这适用于较短的运行时间。根据info threads,即使运行时间很长,也没有更多线程。
  • 如果info threads中没有额外的线程,那么我的猜测是错误的,我不知道GDB在做什么。您可以运行 perf record -p $pid-of-gdb(当 GDB 100% 忙碌时),在 10 秒后中断 perf,然后运行 ​​perf report 并使用输出更新您的问题。该输出应该允许更好的猜测。
  • @MrD 你的perf 输出匹配我的回答:GDB 正在迭代线程。必须有许多 100 或 1000 个。 ls /proc/$(pid-of-target)/task | wc -l 的输出是什么? (注意,这里我们需要下级(被调试)进程的 pid,而不是 GDB 的 pid。)
  • ls /proc/$(pidof pihole-FTL)/task | wc -l 的结果是3
  • @MrD 有趣。您是否从 GDB 收到任何关于 libthread_db 不可用的警告?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-07
  • 1970-01-01
  • 1970-01-01
  • 2021-11-06
  • 2015-03-25
相关资源
最近更新 更多