天天看点

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; 
     }
 }      

继续阅读