Advanced Debugging
About AdvDbg Consult Train Services Products Tools Community Contact  
欢迎光临 高端调试 登录 | 注册 | FAQ
 
  ACPI调试
Linux内核调试
Windows内核调试
 
  调试战役
调试原理
新工具观察
 
  Linux
Windows Vista
Windows
 
  Linux驱动
WDF
WDM
 
  PCI Express
PCI/PCI-X
USB
无线通信协议
 
  64位CPU
ARM
IA-32
  CPU Info Center
 
  ACPI标准
系统认证
Desktop
服务器
 
  Embedded Linux
嵌入式开发工具
VxWorks
WinCE
嵌入式Windows
 
  格蠹调试套件(GDK)
  格蠹学院
  小朱书店
  老雷的微博
  《软件调试》
  《格蠹汇编》
  《软件调试(第二版)》
沪ICP备11027180号-1

Windows内核调试

帖子发起人: zyq8709   发起时间: 2011-06-21 09:18 上午   回复: 13

Print Search
帖子排序:    
   2011-06-21, 09:18 上午
zyq8709 离线,最后访问时间: 2019/8/6 21:05:02 zyq8709

发帖数前10位
注册: 2011-04-19
发 贴: 74
Confused [*-)] Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?请张老师给予指点,多谢!已经迷茫了,求解答!
Reply Quote
我看到有些地方说在dispatch级上调用等待函数,会导致当前线程挂起并会引起线程切换,由于在dispatch级,所以无法切换线程,所以会导致死锁并崩溃。
请看一些代码:
KEVENT e;
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
unsigned i;
for (i = 0; i MajorFunction<img src="/emoticons/emotion-55.gif" alt="Idea [I]" /> = qqDefaultHandler;
DriverObject->MajorFunction[IRP_MJ_CREATE] = qqCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = qqCreateClose;
DriverObject->MajorFunction[IRP_MJ_PNP] = qqPnP;

DriverObject->DriverUnload = qqUnload;
DriverObject->DriverStartIo = NULL;
DriverObject->DriverExtension->AddDevice = qqAddDevice;

return STATUS_SUCCESS;
}

void qqUnload(IN PDRIVER_OBJECT DriverObject)
{
KeSetEvent(&e,IO_NO_INCREMENT,FALSE);
}
void f()
{
KIRQL o;
_asm int 3
KeRaiseIrql(DISPATCH_LEVEL,&o);

KeInitializeEvent(&e,NotificationEvent,FALSE);
_asm int 3
KeWaitForSingleObject(&e,Executive,KernelMode,FALSE,0);
_asm int 3
_asm int 3
PsTerminateSystemThread(STATUS_SUCCESS);
}
NTSTATUS qqAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject)
{
PDEVICE_OBJECT DeviceObject = NULL;
Pqq_DEVICE_EXTENSION pExtension = NULL;
NTSTATUS status;
HANDLE h;
status = IoCreateDevice(DriverObject,
sizeof(qq_DEVICE_EXTENSION),
NULL,
FILE_DEVICE_UNKNOWN,
0,
0,
&DeviceObject);

if (!NT_SUCCESS(status))
return status;

pExtension = (Pqq_DEVICE_EXTENSION)DeviceObject->DeviceExtension;

pExtension->DeviceObject = DeviceObject;
pExtension->PhysicalDeviceObject = PhysicalDeviceObject;
pExtension->TargetDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject);

status = IoRegisterDeviceInterface(PhysicalDeviceObject, &GUID_qqInterface, NULL, &pExtension->DeviceInterface);
ASSERT(NT_SUCCESS(status));

DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
_asm int 3
PsCreateSystemThread(&h,0,NULL,NtCurrentProcess(),0,(PKSTART_ROUTINE)f,0);
return STATUS_SUCCESS;
}
在AddDevice例程中创建一个线程f,然后提升其IRQL为dispatch级,并等待事件,并在Unload例程中设置事件。可有些奇怪的是在f中等待事件并未导致崩溃死锁,而系统运转一切正常,f线程也正常挂起,其余在系统中想做什么都可以,并未受到阻碍。反而是在Unload例程执行并设置事件之后,f线程并未得到执行,反而引起了蓝屏崩溃。
另:我看到KeWaitForSingleObject内发现调用了KeRaiseIrqlToDpcLevel,而在Dispatch级这是没问题的,然后就在此级别上进行了线程切换,按理在Dispatch级上都没问题,WDK文档却规定等待函数在timeout==null时只能低于dispatch,但是在调试跟踪中dispatch级别也没问题,这不是两者矛盾吗,这到底是怎么回事?在dispatch级上调用等待函数会出现什么问题?
请问到底这是怎么一回事,请帮我解答一下吧,多谢!!!
IP 地址: 已记录   报告
   2011-06-22, 22:03 下午
zyq8709 离线,最后访问时间: 2019/8/6 21:05:02 zyq8709

发帖数前10位
注册: 2011-04-19
发 贴: 74
Re: Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?请张老师给予指点,多谢!
Reply Quote
请张老师给予指点,请再顺便看看另外几个问题吧,多谢了!
IP 地址: 已记录   报告
   2011-06-23, 11:56 上午
WANGyu 离线,最后访问时间: 2012/9/10 3:34:00 王宇

发帖数前10位
男
注册: 2007-05-08
发 贴: 306
Re: Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?请张老师给予指点,多谢!
Reply Quote
稍等
IP 地址: 已记录   报告
   2011-06-23, 12:01 下午
Raymond 离线,最后访问时间: 2020/7/3 3:40:25 格蠹老雷

发帖数前10位
注册: 2005-12-19
发 贴: 1,303
Re: Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?请张老师给予指点,多谢!
Reply Quote
等等王宇,顺便问下,楼主做什么的,学生么?
IP 地址: 已记录   报告
   2011-06-23, 12:08 下午
zyq8709 离线,最后访问时间: 2019/8/6 21:05:02 zyq8709

发帖数前10位
注册: 2011-04-19
发 贴: 74
Re: Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?请张老师给予指点,多谢!
Reply Quote
张老师您好,我是一个毕业生,自学的计算机,现在在复习考研。看了您的书,感觉学到了许多。
IP 地址: 已记录   报告
   2011-06-23, 12:55 下午
Raymond 离线,最后访问时间: 2020/7/3 3:40:25 格蠹老雷

发帖数前10位
注册: 2005-12-19
发 贴: 1,303
Re: Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?请张老师给予指点,多谢!
Reply Quote
思考的很深入,这个问题的确值得深究,根本的问题是NT的scheduler运行在DISPATCH_LEVEL,把蓝屏的dump压缩一下发上来看看
IP 地址: 已记录   报告
   2011-06-23, 13:28 下午
zyq8709 离线,最后访问时间: 2019/8/6 21:05:02 zyq8709

发帖数前10位
注册: 2011-04-19
发 贴: 74
Re: Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?请张老师给予指点,多谢!

附件: 代码及dump.rar
Reply Quote
张老师您好,调试环境是VMware加XP SP2。我理解的的调度器也就是一段运行在Dispatch级上的KiSwapThread例程,无论是KfLowerIrql还是KeWaitForSingleObject都是先提升Irql再调用KiSwapContext导致线程切换,感觉也就是一段简单的函数调用,没有什么特别之处,至于说调度器只是一个形象的说法。请各位老师再看一看我发现的另一个关于KfLowerIrql调用时违例却无错误发生的问题(http://advdbg.org/forums/4961/ShowPost.aspx),应该和这个问题有一定联系。
附件为代码和dump文件。
IP 地址: 已记录   报告
   2011-06-23, 14:10 下午
WANGyu 离线,最后访问时间: 2012/9/10 3:34:00 王宇

发帖数前10位
男
注册: 2007-05-08
发 贴: 306
Re: Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?请张老师给予指点,多谢!
Reply Quote
刚才正要回你的蓝屏问题就被叫去吃饭了,回来看到你的 dump,和我想的一样。你的蓝屏是必然的。

qqUnload 置完事件就 Unload 了整个驱动,此时线程 f 还未得到执行。等线程再被调度,地址已不可用:

STACK_TEXT:
b1f11da4 00000000 b1f11ddc 805c5a28 00000000 [Unloaded_qq.sys]+0x5d9 /*论坛会转义尖括号*/

注意这个 Unloaded_

PS : Debugman 太水了,楼主可以不用去了~
IP 地址: 已记录   报告
   2011-06-23, 14:17 下午
zyq8709 离线,最后访问时间: 2019/8/6 21:05:02 zyq8709

发帖数前10位
注册: 2011-04-19
发 贴: 74
Re: Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?请张老师给予指点,多谢!
Reply Quote
多谢王老师的解答,确实是在执行一个收回的地址,所以出错。
那么如果我不在Unload例程中设置事件,而是在其他派遣函数中设置也就是在没被卸载的驱动中执行,是不是就不会出错了?
那么对于KeWaitForSingleObject对Irql级别的要求又该怎么解释呢?

IP 地址: 已记录   报告
   2011-06-23, 16:32 下午
Raymond 离线,最后访问时间: 2020/7/3 3:40:25 格蠹老雷

发帖数前10位
注册: 2005-12-19
发 贴: 1,303
Re: Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?请张老师给予指点,多谢!
Reply Quote
看了下目前的源代码,改变IRQL的代码有问题:
KeRaiseIrql(DISPATCH_LEVEL,&o);
_asm int 3
KeLowerIrql(o);
_asm int 3
KeLowerIrql(DISPATCH_LEVEL);
后面两次调用是何目的?如DDK所言:
It is a fatal error to call KeLowerIrql using an input NewIrql that was not returned by the immediately preceding call to KeRaiseIrql.
按道理来说,对于单CPU的系统,一旦以个CPU被提升到DISPATCH_LEVEL,那么整个系统的GUI就失去响应了,因为CPU没有机会执行普通线程了
IP 地址: 已记录   报告
   2011-06-23, 17:02 下午
zyq8709 离线,最后访问时间: 2019/8/6 21:05:02 zyq8709

发帖数前10位
注册: 2011-04-19
发 贴: 74
Re: Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?请张老师给予指点,多谢!
Reply Quote
张老师,我这样是有用意的。
第一次降低是正常的,第二次我用一个高于当前的Irql来降低目的是为了观察KfLowerIrql对于这种错误的处理,但是我发现并未出现任何错误,而且当前Irql被改为了Dispatch级,然后在该级别上调用KeWaitForSingleObject来观察错误,同样的是等待函数中每一步都被执行了,而且也正常的进入了KiSwapThread和KiSwapContext,并切换了上下文进入了另一个线程,然后再观察系统,一切如常。如果只是一个CPU核心被阻塞,那么我再加载一次驱动安装一个设备,一切仍然如常。我CPU是双核的,但是加载了两次按理说就算是阻塞,也是两个都被阻塞了,然而系统该怎么操作都没有问题,这十分奇怪,并与公认的说法相违背,请各位老师再费心了!
IP 地址: 已记录   报告
   2011-06-23, 18:02 下午
zyq8709 离线,最后访问时间: 2019/8/6 21:05:02 zyq8709

发帖数前10位
注册: 2011-04-19
发 贴: 74
Re: Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?请张老师给予指点,多谢!

附件: 修改后的代码与截图.rar
Reply Quote
我按照王老师的指导修改了代码,只是将设置事件放到了IRP_MJ_CREATE派遣函数,其他的包括违例的IRQL使用都没改,结果竟然一点问题都没了,难道MS关于IRQL的文档说明有问题,请各位老师关注一下,多谢了!
修改后的代码与运行截图见附件。
IP 地址: 已记录   报告
   2011-06-26, 10:46 上午
Raymond 离线,最后访问时间: 2020/7/3 3:40:25 格蠹老雷

发帖数前10位
注册: 2005-12-19
发 贴: 1,303
Re: Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?请张老师给予指点,多谢!
Reply Quote
看了下新的代码,不是把有问题的两次KeLowerIrql去掉了么?这样的话,CPU应该挂在DISPATCH_LEVEL,不会去执行调度器,也就是没有机会执行普通线程,如果看栈回溯,那么很可能看到如下的场景:

kd> knL
# ChildEBP RetAddr
00 980f9b88 82e96362 nt!KeAccumulateTicks+0x3c5
01 980f9bc8 82e9620f nt!KeUpdateRunTime+0x145
02 980f9c20 82e9b597 nt!KeUpdateSystemTime+0x613
03 980f9c20 82e9244c nt!KeUpdateSystemTimeAssist+0x13
04 980f9d0c 99601907 nt!KeWaitForSingleObject+0x510
05 980f9d50 830396bb RealBug!WaitAtHighIrqlThread+0xd7
06 980f9d90 82eeb0f9 nt!PspSystemThreadStartup+0x9e
07 00000000 00000000 nt!KiThreadStartup+0x19

#0-3表示CPU是在响应时钟中断,此时的IRQL如果为0,那么CPU便可以调度普通线程了,但是现在为2。如果在调试会话中,那么NT可能会发出这样一个调试信息:
Assertion: *** DPC watchdog timeout
This is NOT a break in update time
This is most likely a BUG in an ISR
Perform a stack trace to find the culprit
The period will be doubled on continuation
Use gh to continue!!

DDK中的很多说法是“法规性”的规则,触犯了不一定立刻蓝屏,但是可能导致间接的严重问题,比如系统挂死,在DISPATCH_LEVEL等待就属于这种情况。
在检查版本的NT中,有一个ASSERT来检查当前的IRQL,而free版本的没有这个检查。但是问题是一样的,进入等待后便没有办法唤醒这个线程了...

IP 地址: 已记录   报告
   2011-06-27, 17:42 下午
zyq8709 离线,最后访问时间: 2019/8/6 21:05:02 zyq8709

发帖数前10位
注册: 2011-04-19
发 贴: 74
Re: Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?请张老师给予指点,多谢!
Reply Quote
十分感谢张老师的回答,我刚才看了一下,我把代码发错了,我调试的不是这个版本,而是带有那两个错误调用的。
张老师的回答让我有些清醒了,但是我还有一些疑问:就是KeWaitForSingleObject调用之后会调用KiSwapThread例程来切换线程,为何会引发时钟中断来切换线程?
是不是在时钟中断中还有对Irql级别的判断,超过了2就不会进行线程调度?
多谢张老师了!

IP 地址: 已记录   报告
高端调试 » 软件调试 » Windows内核调试 » Re: Dispatch_level及以上不能调用KeWaitForSingleObject的真正原因是什么?请张老师给予指点,多谢!

 
Legal Notice Privacy Statement Corporate Governance Corporate Governance
(C)2004-2020 ADVDBG.ORG All Rights Reserved.