📄 exsup.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*
*
* Structure Exception Handling support.
* Taken from NT sources.
*/
#include <kernel.h>
#include "exsup.h"
#define SavedEsp -8
#define XPointers -4
#define FRAME_EBP_OFFSET 16
struct contextinfo {
CONTEXT CRec;
};
extern void _unwind_handler(void);
extern void _local_unwind2(void);
extern void _except_finish(void);
/* __ABNORMAL_TERMINATION - return TRUE if __finally clause entered via
* _local_unwind2.
*/
#pragma warning(disable:4035)
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
__declspec(naked) BOOL
__abnormal_termination(void)
{
__asm {
xor eax, eax; /* assume FALSE */
mov ecx, fs:[0];
cmp [ecx.ExHandler], offset _unwind_handler;
jne short at_done; /* UnwindHandler first? */
mov edx, [ecx+12]; /* establisher of local_unwind2 */
mov edx, [edx.TryLevel]; /* is TryLevel the same as the */
cmp [ecx+8], edx; /* local_unwind level? */
jne short at_done; /* no - then FALSE */
inc eax /* currently in _abnormal_termination */
at_done:
ret
}
}
#pragma warning(default:4035)
/*
* The structure struct _EXCEPTION_REGISTRATION was changed in C9,
* and a few fields were added. To keep the existing code happy,
* the link field was maintained and the new fields are used here
* as negative offsets from a pointer to such structure.
*/
#define SavedEsp -8
#define XPointers -4
#define FRAME_EBP_OFFSET 16
/* _EXCEPT_HANDLER3 - Try to find an exception handler listed in the scope
* table associated with the given registration record, that wants to accept
* the current exception. If we find one, run it (and never return).
* RETURNS: (*if* it returns)
* ExceptionContinueExecution - dismiss the exception.
* ExceptionContinueSearch - pass the exception up to enclosing handlers
*/
#pragma warning(disable:4035)
#pragma warning(disable:4731)
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
EXCEPTION_DISPOSITION __cdecl
_except_handler3(
PEXCEPTION_RECORD XRecord,
void *Registration,
PCONTEXT Context,
PDISPATCHER_CONTEXT Dispatcher
)
{
EXCEPTION_POINTERS ExcPtrs;
UnusedParameter(Dispatcher);
__asm {
/* DF in indeterminate state at time of exception, so clear it */
cld
mov ebx, Registration;
mov eax, XRecord;
test [eax.ExceptionFlags], EXCEPTION_UNWIND_CONTEXT;
jnz short lh_unwinding;
/* build the EXCEPTION_POINTERS locally, store its address in the
* registration record. this is the pointer that is returned by
* the _exception_info intrinsic.
*/
mov dword ptr ExcPtrs.ExceptionRecord, eax;
mov eax, Context;
mov dword ptr ExcPtrs.ContextRecord, eax;
lea eax, ExcPtrs;
mov [ebx.XPointers], eax;
mov esi, [ebx.TryLevel];
mov edi, [ebx.ScopeTable];
lh_top:
cmp esi, -1;
je short lh_bagit;
lea ecx, [esi+esi*2]; /*ecx= TryLevel*3*/
cmp dword ptr [(edi+ecx*4).Filter], 0;
je short lh_continue; /*term handler, so keep looking*/
/*filter may trash *all* registers, so save ebp and ScopeTable offset*/
push esi;
push ebp;
lea ebp, FRAME_EBP_OFFSET[ebx];
call [(edi+ecx*4).Filter]; /*call the filter*/
pop ebp;
pop esi;
/*ebx may have been trashed by the filter, so we must reload*/
mov ebx, Registration;
/* Accept <0, 0, >0 instead of just -1, 0, +1 */
or eax, eax;
jz short lh_continue;
js short lh_dismiss;
/*;assert(eax==FILTER_ACCEPT)*/
mov eax, Context
mov [eax].CRec.Esi, esi
mov [eax].CRec.Ebx, ebx
mov [eax].CRec.Eip, offset _except_finish
mov eax, ExceptionExecuteHandler
jmp short lh_return
lh_continue:
/* reload the scope table base, possibly trashed by call to filter */
mov edi, [ebx.ScopeTable];
lea ecx, [esi+esi*2];
mov esi, [edi+ecx*4+0]; /* load the enclosing TryLevel */
jmp short lh_top;
lh_dismiss:
mov eax, ExceptionContinueExecution; /* dismiss the exception */
jmp short lh_return;
lh_bagit:
mov eax, ExceptionContinueSearch;
jmp short lh_return;
lh_unwinding:
test [eax.ExceptionFlags], EXCEPTION_TARGET_UNWIND
mov eax, ExceptionContinueSearch;
jnz short lh_return;
push ebp;
lea ebp, FRAME_EBP_OFFSET[ebx];
push -1;
push ebx;
call _local_unwind2;
add esp, 8;
pop ebp;
/* the return value is not really relevent in an unwind context */
mov eax, ExceptionContinueSearch;
lh_return:
}
}
#pragma warning(default:4731)
#pragma warning(default:4035)
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void __declspec(naked)
_except_finish(void)
{
__asm {
/*setup ebp for the local unwinder and the specific handler */
lea ebp, FRAME_EBP_OFFSET[ebx];
/* reload the scope table base */
mov edi, [ebx.ScopeTable];
/*the stop try level == accepting except level */
push esi; /* stop try level */
push ebx; /* Registration* */
call _local_unwind2;
add esp, 8;
lea ecx, [esi+esi*2]; /* ecx=TryLevel*3 */
/* set the current TryLevel to our enclosing level immediately
* before giving control to the handler. it is the enclosing
* level, if any, that guards the handler.
*/
mov eax, [(edi+ecx*4).EnclosingLevel];
mov [ebx.TryLevel], eax;
call [(edi+ecx*4).SpecificHandler];
/* assert(0); -- (NB! should not return) */
}
}
#pragma warning(disable:4733)
//------------------------------------------------------------------------------
//
// _LOCAL_UNWIND2 - run all termination handlers listed in the scope table
// associated with the given registration record, from the current lexical
// level through enclosing levels up to, but not including the given 'stop'
// level.
//
//------------------------------------------------------------------------------
__declspec(naked) void
_local_unwind2(void)
{
/* NOTE: frame (ebp) is setup by caller of __local_unwind2 */
__asm {
push ebx;
push esi;
push edi; /*call to the handler may trash, so we must save it */
mov eax, [esp+16]; /* xr */
/* link in a handler to guard our unwind */
push eax;
push TRYLEVEL_INVALID;
push OFFSET _unwind_handler;
push dword ptr fs:[0];
mov fs:[0], esp;
lu_top:
mov eax, [esp+32]; /* xr */
mov ebx, [eax.ScopeTable];
mov esi, [eax.TryLevel];
cmp esi, -1;
je short lu_done;
cmp esi, [esp+36]; /* stop */
je short lu_done;
lea esi, [esi+esi*2]; /* esi*= 3 */
mov ecx, [(ebx+esi*4).EnclosingLevel];
mov [esp+8], ecx ; /* save enclosing level */
mov [eax.TryLevel], ecx;
cmp dword ptr [(ebx+esi*4).Filter], 0;
jnz short lu_top;
call [(ebx+esi*4).SpecificHandler];
jmp short lu_top;
lu_done:
// cleanup stack
pop dword ptr fs:[0]
add esp, 4*3
pop edi;
pop esi;
pop ebx;
ret
}
}
#pragma warning(default:4733)
//------------------------------------------------------------------------------
// Exception handler function for _local_unwind2()
//------------------------------------------------------------------------------
void __declspec(naked)
_unwind_handler(void)
{
/*
* this is a special purpose handler used to guard our local unwinder.
* its job is to catch collided unwinds.
*
*/
__asm {
mov ecx, dword ptr [esp+4]; /* xr */
test dword ptr [ecx.ExceptionFlags], EXCEPTION_UNWIND_CONTEXT;
mov eax, ExceptionContinueSearch;
jz short uh_return;
//
// We collided in a _local_unwind. We set the dispatched to the
// establisher just before the local handler so we can unwind
// any future local handlers.
//
mov eax, [esp+8]; /* Our Establisher is the one */
/* in front of the local one */
mov edx, [esp+16]; /* set Dispatcher to local_unwind2 */
mov [edx], eax;
mov eax, ExceptionCollidedUnwind;
uh_return:
ret
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -