拿到一个dump文件后,经过简单分析,是设备驱动在处理电源IRP时,超时未完成导致的。这是一个典型的0x9F BSOD错误:
DRIVER_POWER_STATE_FAILURE (9f) A driver has failed to complete a power IRP within a specific time (usually 10 minutes). Arguments: Arg1: 0000000000000003, A device object has been blocking an Irp for too long a time Arg2: fffffa800182aa90, Physical Device Object of the stack Arg3: fffff800139e9930, nt!TRIAGE_9F_POWER on Win7, otherwise the Functional Device Object of the stack Arg4: fffffa8002437e10, The blocked IRP
自动分析的内容告诉我:在处理地址为fffffa8002437e10的电源IRP(IRP_MJ_POWER)时,超时(一般10分钟)未能完成,所以引发了系统0x9F蓝屏。自动分析同时列出了当前线程(处理此IRP的线程)调用栈:
Child-SP RetAddr Call Site
fffff880`181ab5e0 fffff800`169137cb nt!KiSwapContext(void)+0x76
(Inline Function) --------`-------- nt!KiSwapThread+0xfa
fffff880`181ab720 fffff800`1691260f nt!KiCommitThreadWait+0x23b
fffff880`181ab7e0 fffff800`16977acd nt!KeWaitForSingleObject+0x1cf
fffff880`181ab870 fffff800`16920255 nt!ExpAcquireFastMutexContended+0x3d
(Inline Function) --------`-------- nt!ExAcquireFastMutex+0x38
fffff880`181ab8b0 fffff880`046208b6 nt!KeAcquireGuardedMutex(struct _FAST_MUTEX * Mutex = 0xfffffa80`044e81e0)+0x45
// 中间省略ModuleA的调用
fffff880`181abca0 fffff800`168a2fd9 nt!PopIrpWorker(void * Context = )+0x284
fffff880`181abd50 fffff800`169577e6 nt!PspSystemThreadStartup
fffff880`181abda0 00000000`00000000 nt!KxStartSystemThread(void)+0x16
从调用栈能够看到,线程因为在等待一个同步对象,而进入了休眠状态。从字面上看,这是一个FAST_MUTEX对象。如果能够得到这个对象的地址,就太好了。我试图加载NT模块的私有符号,很幸运成功了。切换到函数KeAcquireGuardedMutex的调用帧后,得到了同步对象的有效信息:
0: kd> dt _fast_mutex 0xfffffa80`044e81e0 nt!_FAST_MUTEX +0x000 Count : 0n4 +0x008 Owner : 0xfffffa80`02c8d7c0 Void +0x010 Contention : 8 +0x018 Event : _KEVENT +0x030 OldIrql : 0
调试最担心的问题就是地址无效,比较有效的方法是通过关键值的比对,判断地址的有效性。这里我感兴趣的是Owner变量,是这个FAST_MUTEX对象的拥有者线程。如果地址正确的话,我就能够得到一个线程调用栈。切过去看看:
0: kd> !thread 0xfffffa80`02c8d7c0 //省略summary nt!KiSwapContext+0x76 nt!KiSwapThread+0xfa (Inline Function @ fffff800`169137cb) nt!KiCommitThreadWait+0x23b nt!KeWaitForSingleObject+0x1cf nt!MiWaitForInPageComplete+0xb8 nt!MiIssueHardFault+0x1b7 nt!MmAccessFault+0x81f nt!KiPageFault+0x16e (TrapFrame @ fffff880`03b3a810) //中间省略ModuleA的调用 nt!PspSystemThreadStartup+0x59 nt!KxStartSystemThread+0x16
地址是有效的,并且得到的调用栈中也有一堆ModuleA的函数。问题到此可告一段落了:
这个问题到目前为止,可判定是一个死锁问题。只要线程2能够及时释放它所拥有的FAST_MUTEX对象就可以了。但更深层的原因则是线程2竟然因为一个页错误而陷入长时间的等待,得不到解决。由于这个中间的模块是一个保密模块,本人无权限分析。所以到这里为止我的任务就结束了,接下来要让ModuleA模块的部门做进一步分析。