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