Ch25. Unhandled Exceptions, Vectored Exception Handling, and C++ Exceptions
Unhandled Exceptions
UnhandledExceptionFilter and WER Interactions
step1-3 都是既有UnhandleExceltionFilter內的動作
Filter回傳EXCEPTION_CONTINUE_SEARCH (step3),
讓Kernel接收例外並使用Advanced Local Procedure Call(ALPC)來呼叫WerSVC(step5 & 6).
ALPC會阻擋執行續的動作直到WerSVC結束動作.
(這邊的等待是使用WaitForSingleObjectEx,Ex版才能讓執行續等在可以被呼叫的狀態)
WerSVC會呼叫WerFault.exe(step6)產生報告(step7),
WerFault.exe會跳出"debug & 關閉"的選擇視窗(step8)
- 選擇關閉, WerFault.exe會回復TerminateProcess並將程序關閉.
- 選擇debug,就會進入Just in time debugging
"Note"
"書上著重user mode的問題, 如果是kernel mode的例外, 則因為kernel的記憶體位置損毀導致系統不宜繼續執行, 會產生所謂的藍屏. 系統會呼叫CrashDmp.sys來產生dump檔."
Just-in-Time debugging
透過AeDebug來檢查你的process, MSDN 上表示 "The AeDebug defines remote debugging options for COM."
WerFault.exe會呼叫這個位子的指令來產生debugger
(p.s 假如是系統的, 則必須"預先"attach你的debugger在系統程序上.)
參數auto設定是否要詢問使用者"是要關閉或是debug"
參數debugger底下設定debug的程式, 像是visual studio
"C:\Windows\system32\vsjitdebugger.exe" -p %ld -e %ld
-p 戴的是PID, -e 是在step6 createProcess 中從WerSvc繼承的handle,
(The second parameter identifies an inherited handle referring to a manual-reset event that was created in the nonsignaled state by the WerSvc service )
如果是自製的debugger, 要讓他認識這兩個參數
WerFault.exe在產生debugger process 時會設定createProcess的_bInheritHandles = true, 讓其可以繼承自己handles. 這些handle debugger可直接使用, 也可使用同步事件.
接著透過呼叫下面把自己attach上去
BOOL DebugActiveProcess(DWORD dwProcessID);
BOOL WINAPI DebugActiveProcessStop( _In_ DWORD dwProcessId);
系統會告知debugger目前debuggee用了多少thread, load dll等資訊.
當debugger初始化後, 他會在參數找-e switch. 拿到event的handle並呼叫 SetEvent (step11). 這個動作的目的是讓WerFault.exe知道debugger已經成功的attach到有問題的程式上面並且可以被呼叫例外.
此時WerFault.exe會結束,WerSvc偵測到並讓ALPC return(step12).
ALPC return會發生兩件事:(step13)
- debugee的執行續被喚醒
- kernel收到debugger ready
接著debugger就會收到例外通知, 載入相關的程式碼並指出exception的位置(step14)
流程圖的部分到這邊結束了
後面提到, 假如是要debug而沒有要處理例外事件, 也可以不給-e參數或給0
另外, 可以設定AutoExclusionList, 並用application name(dword type)來設定是否跳過.
同樣的做法我們可以設定WER的registry,
...\Windows NT\CurrentVersion\AeDebug
Auto=0
...\Windows\Windows Error Reporting\DebugApplications\
"Application Name" = 1
Vectored Exception/Continue Handlers
前面ch23, 24 提到的SEH結構是frame-based的結構, 每一個try block(又稱frame)都會藉由link list串聯起來, 當例外產生時, 系統就會往回尋找最可能的try block並呼叫他的catch handler & finally block.
當程式結束或跑完finally後, 這些frames會被link-list中移掉.
Windows提供Vectored Exception Handling(VEH)來當SEH的擴充, 讓程式可以註冊functions來處理自己發出的所有的例外,
從層面上來講, SEH是針對thread的, 而VEH, VCH是針對process的
Vectored handlers are not frame-based, therefore, you can add a handler that will be called regardless of where you are in a call frame.
Vectored handlers are called in the order that they were added, after the debugger gets a first chance notification, but before the system begins unwinding the stack.
- Vectored Continue Handler
PVOID AddVectoredExceptionHandler (
ULONG bFirstInTheList,
PVECTORED_EXCEPTION_HANDLER pfnHandler);
ULONG WINAPI RemoveVectoredExceptionHandler(
_In_ PVOID Handler);
- Vectored Exception handler
PVOID AddVectoredContinueHandler (
ULONG bFirstInTheList,
PVECTORED_EXCEPTION_HANDLER pfnHandler);
ULONG WINAPI RemoveVectoredContinueHandler(
_In_ PVOID Handler);
這兩種handler都是用Vector list儲存,會依序被呼叫.
bFirstInTheList是用來表示放在list的第一個或最後一個.
在VEH list中的function,如果可以修正例外, 他會回傳continue_execution並嘗試重新執行出問題的地方; 不行就回傳continue_search, 讓其他function或SEH接手.
不能回傳exception_execute_handler.
Vectored Continue Handler則是在global unhandled exception filter(SetUnhandledExceptionFilter) 回傳 EXCEPTION_CONTINUE_SEARCH 的時候被呼叫, 也就是在所有的SEH之後執行, 這些handler同樣只能回傳continue_execution或continue_search.
http://www.cnblogs.com/qiangua/p/3710324.html
C++ Exceptions vs. Structured Exceptions
SEH 優點是由OS所提供適用於所有語言,但如果是開發c++程式, 就應該使用c++ exception, 編譯器會自動針對c++的物件作處理並產生釋放物件的程式碼.
Visual C++的編譯器會使用SEH來實作c++ exception handling,也就是說,
c++ try被編譯成 SEH的__try, 如下
void ChunkyFunky() {
try {
...
throw 5;
}
catch (int x) {
...
}
}
into SEH
void ChunkyFunky() {
__try {
...
RaiseException(Code=0xE06D7363, Flag=EXCEPTION_NONCONTINUABLE, Args=5);
}
__except ((ArgType == Integer) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
...
}
}
RaiseException的參數
0xE06D7363是visual c++定義的c++ exception code, 是msc.的ASCII(6D 73 63)
EXCEPTION_NONCONTINUABLE 是為了確保c++ exception不能被重複執行,
從__except可以看到他只接受Execute_handler 跟 continue_search, 沒有continue_execution.
在__except這邊會檢查資料型態來決定是否執行catch區段.
作者表示, 因為c++ exception其實是由SEH來實作, 我們可以同時使用這兩種機制.
以作者為例, 他會在access violation的時候使用virtual memory來commit storage.但c++不允許這樣的回復異常的作法, 於是作者在這邊使用SEH, 其他地方則繼續使用c++
簡單來說, 可以交替使用SEH來做到一些, C++禁止或無法達到的效果.
Exceptions and the Debugger
- 在有設定debugger的情況下, OS會在例外發生的時候呼叫debugger, 稱作First-chance notification debugger會回復請執行續搜尋exception filters. 如果所有的filter都回應exception_continue_search, OS會再次用last-change notification呼叫debugger. 這兩次的呼叫是讓開發者可以針對例外有比較多的控制選項
DEMO