1. 症状
Qt Creator 中的调试会话以随机方式意外终止(即,有时它们正常终止),并出现以下错误之一:
- PC 寄存器不可用(最常见的错误,通常为“Internal error: pc 0×0 in read in psymtab, but not in symtab”)
- SIGSEV
- 西吉尔
这将发生的第一个迹象是,当我踩到我的代码行时,我会进入一个汇编器窗口,进入 NTDLL(通常是ntdll!LdrFindResource_U+60953
)。
我正在使用 QT Creator 的 MinGW(32 位)在 Win7 64 上运行 Qt Creator 2.6.2 和 Qt 5.0.1。我已经在另一台具有 Win732 位的机器上进行了测试,并且行为是相同的。
根据我在 Qt 论坛上收到的回复,Rebuild 或 Clean + Build 对此问题没有任何明显影响。
2. 先分析
由于第一个错误是最常见的,所以我在网上搜索它,这导致了我这个. 它似乎是正确的——肯定有一个 SIGTRAP 导致了那个错误。
但是,当我仔细检查了所有保存的调试器日志时,我发现有几次没有发生该错误(尽管 SIGTRAP 始终存在)。
3.图案
借助 WinMerge 和一些耐心,我终于能够在所有错误情况下感知到一个模式。所有日志(错误和成功)都有这样的内容:
>=thread-created,id="2",group-id="i1"
sThread 2 created
除了我的应用程序(在线程 id=“1”上运行)之外,它还创建了第二个线程。但是,所有成功日志都有这样的内容:
>=thread-exited,id="2",group-id="i1"
sThread 2 in group i1 exited
因此,我又运行了几个调试会话,并在遇到第一个断点时检查了正在运行的线程。在所有错误情况下,我都得到了这样的结果:
<455info threads
>&"info threads\n"
>~" Id Target Id Frame \n"
>~" 2 Thread 7160.0x33ec 0x76f1fd71 in ntdll!RtlFindSetBits () from C:\\Windows\\system32\\ntdll.dll\n"
>~"* 1 Thread 7160.0x128c main (argc=1, argv=0xbb30d8) at ..\\Exeample\\main.cpp:10\n"
>455^done
使用 Process Explorer,我可以看到第二个线程已附加到我的可执行文件(即使我没有创建线程,您也可以在此处查看使用的代码)。
此外,所有错误案例在第二个线程上都有一个 SIGTRAP:
>~"[Switching to Thread 7160.0x33ec]\n"
>*stopped,reason="signal-received",signal-name="SIGTRAP",signal-meaning="Trace/breakpoint trap",frame={addr="0x76f1000d",func="ntdll!LdrFindResource_U",args=[],from="C:\\\\Windows\\\\system32\\\\ntdll.dll"},thread-id="2",stopped-threads="all"
dNOTE: INFERIOR SPONTANEOUS STOP
4. 仔细检查 GDB
为了确定这是否是 GDB 问题,我运行了几个命令行调试会话,包括和不使用“-i mi”。从来没有对第二个线程的任何引用,而且我从来没有遇到过调试会话意外终止,这就是为什么我相信这个问题的原因可能出在 Qt Creator 中。
5.请求帮助
我已经下载了 Qt Creator 的源代码,并在那里寻找了线索,但我并没有走得太远。
gdbengine.cpp 提到了一个“停止线程”,但我发现唯一提到的是这里。
有人对我接下来应该检查的内容有任何想法/指示吗?
谢谢你的时间。
编辑:
我还没有找到原因,但是在用进程监视器查看之后,我得到了更多的数据。
创建第二个线程以加载我的应用程序的可执行文件及其所需的 DLL。我已经确认只有当我从 Qt Creator IDE 调试我的应用程序时才会创建第二个线程;如果我从 IDE 运行它(即,使用“run”而不是“debug”),或者如果我从命令行调试它(从命令行启动 gdb),或者如果我从命令行运行它,这个永远不会创建第二个线程,并且可执行文件 + DLL 图像由我的应用程序的主(也是唯一的)线程加载。
在我上面所说的“成功案例”中,即当第二个线程退出时,它会在加载最后一个 DLL 后立即退出,这就是为什么我相信第二个线程只是为了这个加载而创建的。