在 windbg 中进行内核调试时无法获得完整的用户模式堆栈跟踪

Unable to get full user-mode stacktrace while kernel debugging in windbg

我在 Windows 10 主机上有一个虚拟 Windows 7 x64 机器,我用 windbg 10.0.10586.567 对它进行内核调试。我是 运行 我自己的应用程序,我有完整的源代码和私有符号。每当我中断并请求应用程序线程的堆栈跟踪时,当我的应用程序的一个二进制文件是 "hit."

时,回溯总是停止

因此,例如,如果我闯入,切换到进程,并使用 !thread [thread address] 1f 请求堆栈跟踪,我会得到类似这样的结果(注意 "early" 零 return 地址在最后一行):

fffff880`0534e870 fffff800`026d6992 nt!KiSwapContext+0x7a
fffff880`0534e9b0 fffff800`026d81a2 nt!KiCommitThreadWait+0x1d2
fffff880`0534ea40 fffff800`029c7a2e nt!KeDelayExecutionThread+0x186
fffff880`0534eab0 fffff800`026d08d3 nt!NtDelayExecution+0x59
fffff880`0534eae0 00000000`76e7165a nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ fffff880`0534eae0)
00000000`00276708 000007fe`fcf91203 ntdll!NtDelayExecution+0xa
00000000`00276710 00000001`410e7dd9 KERNELBASE!SleepEx+0xab
00000000`002767b0 00000000`00000000 MyApp!MainMessageLoop+0x4b1 [d:\whatever\path\myapplication.cpp @ 3024]

这看起来与您在调试 x64 进程的用户模式转储(缺少展开数据)时丢失二进制文件非常相似,除了在这种情况下堆栈跟踪通常不会停止 "this sudden",而是它在那个时候误入歧途,并显示虚假值。

一些额外的 info/things 我试过了:

有什么想法吗?

这不是问题的完美解决方案(或者有人可能会说根本不是任何解决方案),但我提供了这个临时答案和解决方法。

你应该能够得到你想要的信息,尽管使用 dps @rsp L10.

这样的格式不是很好

在 x86-64 中,您没有 x86 ebp 链的并行,但 return 地址仍在堆栈上。这些将为您提供堆栈中的函数,它们之间的值将是传递给函数的参数(以及堆栈中保存的寄存器等)。 A random example from Google(因为我现在不在我的 Windows 机器上):

0:017> dps @rsp
00000000`1bb0fbb8  00000000`00000020
00000000`1bb0fbc0  00000000`00000000
00000000`1bb0fbc8  00000000`008bc6c6 Dolphin!ReadDataFromFifoOnCPU+0xb6 [d:\sources\comex\source\core\videocommon\fifo.cpp @ 245]
00000000`1bb0fbd0  00000000`1ba0ffeb
00000000`1bb0fbd8  00000000`00000020
00000000`1bb0fbe0  00000000`00000020
00000000`1bb0fbe8  00000000`00000800
00000000`1bb0fbf0  00000000`1ba0ffeb
00000000`1bb0fbf8  00000000`008c2ff5 Dolphin!InterpretDisplayListPreprocess+0x45 [d:\sources\comex\source\core\videocommon\opcodedecoding.cpp @ 87]
00000000`1bb0fc00  00000000`00000000
00000000`1bb0fc08  00000000`008bc041 Dolphin!RunGpu+0x81 [d:\sources\comex\source\core\videocommon\fifo.cpp @ 389]
00000000`1bb0fc10  00000000`8064cbc0
00000000`1bb0fc18  00000000`1bb0fcc0
00000000`1bb0fc20  00000000`00000000
00000000`1bb0fc28  00000000`008c2dda Dolphin!OpcodeDecoder_Preprocess+0x14a [d:\sources\comex\source\core\videocommon\opcodedecoding.cpp @ 326]
00000000`1bb0fc30  00000000`8064cbe0

鉴于您有符号,return 地址很容易区分。

展开数据是为用户模式模块延迟加载的,因此除非有人需要,否则不会被映射。不幸的是,内核调试器不会强制为用户图像显示信息,因此有时您会遇到这种情况。您可以通过转储 PE header (!dh) 并检查异常目录 (!pte imagename+offset) 的状态来查看数据是否已映射。

假设您拥有该应用程序,请尝试通过在您的应用程序中的某处执行堆栈遍历 NOP 来强制驻留信息:

PVOID stack[2];
(VOID)CaptureStackBackTrace(0, 2, (PVOID*)&stack, NULL);

这并不能保证整个目录都存在,但通常已经足够了。

我不小心发现了一个解决这个问题的 linker 开关:/DEBUGTYPEPDATA 参数。如果您 link 使用此开关的二进制文件,展开信息将被复制到您的 PDB 中。

我recompiled/relinked有问题的应用程序带有/DEBUGTYPE:CV,PDATA(如果指定/DEBUG/DEBUGTYPE:CV是默认值,请参阅documentation),现在一切工作起来很有魅力,我总是得到完整的调用堆栈。

其中一个奇怪的方面:windbg 愉快地使用在 PDB 中找到的展开数据,但忽略了映射二进制文件中的相同数据(都在主机上)。