为什么不能在64位Windows放松身心的用户内核用户异常? [英] Why can't 64-bit Windows unwind user-kernel-user exceptions?

查看:348
本文介绍了为什么不能在64位Windows放松身心的用户内核用户异常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么不能在64位Windows异常期间展开堆栈,如果堆栈穿过内核的边界 - 当32位Windows能

这整个问题的背景来源于:

<一个href="http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/">The情况下,消失的OnLoad例外 - 在64 用户模式回调异常

背景

在32位Windows,如果我扔在我的用户模式的code的异常,这是所谓的内核模式的code回首,那从我的用户模式的code的调用,如:

 用户模式内核模式
------------------ -------------------
CreateWindow的(...); ------&GT; NtCreateWindow(...)
                                   |
的WindowProc&LT; --------------------- +
 

的结构化异常处理(SEH)的Windows可以展开堆栈,展开回通过内核模式,回到我的用户code,在那里我可以处理这个异常,我看到一个有效的堆栈跟踪。

但不是在64位Windows

64位的Windows版本无法做到这一点:

  

有关复杂的原因,我们的不能传播异常回到64位操作系统(AMD64和IA64)。这一直以来的第64位版本的Server 2003在x86有史以来的情况下,这种情况并非如此 - 除了被通过内核的边界传播,并最终会走在后面的帧

既然没有办法走回了可靠的堆栈跟踪在这种情况下,不得不做出一个决定:让你看到不荒谬异常,或者干脆隐藏它:

  

内核架构师当时决定采取保守AppCompat友好的方式 - 隐藏例外情况,并希望最好

文章接着说说如何,这是所有64位Windows操作系统的行为方式:

  • 在Windows XP的64位
  • 在Windows Server 2003中的64位
  • 在Windows Vista的64位
  • 在Windows Server 2008中的64位

不过,从Windows 7(和Windows Server 2008),建筑师改变了想法 - 样的。对于只有 64位应用程序(而不是32位应用程序),他们将(默认)停止 SUP pressing这些用户可内核用户异常。因此,在默认情况下,上:

  • 在Windows 7的64位
  • 在Windows Server 2008中

所有的64位应用程序的的这些例外,他们从来没有使用过,看到他们。

  

在Windows 7中,当原生64 的以这种方式应用程序崩溃时,的程序兼容性助手的通知。如果应用程序没有一个 Windows 7的清单,我们展示一个对话框,告诉你,PCA已申请了应用程序兼容性垫片。这是什么意思?这意味着,下一次你运行应用程序时,Windows会模拟Server 2003的行为,使异常消失。请记住,这PCA不能在Server 2008 R2的存在,所以这个建议并不适用。

所以,问题

现在的问题是为什么的是64位的Windows无法通过内核过渡到放松的堆栈回来,而Windows的32位版本可以吗?

唯一的线索是:

  

有关复杂的原因,我们的不能传播异常回到64位操作系统(AMD64和IA64)。

该提示是的它的复杂的。

我可能不明白的解释,因为我不是一个操作系统开发者 - 但我想在拍摄知道为什么


更新:修复停止燮pressing 32位应用程序

微软已经发布了一个的修复的兼容32位应用程序中也不再有例外燮pressed:

  

KB976038:例外,从这个运行在64位版本的Windows的应用程序抛出被忽略

     
      
  • 被扔在回调例程运行在用户模式下异常。
  •   
     

在这种情况下,此异常不会导致应用程序崩溃。相反,应用程序进入不一致的状态。然后,应用程序将引发一个不同的异常和崩溃。

     

一个用户模式回调函数通常被称为由内核模式组件的应用程序定义的函数。用户模式回调函数的例子都是Windows程序和钩子程序。这些功能是由Windows调用来处理Windows消息或处理的Windows挂钩事件。

该修补程序,然后让您从全局吃例外停止的Windows:

  HKLM \ SOFTWARE \微软\的Windows NT \ CURRENTVERSION \图像文件执行选项
DisableUserModeCallbackFilter:DWORD = 1
 

或每个应用程序:

  HKLM \ SOFTWARE \微软\的Windows NT \ CURRENTVERSION \图像文件执行选项\ Notepad.exe的
DisableUserModeCallbackFilter:DWORD = 1
 

该行为也KB973460记录在XP和Server 2003:

    这是在Windows Server 2003或Windows XP的64位版本上运行的是从64位应用程序抛出
  • 例外专业被忽略

一个提示

我发现了另一个提示使用xperf捕捉在64位Windows堆栈跟踪调查时:

堆栈走在Xperf

  

禁用分页执行

     

为了追踪工作在64位的Windows,你需要设置的 disablepagingexecutive调整注册表项。这告诉操作系统不要页面内核模式驱动程序和系统code到磁盘上,这是一个prerequisite获取使用xperf 64位调用堆栈,因为64位堆栈行走取决于元数据的可执行映像,而且在某些情况下xperf 堆栈步code是不允许触碰调出网页。从提升的命令提示符下运行以下命令将设置此注册表项为您服务。

  REG ADDHKLM \系统\ CurrentControlSet \控制\会话管理器\内存管理-v
 disablepagingexecutive调整-d为0x1 -t REG_DWORD -f
 

     

设置,您需要重新启动系统之前,你可以记录调用栈此注册表项之后。有了这个标志设置意味着Windows内核锁的更多的页面到RAM中,因此这可能会消耗大约10 MB的额外的物理内存。

这使IM pression,在64位Windows(且仅在64位Windows),你不能走内核堆栈,因为有可能是页面在磁盘上。

解决方案

我是谁一loooooooong前段时间写了这个修补程序开发商以及博客文章。最主要的原因是,完整的寄存器文件并不总是当你过渡到内核空间,性能方面的原因抓获。

如果你犯了一个正常的系统调用,在64 应用程序二进制接口(ABI),只需要你preserve 非易失性寄存器的(类似于一种制造普通的函数调用)。然而,正确地展开异常需要你有所有的寄存器,所以这是不可能的。基本上,这是一个关键的场景PERF的之间进行选择(即一个场景,可能会发生每秒数千次)与100%正确处理一个病理方案(崩溃)。

奖金读

Why can't 64-bit Windows unwind the stack during an exception, if the stack crosses the kernel boundary - when 32-bit Windows can?

The context of this entire question comes from:

The case of the disappearing OnLoad exception – user-mode callback exceptions in x64

Background

In 32-bit Windows, if i throw an exception in my user mode code, that was called back from kernel mode code, that was called from my user mode code, e.g:

User mode                     Kernel Mode
------------------            -------------------
CreateWindow(...);   ------>  NtCreateWindow(...)
                                   |
WindowProc   <---------------------+                                   

the Structured Exception Handling (SEH) in Windows can unwind the stack, unwinding back through kernel mode, back into my user code, where i can handle the exception and i see a valid stack trace.

But not in 64-bit Windows

64-bit editions of Windows cannot do this:

For complicated reasons, we cannot propagate the exception back on 64-bit operating systems (amd64 and IA64). This has been the case ever since the first 64-bit release of Server 2003. On x86, this isn’t the case – the exception gets propagated through the kernel boundary and would end up walking the frames back

And since there's no way to walk back a reliable stack trace in this case, the had to make a decision: let you see the non-nonsensical exception, or hide it altogether:

The kernel architects at the time decided to take the conservative AppCompat-friendly approach – hide the exception, and hope for the best.

The article goes on to talk about how this was how all 64-bit Windows operating systems behaved:

  • Windows XP 64-bit
  • Windows Server 2003 64-bit
  • Windows Vista 64-bit
  • Windows Server 2008 64-bit

But starting with Windows 7 (and Windows Server 2008), the architects changed their minds - sort of. For only 64-bit applications (not 32-bit applications), they would (by default) stop suppressing these user-kernel-user exceptions. So, by default, on:

  • Windows 7 64-bit
  • Windows Server 2008

all 64-bit applications will see these exceptions, where they never used to see them.

In Windows 7, when a native x64 application crashes in this fashion, the Program Compatibility Assistant is notified. If the application doesn’t have a Windows 7 Manifest, we show a dialog telling you that PCA has applied an Application Compatibility shim. What does this mean? This means, that the next time you run your application, Windows will emulate the Server 2003 behavior and make the exception disappear. Keep in mind, that PCA doesn’t exist on Server 2008 R2, so this advice doesn’t apply.

So the question

The question is why is 64-bit Windows unable to unwind a stack back through a kernel transition, while 32-bit editions of Windows can?

The only hint is:

For complicated reasons, we cannot propagate the exception back on 64-bit operating systems (amd64 and IA64).

The hint is it's complicated.

i may not understand the explanation, as i'm not an operating system developer - but i'd like a shot at knowing why.


Update: Hotfix to stop suppressing 32-bit apps

Microsoft has released a hotfix enables 32-bit applications to also no longer have the exceptions suppressed:

KB976038: Exceptions that are thrown from an application that runs in a 64-bit version of Windows are ignored

  • An exception that is thrown in a callback routine runs in the user mode.

In this scenario, this exception does not cause the application to crash. Instead, the application enters into an inconsistent state. Then, the application throws a different exception and crashes.

A user mode callback function is typically an application-defined function that is called by a kernel mode component. Examples of user mode callback functions are Windows procedures and hook procedures. These functions are called by Windows to process Windows messages or to process Windows hook events.

The hotfix then lets you stop Windows from eating the exceptions globally:

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
DisableUserModeCallbackFilter: DWORD = 1

or per-application:

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\Notepad.exe
DisableUserModeCallbackFilter: DWORD = 1

The behavior was also documented on XP and Server 2003 in KB973460:


A hint

i found another hint when investigating using xperf to capture stack traces on 64-bit Windows:

Stack Walking in Xperf

Disable Paging Executive

In order for tracing to work on 64-bit Windows you need to set the DisablePagingExecutive registry key. This tells the operating system not to page kernel mode drivers and system code to disk, which is a prerequisite for getting 64-bit call stacks using xperf, because 64-bit stack walking depends on metadata in the executable images, and in some situations the xperf stack walk code is not allowed to touch paged out pages. Running the following command from an elevated command prompt will set this registry key for you.

 REG ADD "HKLM\System\CurrentControlSet\Control\Session Manager\Memory Management" -v 
 DisablePagingExecutive -d 0x1 -t REG_DWORD -f

After setting this registry key you will need to reboot your system before you can record call stacks. Having this flag set means that the Windows kernel locks more pages into RAM, so this will probably consume about 10 MB of additional physical memory.

This gives the impression that in 64-bit Windows (and only in 64-bit Windows), you are not allowed to walk kernel stacks because there might be pages out on disk.

解决方案

I'm the developer who wrote this Hotfix a loooooooong time ago as well as the blog post. The main reason is that the full register file isn't always captured when you transition into kernel space, for performance reasons.

If you make a normal syscall, the x64 Application Binary Interface (ABI) only requires you to preserve the non-volatile registers (similar to making a normal function call). However, correctly unwinding the exception requires you to have all the registers, so it's not possible. Basically, this was a choice between perf in a critical scenario (i.e. a scenario that potentially happens thousands of times per second) vs. 100% correctly handling a pathological scenario (a crash).

Bonus Reading

这篇关于为什么不能在64位Windows放松身心的用户内核用户异常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆