注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

写着玩

Bob

 
 
 

日志

 
 
 
 

陷阱调度--6  

2009-07-26 23:58:25|  分类: Win32 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

http://hi.baidu.com/l_wait/blog/item/e08864cbc88ec71bbf09e66b.html

 

异常调度

       与中断的随机发生不同,异常是直接由程序执行引起的状况。Windows采用了一种叫做结构化异常处理(structured exception handling)的机制,该机制允许应用程序在出现异常的时候获得控制权。于是应用程序可以修复异常,再回到发生异常的地方,展开栈(于是结束掉引起异常的部分的执行),或者告诉系统此异常无法识别,于是系统会再继续寻找可以处理这个异常的异常处理程序。要理解后面文字你需要熟悉Windows结构化异常处理背后的概念——如果你还不熟悉,请在继续阅读之前参考Platform SDK的Windows API参考文档的概述,或者Jeffrey Richter的Programming Applications for Microsoft Windows(Fourth Edition, Microsoft Press, 2000)的第23到第25章。请记得,异常处理虽然可以通过扩充语言而被引入(比如,Microsoft Visual C++中的__try),但是它实际上是一种系统机制而非语言特质。其他Windows异常处理的用户还包括C++和Java exceptions等。

   在0x86中,所有的异常都有预定义的中断号,直接对应于IDT的项,而后者为特定的异常指出陷阱处理程序。由于IDT的第一项是指定给了异常,所以只好将靠后的项分配给硬件中断了。

       所有的异常,除了那些能够被陷阱处理程序解决的简单异常,其他的都会交给一个叫异常调度程序(exception dispatcher)的内核模块处置。异常调度程序的工作是寻找可以处理某个异常的异常处理程序。内核定义的与体系结构无关的异常包括内存非法访问、整数除0、整数溢出、浮点异常,以及除错器断点等。与体系结构无关的异常清单可以从Windows API参考文档中获得。

       对于用户程序来说,内核对某些异常的捕获和处理是显而易见的。比如,在调式一个程序时遇到断点会产生一个异常,内核会调用除错器来处理这个异常。对于另外一些异常,内核会返回给调用者一个表示未成功的代码。

       少数异常会被滤过,不被处理,返回到用户模式。比如,系统不会处理内存非法访问或计算溢出产生的异常。一个环境子系统会建立一个基于帧的异常处理程序来处理这些异常。基于帧是指,将异常处理与某个特定的过程激活关联在一起。当一过程被调用,一个栈帧表示过程激活被推入栈中。一个栈帧可以包含一个或多个与之关联的异常处理程序,每一个异常处理都被用来保护源代码中的某个代码块。当有异常发生,内核就会搜索关联当前栈帧的异常处理程序。如果没找到,内核就会继续搜索关联之前栈帧的异常处理程序,以此类推,直到找到一个基于帧的异常处理程序。如果最终没有找到,内核会调用它的默认异常处理程序。

       当有一个异常出现,不管它是由软件直接引起还是由硬件间接引起的,内核中都会因此展开一系列的事件。CPU硬件将控制传递给内核陷阱处理程序,后者会新建一个陷阱帧(就和产生中断时一样)。如果异常被修复,陷阱帧允许系统从产生异常的点重新执行。陷阱处理程序还会建立一个异常记录,其中存储了出现异常的原因和其他相关信息。

       如果异常发生在内核模式,异常调度器只简单地呼叫一个例程来定位可能能处理该异常的基于帧的异常处理程序。因为无法处理的内核模式异常会被视为一个严重的操作系统错误,所以你可以认为调度器总会为它找到一个异常处理程序。

       如果异常发生在用户模式,异常调度器的工作会更加复杂。Windows子系统用一个除错器端口和一个异常端口用来接收Windows进程的用户模式异常发出的消息。内核将这些信息用于默认的异常处理。

      除错器断点是常见的异常来源。因此,异常调度器的第一个动作就是看这个发生异常的进程是否有一个关联的除错进程。如果有,且系统为Windows 2000,异常调度器会通过一个LPC(local procedure call)将第一时间除错消息发送到与发生异常的进程关联的除错端口。在Windows XP和Windows Server 2003中,异常调度器会发送一个除错器物件消息到与该进程关联的除错器物件(它在系统内部被当作一个端口)。

       如果该进程没有附加的除错进程,或者除错器不能处理这个异常,异常调度器就会切换到用户模式,将陷阱帧复制到用户栈中一个叫CONTEXT的数据结构(其描述见Platform SDK),然后调用一个例程以搜索基于帧的异常处理程序。如果没有找到,或者都不能处理该异常,异常调度器就再切换回内核模式,然后再次调用除错器让用户进一步调式(这个叫做二次通知)。

       如果除错器没在工作,并且也没找到基于帧的处理程序,内核就会向与线程所属的进程关联的异常端口发送一个消息。异常端口如果存在,它是由控制线程的环境子系统注册的。异常端口让可能一直监听端口的环境子系统有机会将异常转换成专属于环境的信号或异常。CSRSS (Client/Server Run-Time Subsystem)只简单地弹出一个对话框以告知用户出现了错误并结束进程,而当POSIX从内核获得消息说它的一个线程产生了一个异常,POSIX子系统会发送一个POSIX风格的信号给造成异常线程。但是,如果内核进行到这里而子系统还是没能处理异常,内核就会执行一个默认的异常处理程序简单地结束掉引起异常线程所属的进程。

无法处理的异常

       所有的Windows线程都有一个在栈顶声明的异常处理程序,它用来处理无法处理的异常。这个异常处理程序声明于Windows内部函数start-of-process或start-of-thread中。当进程的第一个线程开始执行时即调用函数start-of-process。它调用程序的主入口点。当用户新建了一个线程时就执行函数start-of-thread。它调用用户提供的在CreateThread中指定的线程最先执行的例程。

       请注意当线程存在一个无法解决的异常时,Windows的unhandled exception filter就会被调用。此函数的目的在于为无法解决的异常提供系统定义的处理行为,它的行动力基于注册表键HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug中的内容。键中两个重要的项分别为:Auto和Debugger。Auto决定了是让除错器自动运行unhandled exception filter还是询问用户要怎么做。其默认值为1,意为它会自动调用除错器。但是,装载类似Visual Studio的开发工具会将该项置为0。Debugger的值是一个字符串,它指出了当存在无法解决的异常时可执行的除错器的位置。

       默认的除错器是\Windows\System32\Drwtsn32.exe (Dr. Watson),它其实不是真正的除错器而是一个“尸检”工具,它获取应用程序崩溃时的状态,并将状态写入日至文件(Drwtsn32.log)和进程崩溃转储文件(User.dmp)中。两个文件的默认位置为\Documents And Settings\All Users\Documents\DrWatson文件夹。

       日志文件中包含了一些基本信息,如异常码、出错程序的名字、加载的DLLs清单、一个栈以及对产生异常线程的指令跟踪。细节详见Dr.Watson的帮助文档。

   崩溃转储文件中包含了异常发生时进程的私有页(不包括EXEs或DLLs的代码页)。可以用WinDbg打开此文件,WinDbg是包括在Debugging Tools工具包或者Visual Studio 2003及其后版本里面的除错器。由于每次进程崩溃都会改写User.dmp文件,所以除非每次都重命名或复制该文件,否则系统中只会保留最新的一版。

Windows错误报告

       Windows XP和Windows Server 2003有了一个新的,更复杂的错误报告机制叫Windows Error Reporting,它会自动提交用户模式进程崩溃信息以及内核模式系统崩溃信息。

   Windows Error Reporting可以以如下方式进行配置:我的电脑 -〉属性 -〉高级 -〉错误报告。这些设置被存储于注册表的HKLM\Software\Microsoft\PCHealth\ErrorReporting中。

   当一个无法处理的异常被unhandled exception filter捕获,就进行一个初步的判断看是否开始Windows Error Reporting。如果注册表的HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug\Auto的值为0或者Debugger的串值中包括"Drwtsn32",就加载\Windows\System32\Faultrep.dll到出错的进程并且调用函数ReportFault。ReportFault会检查存储在HKLM\Software\Microsoft\PCHealth\ErrorReporting中的Error Reporting的配置看这个进程崩溃是否需要报告,如果需要,一般来说会新建一个进程运行,该程序会显示一个对话框表示这个进程崩溃并且请用户选择是否向Microsoft提交错误报告。

   如果按下“发送错误报告”按钮,错误报告(一个最简转储文件和一个包括了加载到出错进程的DLL细节的文本文件)会被发送到Microsoft的在线崩溃分析服务器,Watson.Microsoft.com。(与内核模式系统崩溃不同,在提交报告时无法得知是否有一种有效的解决办法)接着unhandled exception filter会新建一个进程以运行系统规定的除错器(一般来说是Drwtsn32.exe),该除错器会默认生成两个转储文件和日志记录。与Windows 2000不同,这里的转储文件是指一个最简转储文件,不是全部。所以,当需要全部的进程内存转储来帮助调式出错程序时,你可以不带命令行参数的运行Dr. Watson以改变其设置。

   在一个不联网的环境里或者当管理员想要控制哪些错误报告会被提交给Microsoft时,错误报告的目标会被设置成一个内部的文件服务器。Microsoft向有授权用户提供了一个叫Corporate Error Reporting的工具集,它了解Windows Error Reporting所建立的目录结构并且使管理员可以选择向Microsoft提交哪些错误报告。

  评论这张
 
阅读(431)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017