Goto sanos source index
//
// except.c
//
// MSVCRT exception handling
//
// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
// Copyright (C) 2000 Jon Griffiths
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the project nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
#include "msvcrt.h"
__declspec(dllimport) VOID __stdcall RtlUnwind(PEXCEPTION_FRAME endframe, LPVOID eip, PEXCEPTION_RECORD rec, DWORD retval);
typedef struct _SCOPETABLE {
int previousTryLevel;
int (*lpfnFilter)(PEXCEPTION_POINTERS);
int (*lpfnHandler)(void);
} SCOPETABLE, *PSCOPETABLE;
typedef struct _MSVCRT_EXCEPTION_FRAME {
EXCEPTION_FRAME *prev;
void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME, PCONTEXT, PEXCEPTION_RECORD);
PSCOPETABLE scopetable;
int trylevel;
int _ebp;
PEXCEPTION_POINTERS xpointers;
} MSVCRT_EXCEPTION_FRAME;
#define TRYLEVEL_END (-1) // End of trylevel list
static __inline EXCEPTION_FRAME *push_frame(EXCEPTION_FRAME *frame) {
struct tib *tib = gettib();
frame->prev = (EXCEPTION_FRAME *) tib->except;
tib->except = (struct xcptrec *) frame;
return frame->prev;
}
static __inline EXCEPTION_FRAME *pop_frame(EXCEPTION_FRAME *frame) {
struct tib *tib = gettib();
tib->except = (struct xcptrec *) frame->prev;
return frame->prev;
}
#pragma warning(disable: 4731) // C4731: frame pointer register 'ebp' modified by inline assembly code
static void call_finally_block(void *code_block, void *base_ptr) {
__asm {
mov eax, [code_block]
mov ebp, [base_ptr]
call eax
}
}
static DWORD call_filter(void *func, void *arg, void *base_ptr) {
DWORD rc;
__asm {
push ebp
push [arg]
mov eax, [func]
mov ebp, [base_ptr]
call eax
pop ebp
pop ebp
mov [rc], eax
}
return rc;
}
static EXCEPTION_DISPOSITION msvcrt_nested_handler(EXCEPTION_RECORD *rec, EXCEPTION_FRAME *frame, CONTEXT *ctxt, EXCEPTION_FRAME **dispatcher) {
if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) return ExceptionContinueSearch;
*dispatcher = frame;
return ExceptionCollidedUnwind;
}
void _global_unwind2(PEXCEPTION_FRAME frame) {
RtlUnwind(frame, 0, 0, 0);
}
void _local_unwind2(MSVCRT_EXCEPTION_FRAME* frame, int trylevel) {
MSVCRT_EXCEPTION_FRAME *curframe = frame;
EXCEPTION_FRAME reg;
//syslog(LOG_DEBUG, "_local_unwind2(%p,%d,%d)",frame, frame->trylevel, trylevel);
// Register a handler in case of a nested exception
reg.handler = (PEXCEPTION_HANDLER) msvcrt_nested_handler;
reg.prev = (PEXCEPTION_FRAME) gettib()->except;
push_frame(®);
while (frame->trylevel != TRYLEVEL_END && frame->trylevel != trylevel) {
int curtrylevel = frame->scopetable[frame->trylevel].previousTryLevel;
curframe = frame;
curframe->trylevel = curtrylevel;
if (!frame->scopetable[curtrylevel].lpfnFilter) {
syslog(LOG_WARNING, "warning: __try block cleanup not implemented - expect crash!");
// TODO: Remove current frame, set ebp, call frame->scopetable[curtrylevel].lpfnHandler()
}
}
pop_frame(®);
}
int _except_handler3(PEXCEPTION_RECORD rec, MSVCRT_EXCEPTION_FRAME* frame, PCONTEXT context, void *dispatcher) {
long retval;
int trylevel;
EXCEPTION_POINTERS exceptPtrs;
PSCOPETABLE pScopeTable;
//syslog(LOG_DEBUG, "msvcrt: exception %lx flags=%lx at %p handler=%p %p %p semi-stub",
// rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
// frame->handler, context, dispatcher);
__asm cld;
if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) {
// Unwinding the current frame
_local_unwind2(frame, TRYLEVEL_END);
return ExceptionContinueSearch;
} else {
// Hunting for handler
exceptPtrs.ExceptionRecord = rec;
exceptPtrs.ContextRecord = context;
*((DWORD *) frame - 1) = (DWORD) &exceptPtrs;
trylevel = frame->trylevel;
pScopeTable = frame->scopetable;
while (trylevel != TRYLEVEL_END) {
if (pScopeTable[trylevel].lpfnFilter) {
//syslog(LOG_DEBUG, "filter = %p", pScopeTable[trylevel].lpfnFilter);
retval = call_filter(pScopeTable[trylevel].lpfnFilter, &exceptPtrs, &frame->_ebp);
//syslog(LOG_DEBUG, "filter returned %s", retval == EXCEPTION_CONTINUE_EXECUTION ?
// "CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ?
// "EXECUTE_HANDLER" : "CONTINUE_SEARCH");
if (retval == EXCEPTION_CONTINUE_EXECUTION) return ExceptionContinueExecution;
if (retval == EXCEPTION_EXECUTE_HANDLER) {
// Unwind all higher frames, this one will handle the exception
_global_unwind2((PEXCEPTION_FRAME) frame);
_local_unwind2(frame, trylevel);
// Set our trylevel to the enclosing block, and call the __finally code, which won't return
frame->trylevel = pScopeTable->previousTryLevel;
//syslog(LOG_DEBUG, "__finally block %p",pScopeTable[trylevel].lpfnHandler);
call_finally_block(pScopeTable[trylevel].lpfnHandler, &frame->_ebp);
panic("Returned from __finally block");
}
}
trylevel = pScopeTable->previousTryLevel;
}
}
return ExceptionContinueSearch;
}