windows SEH机制注释(1) 基于ReactOS [第二次修订]

1.SEH链表的布局:

FS:[0]->因函数层层调用形成嵌套的全局SEH链表:

_SEHFrame!__SEHRegistration* SER_Prev-函数调用形成->_SEHFrame!__SEHRegistration* SER_Prev-函数调用形成->SER_Prev ... [该方向是线程全局fs:[0]链表]

        |                                                                                                   |
        |                                                                                                   |

        |                                                                                                   |-[单个函数内部嵌套SEH链表:SEH_SEHFrame!SPF_TopTryLevel!__SEHPortableTryLevel* ]

        |

        |-[单个函数内部嵌套SEH链表:SEH_SEHFrame!SPF_TopTryLevel!__SEHPortableTryLevel* SPF_TopTryLevel->_SEHFrame!SPF_TopTryLevel!__SEHPortableTryLevel* SPF_TopTryLevel] ...

2.SEH组织结构:

1).如果,函数中使用了SEH机制,就会生成一个SEH节点,插入到链表fs:[0]中;

2).SEH内部又可以再嵌套使用SEH机制,内部的SEH又需要一个SEH节点来管理;

    WinOS在设计上引入了面向对象的思想,在SEH中也有体现:为了体现内部嵌套的SEH与函数中最外部SEH节点的从属关系,需要将这个内部嵌套的SEH挂到外部SEH节点(已挂在fs:[0]链表中)的用于管理嵌套异常的链表头中。

鉴于上述结论,可知一个SEH节点的归属,不是在fs:[0]链表中,就是在某个fs:[0]链表中SEH节点的嵌套异常链表中。要确定SEH的位置,首先要知道插入到fs:[0]中的哪个位置;还要知道在嵌套链表中的位置,SEHFrame因此诞生,用以描述SEH节点的归属。


3.SEH组织结构的实现:

3-1).姑且称__SEHFrame结构为SEH管理结构,为什么这样称呼他?

上面提到SEH节点不是在fs:[0]链表中,就是在某个SEH节点的嵌套链表中,而这个结构正好具有这两个特征:

首先,__SEHFrame中__SEHRegistration域表明SEH是否处于fs:[0]所指向的链表中。

其次,__SEHFrame中的SPF_TopTryLevel域表明SEH节点是全局SEH链表下某个嵌套链表节点中。

下面,展开看下这个结构。


typedef struct __SEHFrame
{
    _SEHPortableFrame_t SEH_Header;
        /*
        struct __SEHPortableFrame

        {

            _SEHRegistration_t SPF_Registration;
                /*
                包含单个seh框架或者局部seh框架栈(seh嵌套?)的最外层SEH节点
                struct __SEHRegistration

                {

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    //用以加入全局ExceptionList队列[fs:0]
                    struct __SEHRegistration* SER_Prev;
                    //一个具体节点的处理都由这个函数实施

                    _SEHFrameHandler_t SER_Handler;

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                }
                */
            //异常码
            unsigned long SPF_Code;
            //_SEHHandler_t设置为_SEHCompilerSpecificHandler
            volatile _SEHHandler_t SPF_Handler;
            //SPF_TopTryLevel代表具体seh框架,可能是指函数中诺干嵌套try{}except{}中的一个,
            //异常发生后,从系统处理中跳转到try{}except{}中的处理,需要__SEHTryLevel结构
            //__SEHTryLevel结构再下面
            _SEHPortableTryLevel_t* volatile SPF_TopTryLevel;
                /*
                struct __SEHPortableTryLevel

                {

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    //构成局部SEH框架栈中的一个节点,
                    //每个节点代表嵌套SEH结构中某个具体的SEH框架
                    //

                    struct __SEHPortableTryLevel * volatile SPT_Next;

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                    //与该SEH节点相关的过滤函数和finally函数指针
                    volatile _SEHHandlers_t SPT_Handlers;
                    /*
                        typedef struct __SEHHandlers
                        {
                        _SEHFilter_t SH_Filter;
                        _SEHFinally_t SH_Finally;
                        }
                    */
                }
                */
            volatile int SPF_Tracing;
        }
        */
    //缓冲区,存放寄存器值
    void * volatile SEH_Locals;
}

3-2).SEH节点

struct __SEHTryLevel 姑且称为SEH处理结构,为什么这样称呼他?

首先这个结构跟上面的结构有所不同,没有SEH归属相关的管理信息(虽然__SEHTryLevel!__SEHPortableTryLevel!SPT_Next仍有管理从属相关的信息)。

另外,_SEHJmpBuf_t ST_JmpBuf域涉及异常出现时跳转相关,跳转的异常处理代码中,因此,个人觉得,这个称为SEH处理节点不为过。


struct __SEHTryLevel
{
    _SEHPortableTryLevel_t ST_Header;
        /*
        struct __SEHPortableTryLevel
        {
            //构成局部SEH框架栈中的一个节点,
            //每个节点代表具体的SEH框架
            struct __SEHPortableTryLevel * volatile SPT_Next;
            //过滤函数和finally函数指针
            volatile _SEHHandlers_t SPT_Handlers;
            /*
                typedef struct __SEHHandlers
                {
                _SEHFilter_t SH_Filter;
                _SEHFinally_t SH_Finally;
                }
            */
        }
        */
    //异常发生后,从系统处理中跳转到try{}except{}中的处理,需要__SEHTryLevel!ST_JmpBuf保存的上下文
    _SEHJmpBuf_t ST_JmpBuf;
};

4.结构介绍完,来看个SEH宏展开:

func()
{
    _SEH_TRY
    {
        //do sth
        __SEH_TRY
        {

           //异常了吧
            _asm int 0x03;
        }
        _SEH_HANDLE
        {
            status = _SEH_GetExceptionCode();
        }
        _SEH_END
    }
    _SEH_HANDLE
    {
        status = _SEH_GetExceptionCode();
    }
    _SEH_END
}

func()
{
    ///
    外层SEH
    ///
    for(;;)
    {
        /*
        初次进入函数时,_SEHScopeKind _SEHPortableFrame _SEHPortableTryLevel为文件范围的静态变量,值分别为1 0 0
        经过逻辑判断,赋值_SEHTopTryLevel==1,意为这是顶层SEH
        */
        _SEH_INIT_CONST int _SEHTopTryLevel = (_SEHScopeKind != 0);  //(a)
        
        /*
        生成一个包含SEH节点的局部SEH框架指针(值空),_SEHCurPortableFrame ==> current frame当前框架,

        上面说了静态变量_SEHPortableFrame==NULL

        */
        _SEHPortableFrame_t* const _SEHCurPortableFrame = _SEHPortableFrame;
        
        /*
        局部SEH框架可能嵌套诺干SEH子框架,如
            try
            {
                try{} ...
            }
        _SEHPrevPortableTryLevel应该为当前局部SEH框架中所有嵌套SEH子框架的顶层框架,

        初始时_SEHPortableTryLevel==NULL;

        */
        _SEHPortableTryLevel_t* const _SEHPrevPortableTryLevel = _SEHPortableTryLevel;
    
        {
            //上一个_SEHScopeKind是文件静态变量,现在定义是本层try的局部变量_SEHScopeKind
            _SEH_INIT_CONST int _SEHScopeKind = 0;  //(5)
            register int _SEHState = 0;
            register int _SEHHandle = 0; 


            //SEH管理变量,指明SEH的归属
            //__SEHFrame!_SEHPortableTryLevel_t* SPF_TopTryLevel是一个指针成员,指向栈上变量_SEHTryLevel_t!ST_Header
            _SEHFrame_t _SEHFrame;
            //SEH处理结构变量
            _SEHTryLevel_t _SEHTryLevel;

           
            /*此处定义的_SEHPortableFrame、_SEHPortableTryLevel指针,与SEH结构开始时的文件静态变量_SEHPortableFrame _SEHPortableTryLevel相呼应;当创建内部嵌套的SEH处理结构时,会用到外层定义的这几个局部变量

            */

            /*
            (6) 经过(a)处的赋值,现在_SEHTopTryLevel==1
            因此下面的?:操作符的结果使得_SEHPortableFrame的值为本层局部 SEH管理变量_SEHFrame.SEH_Header地址。而很凑巧的是,_SEHFrame!SEH_Header位于结构体起始地址,这个地址又恰好又是_SEHPortableFrame!SPF_Regstration的地址,因此,这个语句意为:如果本层SEH是最外层SEH(_SEHTopTryLevel==1),则_SEHPortableFrame指向fs:[0]
            */
            _SEHPortableFrame_t* const _SEHPortableFrame =
                _SEHTopTryLevel ? &_SEHFrame.SEH_Header : _SEHCurPortableFrame;
              /*

             _SEHPortableTryLevel指向本层局部SEH处理变量地址 (链表头)

             */  

            //(7)
            _SEHPortableTryLevel_t* const _SEHPortableTryLevel = &_SEHTryLevel.ST_Header;
    
            (void)_SEHScopeKind;
            (void)_SEHPortableFrame;
            (void)_SEHPortableTryLevel;
            (void)_SEHHandle;
    
            for(;;)
            {
                //(1)
                if(_SEHState) /*初始时_SEHState为0,进入(2)else分支_SEHSetJmp,设置长跳转后_SEHState++;continue*/
                {
                    for(;;)
                    {
                        {
                        /*这层循环中是执行受保护的代码,受保护代码执行完,会遇到下面的break,跳出_SEH_TRY*/
                        /*_SEHHandle _SEHTryLevel _SEHFrame定义在_SEH_TRY*/
                            扩展前try的开始{
                            
                            
                                ///
                                内层SEH
                                ///
                                for(;;)
                                {
                                    /*
                                    内层SEH_TRY使用的_SEHScopeKind是外层SEH_TRY定义的栈变量,初值为0,位于(5)
                                    因此_SEHTopTryLevel=0,意为接下去的SEH处理节点不是函数的顶层节点
                                    */
                                    _SEH_INIT_CONST int _SEHTopTryLevel = (_SEHScopeKind != 0);
                                    
                                    /*
                                    此处的_SEHPortableFrame是位于(6)的外层SEH定义的指针,指向外层SEH管理变量_SEHFrame.SEH_Header
                                    */
                                    _SEHPortableFrame_t * const _SEHCurPortableFrame = _SEHPortableFrame;
                                    
                                    
                                    /*
                                    同上,位于(7),_SEHPortableTryLevel是外层SEH定义的指针,该指针指向外层SEH处理结构,
                                    这么看,倒是符合Prev这个名字
                                    */
                                    _SEHPortableTryLevel_t * const _SEHPrevPortableTryLevel = _SEHPortableTryLevel;
                                
                                    {
                                        _SEH_INIT_CONST int _SEHScopeKind = 0;
                                        register int _SEHState = 0;
                                        register int _SEHHandle = 0;
                                        _SEHFrame_t _SEHFrame;
                                        _SEHTryLevel_t _SEHTryLevel;
                                        /*本层的SEH管理结构。
                                        _SEHTopTryLevel==0,_SEHPortableFrame=_SEHCurPortableFrame。而_SEHCurPortableFrame在进入内层SEH时

                                        指向外层SEH管理变量_SEHFrame,
                                        这是在形成函数内部嵌套SEH结构的链表?
                                        */
                                        _SEHPortableFrame_t* const _SEHPortableFrame =
                                            _SEHTopTryLevel ? &_SEHFrame.SEH_Header : _SEHCurPortableFrame;
                                            
                                        _SEHPortableTryLevel_t * const _SEHPortableTryLevel = &_SEHTryLevel.ST_Header;
                               
                                        (void)_SEHScopeKind;
                                        (void)_SEHPortableFrame;
                                        (void)_SEHPortableTryLevel;
                                        (void)_SEHHandle;
                               
                                        for(;;)
                                        {
                                            if(_SEHState) /*初始时_SEHState为0,进入else分支_SEHSetJmp,设置长跳转后_SEHState++;continue*/
                                            {
                                                for(;;)
                                                {
                                                    {
                                                    /*这层循环中是执行受保护的代码,受保护代码执行完,会遇到下面的break,跳出_SEH_TRY*/
                                                    /*_SEHHandle _SEHTryLevel _SEHFrame定义在_SEH_TRY*/
                                                        扩展前try的开始{
                                                       
                                                       
                                                            ///
                                                            _asm int 0x03;
                                                            ///
                                                           
                                                           
                                                        扩展前try的结束}
                                                    }
                               
                                                    break;
                                                }
                               
                                                break; /*没有遇到异常,受保护代码跳出到if(_SEHHandle){...},判断 _SEHHandle的值*/
                                            } /*在if((_SEHHandle = _SEHSetJmp(_SEHTryLevel.ST_JmpBuf)) == 0)中被置位0*/
                                            else
                                            {
                                                if((_SEHHandle = _SEHSetJmp(_SEHTryLevel.ST_JmpBuf)) == 0)
                                                {
                                                    _SEHTryLevel.ST_Header.SPT_Handlers.SH_Filter = (_SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER)); //执行异常处理代码
                                                    _SEHTryLevel.ST_Header.SPT_Handlers.SH_Finally = 0;
                                                    /*
                                                    _SEHPrevPortableTryLevel指向外层的SEH处理结构,
                                                    内层SEH处理结构的下一个节点指向外层SEH处理结构,形成函数内部嵌套SEH链,注意与后面外层_SEHTryLevel的区别
                                                    */
                                                    _SEHTryLevel.ST_Header.SPT_Next = _SEHPrevPortableTryLevel;/*定义于_SEH_TRY!_SEHPortableTryLevel_t * _SEHPrevPortableTryLevel*/
                                                    _SEHFrame.SEH_Header.SPF_TopTryLevel = &_SEHTryLevel.ST_Header;
                               
                                                    if(_SEHTopTryLevel) /*_SEH_TRY!_SEH_INIT_CONST int _SEHTopTryLevel = (_SEHScopeKind != 0);*/
                                                    {
                                                        if(&_SEHLocals != _SEHDummyLocals)
                                                            _SEHFrame.SEH_Locals = &_SEHLocals;
                               
                                                        _SEH_EnableTracing(_SEH_DO_DEFAULT_TRACING);
                                                        _SEHFrame.SEH_Header.SPF_Handler = _SEHCompilerSpecificHandler;
                                                        _SEHEnterFrame(&_SEHFrame.SEH_Header); /*_SEHEnterFrame是个函数,用于挂入[FS:0]*/
                                                    }
                                                    //即将进入受保护的代码块去执行,即if(_SEHState)块中

                                                    ++ _SEHState;
                                                    continue;
                                                }
                                                else
                                                {
                                                    break;
                                                }
                                            }
                               
                                            break;
                                        }
                                        //链表操作,指向外层的SEH处理结构
                                        _SEHPortableFrame->SPF_TopTryLevel = _SEHPrevPortableTryLevel;
                               
                                        if(_SEHHandle)
                                        {
                                            {
                                                status = _SEH_GetExceptionCode();
                                            }
                                        }
                                    }
                               
                                    if(_SEHTopTryLevel)
                                        _SEHLeaveFrame();
                               
                                    break;
                                }
                            }
                            ///
                            ///
                            ///
                                
                                
                            扩展前try的结束}
                        }
    
                        break;
                    }
    
                    break;
                    /*如果没有遇到异常,受保护代码跳出到if(_SEHHandle){...} _SEHHandle的值一直未被修改,
                    在首次if((_SEHHandle = _SEHSetJmp(_SEHTryLevel.ST_JmpBuf)) == 0)中被置位0,因此不执行
                    if(_SEHHandle){...}内的代码
                    */
                }
                //(2),承接上面(1)处的if语句
                else
                {
                    //_SEHSetJmp注释在后面
                    /*
                    创建一个SEH处理结构_SEHTryLevel时,_SEHState为0,进入else分支调用_SEHSetJmp,设置异常出现后的跳转目标
                    */
                    //(3)
                    if((_SEHHandle = _SEHSetJmp(_SEHTryLevel.ST_JmpBuf)) == 0)
                    {
                        /*
                        SEH处理结构的过滤/善后函数
                        */
                        _SEHTryLevel.ST_Header.SPT_Handlers.SH_Filter = (_SEH_STATIC_FILTER(_SEH_EXECUTE_HANDLER));
                        _SEHTryLevel.ST_Header.SPT_Handlers.SH_Finally = 0;
                        /*
                        外层_SEHPrevPortableTryLevel指针为空,因此外层SEH处理结构_SEHTryLevel也指向空,注意与内层SEH处理结构的区别;

                       另外,SEH结构是先进后出的结构,_SEHTryLevel.ST_Header.SPT_Next = NULL;使得外层SEH处理结构添加到链表尾部。

                        */
                        _SEHTryLevel.ST_Header.SPT_Next = _SEHPrevPortableTryLevel;/*定义于_SEH_TRY!_SEHPortableTryLevel_t * _SEHPrevPortableTryLevel*/
                        _SEHFrame.SEH_Header.SPF_TopTryLevel = &_SEHTryLevel.ST_Header;


                        //对于外层SEH,_SEHTopTryLevel==1
                        if(_SEHTopTryLevel) /*_SEH_TRY!_SEH_INIT_CONST int _SEHTopTryLevel = (_SEHScopeKind != 0);*/
                        {
                            if(&_SEHLocals != _SEHDummyLocals)
                                _SEHFrame.SEH_Locals = &_SEHLocals;
    
                            _SEH_EnableTracing(_SEH_DO_DEFAULT_TRACING);
                            _SEHFrame.SEH_Header.SPF_Handler = _SEHCompilerSpecificHandler;
                            //只有外层SEH处理结构会挂到FS:[0]中
                            _SEHEnterFrame(&_SEHFrame.SEH_Header); /*_SEHEnterFrame是个函数,用于挂入[FS:0]*/
                        }
                        /*
                        ++ _SEHState;
                        continue;
                        这两句执行后,才有机会进入到(1)中,然后执行受保护的代码,在这个函数中是_asm int 0x03
                        */
                        ++ _SEHState;
                        continue;
                    }
                    else
                    {
                        break;
                    }
                }
    
                break;
            }
            //链表操作
            _SEHPortableFrame->SPF_TopTryLevel = _SEHPrevPortableTryLevel;
            
            //(5)发生异常后,会跳转到(3),由_SEHSetJmp返回1,将_SEHHandle设置成1,然后进入if(_SEHHandle) {}
            if(_SEHHandle)
            {
                {
                    status = _SEH_GetExceptionCode();
                }
            }
        }
    
        if(_SEHTopTryLevel)
            _SEHLeaveFrame();
    
        break;
    }
}

_SEHSetJmp@4:
;[esp+0],调用_SEHSetJmp时压入的函数地址
mov eax,[esp+4] ;指向参数_SEHTryLevel.ST_JmpBuf
mov ecx,[esp+0] ;ecx保存_SEHSetJmp时压入的函数地址,应该是给_SEHHandle赋值那句
;(4)
lea edx,[esp+8] ;调用_SEHSetJmp前的堆栈指针
mov [eax+0],ebp ;ctx保存到_SEHTryLevel.ST_JmpBuf
。。。
xor eax,eax ;返回值,第一次返回值为0,因此_SEHSetJmp返回后_SEHHandle赋值为0
ret 4

后期发生异常,据说会调用_SEHLongJmp@8
_SEHLongJmp@8:
mov eax,[esp+8] ;据说此时[esp+8]==1,eax做返回值
...
;对应(4)处,edx保存的返回地址,jmp的返回地址为_SEHSetJmp,返回后,_SEHHandle赋值==1,一路跳到(5)
;执行异常处理
jmp edx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值