深入研究Win32结构化异常处理(SEH总结篇)
本文假设你熟悉WIN32,C/C++。
引言:
本文是在《Win32 结构化异常处理(SEH)探秘》基础上做的更新总结。探索MS C/C++编译器和MS核心DLL在操作系统SEH上的不同扩展,逐个分析其内部采用的数据结构及处理流程。
摘要:
Win32 结构化异常处理其核心是操作系统提供的服务,特定的编译器运行库包装操作系统SEH的实现,这其中就包括MS C/C++编译器定义的__try,__finally,__except关键字,这些关键字包装操作系统SEH的实现,方便我们编写异常处理语句。在本文中,我将一层层对SEH进行解剖,以便展示其最基本的概念。
SEH 浅析
当某个线程出错了,操作系统会给我们一个机会通知这个情况。具体点说,操作系统会调用某个用户定义的回调函数,这个回调函数可以做任何它想做的事情,不管回调函数做什么,其最后总是返回一个值,这个值告诉系统下一步做什么。我们来看看这个异常回调函数的原型(该原型在VC/include/excpt.h中有声明):
第一个参数是指向EXCEPTION_RECORD结构指针,该结构在WINNT.H中定义(成员含义查阅MSDN):
ExceptionCode是有操作系统提供给异常的一个数,代表异常发生的原因。ExceptionAddress表示异常发生的地址。
第二个参数是指向异常帧结构的指针,是一个很重要的参数。操作系统的异常帧结构类型如下:
第三个参数是CONTEXT结构的指针,CONTEXT结构在WINNT.H中定义,它表示特定线程异常发生时寄存器的值:
第四个参数是_DispatcherContext,用于存放下一个异常帧,全局展开在执行当前异常帧局部展开中发生嵌套展开时使用。
为了简化起见,我们可以这样理解:当异常发生时,有一个回调函数被调用,此回调函数带有四个参数。那么,当错误发生时候,操作系统如何知道去哪里调用这个回调函数呢?答案涉及另一个结构_EXCEPTION_REGISTRATION,它在vc/crt/src/exsup.inc中定义:
大家会发现这个结构和回调函数第二个参数的类型很相似,是的,它其实就是操作系统的异常帧结构类型!当错误发生时,操作系统将调用这个结构中的hanlder所指向的回调函数。好了,新的问题又来了,OS在哪里查找并发现_EXCEPTION_REGISTRATION结构?