为什么不能在64位Windows异常时展开堆栈,如果堆栈越过边界的内核 - 在32位Windows可以吗?
这整个问题的背景来自于:
在消失的OnLoad异常的情况下-在64位用户模式回调异常
背景
在32位Windows,如果我在用户模式下的代码抛出一个异常,这是从内核模式代码打电话回来,这是从我的用户模式代码,例如叫:
User mode Kernel Mode
------------------ -------------------
CreateWindow(...); ------> NtCreateWindow(...)
|
WindowProc <---------------------+
结构化异常在Windows处理(SEH)可以展开栈,通过内核模式展开回来,回到我的用户代码,在那里我可以处理该异常,我看到一个有效的堆栈跟踪。
但不是在64位Windows
Windows的64位版本不能做到这一点:
对于复杂的原因,我们不能传播异常回到64位操作系统 (AMD64和IA64)。 这已经是自2003年服务器在x86的第64位版本不断的情况下,这种情况并非如此 - 除了获得通过内核的边界而传播,并最终会走在后面的帧
而且,由于没有办法往回走了可靠的堆栈跟踪在这种情况下,不得不做出一个决定:让你看到不无意义异常,或者干脆隐藏它:
当时的内核架构师决定采取保守的程序兼容性友好的方式 - 隐藏例外,并希望最好的。
文章接着说说如何,这是所有64位Windows操作系统的表现如何:
- Windows XP中64位
- Windows Server 2003的64位
- Windows Vista中的64位
- 在Windows Server 2008 64位
但是,开始使用Windows 7(和Windows Server 2008),建筑师改变了主意 - 那种。 仅适用于 64位应用程序(不是32位应用程序),他们会(默认) 停止抑制这些用户内核用户异常。 因此,在默认情况下,于:
- Windows 7的64位
- 在Windows Server 2008
所有的64位应用程序会看到这些异常,他们从来没有使用过,看到他们。
在Windows 7中,当以这种方式的本地x64的应用程序崩溃, 程序兼容性助手通知。 如果应用程序没有Windows 7的清单 ,我们展示了一个对话框,告诉你,PCA已申请了应用程序兼容性垫片 。 这是什么意思? 这意味着,在下次运行应用程序时,Windows会效仿Server 2003的行为,使异常消失。 请记住,PCA不能在Server 2008 R2的存在,所以这个建议并不适用。
所以问题
问题是,为什么是64位Windows无法放松堆栈回通过内核过渡, 而Windows的32位版本可以吗?
唯一的线索是:
对于复杂的原因,我们不能传播异常回到64位操作系统 (AMD64和IA64)。
该提示是很复杂的 。
我可能不明白的解释,因为我不是一个操作系统开发者 - 但我想射击在知道为什么。
更新:修补程序停止抑制32位应用程序
微软已经发布了一个修补程序使32位应用程序也不再具有抑制异常:
KB976038:这是从在Windows的64位版本上运行的应用程序引发的异常被忽略
- 是抛出一个回调例程运行在用户模式下的异常。
在这种情况下,这种异常不会导致应用程序崩溃。 相反,应用程序进入不一致的状态。 然后,应用程序将引发一个不同的异常和崩溃。
用户模式回调函数通常是由内核模式组件调用的应用程序定义的函数。 用户模式回调函数的例子都是Windows程序和钩子程序。 这些功能是通过调用Windows处理Windows消息或处理的Windows挂钩事件。
该修补程序,然后让您从全局吃例外停止Windows:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options DisableUserModeCallbackFilter: DWORD = 1
或者每个应用程序:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Notepad.exe DisableUserModeCallbackFilter: DWORD = 1
行为也在KB973460在案XP和Server 2003:
- 这是从64位应用程序引发的异常是在Windows Server 2003的Windows XP专业版或64位版本上运行会被忽略
一个提示
我发现了另一个提示使用xperf捕捉到在64位Windows堆栈跟踪调查时:
堆栈走在Xperf
禁用分页执行
为了跟踪在64位Windows工作,你需要设置disablepagingexecutive调整注册表项。 这告诉操作系统不要页面内核模式驱动程序和系统代码到磁盘,这是获得使用xperf 64位调用堆栈的前提条件,因为64位堆栈行走取决于元数据的可执行映像,并在某些情况下, xperf 堆栈步代码是不允许碰调出的页面 。 从提升的命令提示符下运行以下命令将设置您此注册表项。
REG ADD "HKLM\System\CurrentControlSet\Control\Session Manager\Memory Management" -v DisablePagingExecutive -d 0x1 -t REG_DWORD -f
设置此注册表项后,您将需要重新启动系统之前,你可以记录调用栈。 有了这个标志设置意味着Windows内核锁更多的页面到RAM,所以这可能会消耗大约10 MB的额外物理内存。
这给人的印象是,在64位Windows(且仅在64位Windows),你不能走内核堆栈,因为有可能是页面出在磁盘上。