Commit dd93d255 authored by Alexandre Julliard's avatar Alexandre Julliard

Improved exception handling.

Based on the work of Sergey Turchanov <turchanov@usa.net>.
parent 4cd07769
...@@ -6,6 +6,7 @@ VPATH = @srcdir@ ...@@ -6,6 +6,7 @@ VPATH = @srcdir@
MODULE = ntdll MODULE = ntdll
C_SRCS = \ C_SRCS = \
exception.c \
file.c \ file.c \
nt.c \ nt.c \
om.c \ om.c \
......
/*
* NT exception handling routines
*
* Copyright 1999 Turchanov Sergey
* Copyright 1999 Alexandre Julliard
*/
#include "debugtools.h"
#include "winnt.h"
#include "ntddk.h"
#include "except.h"
#include "stackframe.h"
DEFAULT_DEBUG_CHANNEL(seh)
/* Exception record for handling exceptions happening inside exception handlers */
typedef struct
{
EXCEPTION_FRAME frame;
EXCEPTION_FRAME *prevFrame;
} EXC_NESTED_FRAME;
/*******************************************************************
* EXC_RaiseHandler
*
* Handler for exceptions happening inside a handler.
*/
static DWORD CALLBACK EXC_RaiseHandler( EXCEPTION_RECORD *rec, EXCEPTION_FRAME *frame,
CONTEXT *context, EXCEPTION_FRAME **dispatcher )
{
if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
return ExceptionContinueSearch;
/* We shouldn't get here so we store faulty frame in dispatcher */
*dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
return ExceptionNestedException;
}
/*******************************************************************
* EXC_UnwindHandler
*
* Handler for exceptions happening inside an unwind handler.
*/
static DWORD CALLBACK EXC_UnwindHandler( EXCEPTION_RECORD *rec, EXCEPTION_FRAME *frame,
CONTEXT *context, EXCEPTION_FRAME **dispatcher )
{
if (!(rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)))
return ExceptionContinueSearch;
/* We shouldn't get here so we store faulty frame in dispatcher */
*dispatcher = ((EXC_NESTED_FRAME*)frame)->prevFrame;
return ExceptionCollidedUnwind;
}
/*******************************************************************
* EXC_CallHandler
*
* Call an exception handler, setting up an exception frame to catch exceptions
* happening during the handler execution.
*/
static DWORD EXC_CallHandler( PEXCEPTION_HANDLER handler, PEXCEPTION_HANDLER nested_handler,
EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame,
CONTEXT *context, EXCEPTION_FRAME **dispatcher )
{
EXC_NESTED_FRAME newframe;
DWORD ret;
newframe.frame.Handler = nested_handler;
newframe.prevFrame = frame;
EXC_push_frame( &newframe.frame );
TRACE( "calling handler at %p\n", handler );
ret = handler( record, frame, context, dispatcher );
TRACE( "handler returned %lx\n", ret );
EXC_pop_frame( &newframe.frame );
return ret;
}
/*******************************************************************
* EXC_DefaultHandling
*
* Default handling for exceptions. Called when we didn't find a suitable handler.
*/
static void EXC_DefaultHandling( EXCEPTION_RECORD *rec, CONTEXT *context )
{
if (rec->ExceptionFlags & EH_STACK_INVALID)
ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
else if (rec->ExceptionCode == EXCEPTION_NONCONTINUABLE_EXCEPTION)
ERR("Process attempted to continue execution after noncontinuable exception.\n");
else
ERR("Unhandled exception code %lx flags %lx addr %p\n",
rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
/* Should I add here a back trace ? */
TerminateProcess( GetCurrentProcess(), 1 );
}
/*******************************************************************
* EXC_RaiseException
*
* Implementation of NtRaiseException.
*/
static void EXC_RaiseException( EXCEPTION_RECORD *rec, CONTEXT *context )
{
PEXCEPTION_FRAME frame, dispatch, nested_frame;
EXCEPTION_RECORD newrec;
DWORD res;
frame = NtCurrentTeb()->except;
nested_frame = NULL;
while (frame != (PEXCEPTION_FRAME)0xFFFFFFFF)
{
/* Check frame address */
if (((void*)frame < NtCurrentTeb()->stack_low) ||
((void*)(frame+1) > NtCurrentTeb()->stack_top) ||
(int)frame & 3)
{
rec->ExceptionFlags |= EH_STACK_INVALID;
break;
}
/* Call handler */
res = EXC_CallHandler( frame->Handler, EXC_RaiseHandler, rec, frame, context, &dispatch );
if (frame == nested_frame)
{
/* no longer nested */
nested_frame = NULL;
rec->ExceptionFlags &= ~EH_NESTED_CALL;
}
switch(res)
{
case ExceptionContinueExecution:
if (!(rec->ExceptionFlags & EH_NONCONTINUABLE)) return;
newrec.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
newrec.ExceptionFlags = EH_NONCONTINUABLE;
newrec.ExceptionRecord = rec;
newrec.NumberParameters = 0;
RtlRaiseException( &newrec ); /* never returns */
break;
case ExceptionContinueSearch:
break;
case ExceptionNestedException:
if (nested_frame < dispatch) nested_frame = dispatch;
rec->ExceptionFlags |= EH_NESTED_CALL;
break;
default:
newrec.ExceptionCode = STATUS_INVALID_DISPOSITION;
newrec.ExceptionFlags = EH_NONCONTINUABLE;
newrec.ExceptionRecord = rec;
newrec.NumberParameters = 0;
RtlRaiseException( &newrec ); /* never returns */
break;
}
frame = frame->Prev;
}
EXC_DefaultHandling( rec, context );
}
/*******************************************************************
* EXC_RtlUnwind
*
* Implementation of RtlUnwind.
*/
static void EXC_RtlUnwind( EXCEPTION_FRAME *pEndFrame, EXCEPTION_RECORD *pRecord,
CONTEXT *context )
{
EXCEPTION_RECORD record, newrec;
PEXCEPTION_FRAME frame, dispatch;
/* build an exception record, if we do not have one */
if (!pRecord)
{
record.ExceptionCode = STATUS_UNWIND;
record.ExceptionFlags = 0;
record.ExceptionRecord = NULL;
record.ExceptionAddress = (LPVOID)EIP_reg(context);
record.NumberParameters = 0;
pRecord = &record;
}
pRecord->ExceptionFlags |= EH_UNWINDING | (pEndFrame ? 0 : EH_EXIT_UNWIND);
/* get chain of exception frames */
frame = NtCurrentTeb()->except;
while ((frame != (PEXCEPTION_FRAME)0xffffffff) && (frame != pEndFrame))
{
/* Check frame address */
if (pEndFrame && (frame > pEndFrame))
{
newrec.ExceptionCode = STATUS_INVALID_UNWIND_TARGET;
newrec.ExceptionFlags = EH_NONCONTINUABLE;
newrec.ExceptionRecord = pRecord;
newrec.NumberParameters = 0;
RtlRaiseException( &newrec ); /* never returns */
}
if (((void*)frame < NtCurrentTeb()->stack_low) ||
((void*)(frame+1) > NtCurrentTeb()->stack_top) ||
(int)frame & 3)
{
newrec.ExceptionCode = STATUS_BAD_STACK;
newrec.ExceptionFlags = EH_NONCONTINUABLE;
newrec.ExceptionRecord = pRecord;
newrec.NumberParameters = 0;
RtlRaiseException( &newrec ); /* never returns */
}
/* Call handler */
switch(EXC_CallHandler( frame->Handler, EXC_UnwindHandler, pRecord,
frame, context, &dispatch ))
{
case ExceptionContinueSearch:
break;
case ExceptionCollidedUnwind:
frame = dispatch;
break;
default:
newrec.ExceptionCode = STATUS_INVALID_DISPOSITION;
newrec.ExceptionFlags = EH_NONCONTINUABLE;
newrec.ExceptionRecord = pRecord;
newrec.NumberParameters = 0;
RtlRaiseException( &newrec ); /* never returns */
break;
}
NtCurrentTeb()->except = frame = frame->Prev;
}
}
/*******************************************************************
* NtRaiseException (NTDLL.175)
*
* Real prototype:
* DWORD WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *ctx, BOOL first );
*/
REGS_ENTRYPOINT(NtRaiseException)
{
DWORD ret;
EXCEPTION_RECORD *rec;
CONTEXT *ctx;
BOOL first;
ret = STACK32_POP(context); /* return addr */
rec = (PEXCEPTION_RECORD)STACK32_POP(context);
ctx = (PCONTEXT)STACK32_POP(context);
first = (BOOL)STACK32_POP(context);
STACK32_PUSH(context,ret); /* restore return addr */
EXC_RaiseException( rec, context );
*context = *ctx;
}
/***********************************************************************
* RtlRaiseException (NTDLL.464)
*
* Real prototype:
* void WINAPI RtlRaiseException(PEXCEPTION_RECORD pRecord)
*/
REGS_ENTRYPOINT(RtlRaiseException)
{
EXCEPTION_RECORD *rec;
DWORD ret;
ret = STACK32_POP(context); /* return addr */
rec = (PEXCEPTION_RECORD)STACK32_POP(context);
STACK32_PUSH(context,ret); /* restore return addr */
rec->ExceptionAddress = (LPVOID)EIP_reg(context);
EXC_RaiseException( rec, context );
}
/*******************************************************************
* RtlUnwind (KERNEL32.590) (NTDLL.518)
*
* This function is undocumented. This is the general idea of
* RtlUnwind, though. Note that error handling is not yet implemented.
*
* The real prototype is:
* void WINAPI RtlUnwind( PEXCEPTION_FRAME pEndFrame, LPVOID unusedEip,
* PEXCEPTION_RECORD pRecord, DWORD returnEax );
*/
REGS_ENTRYPOINT(RtlUnwind)
{
PEXCEPTION_FRAME pEndFrame;
PEXCEPTION_RECORD pRecord;
/* get the arguments from the stack */
DWORD ret = STACK32_POP(context); /* return addr */
pEndFrame = (PEXCEPTION_FRAME)STACK32_POP(context);
(void)STACK32_POP(context); /* unused arg */
pRecord = (PEXCEPTION_RECORD)STACK32_POP(context);
EAX_reg(context) = STACK32_POP(context);
STACK32_PUSH(context,ret); /* restore return addr */
EXC_RtlUnwind( pEndFrame, pRecord, context );
}
/***********************************************************************
* RtlRaiseStatus (NTDLL.465)
*
* Raise an exception with ExceptionCode = status
*/
void WINAPI RtlRaiseStatus( NTSTATUS status )
{
EXCEPTION_RECORD ExceptionRec;
ExceptionRec.ExceptionCode = status;
ExceptionRec.ExceptionFlags = EH_NONCONTINUABLE;
ExceptionRec.ExceptionRecord = NULL;
ExceptionRec.NumberParameters = 0;
RtlRaiseException( &ExceptionRec );
}
...@@ -283,15 +283,7 @@ void __cdecl DbgPrint(LPCSTR fmt,LPVOID args) { ...@@ -283,15 +283,7 @@ void __cdecl DbgPrint(LPCSTR fmt,LPVOID args) {
MSG("DbgPrint says: %s",buf); MSG("DbgPrint says: %s",buf);
/* hmm, raise exception? */ /* hmm, raise exception? */
} }
DWORD NtRaiseException ( DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments,CONST ULONG_PTR *lpArguments)
{ FIXME(ntdll,"0x%08lx 0x%08lx 0x%08lx %p\n", dwExceptionCode, dwExceptionFlags, nNumberOfArguments, lpArguments);
return 0;
}
DWORD RtlRaiseException ( DWORD x)
{ FIXME(ntdll, "0x%08lx\n", x);
return 0;
}
/****************************************************************************** /******************************************************************************
* RtlAcquirePebLock [NTDLL] * RtlAcquirePebLock [NTDLL]
*/ */
......
...@@ -122,50 +122,51 @@ int dbch_resource = 110; ...@@ -122,50 +122,51 @@ int dbch_resource = 110;
int dbch_scroll = 111; int dbch_scroll = 111;
int dbch_security = 112; int dbch_security = 112;
int dbch_segment = 113; int dbch_segment = 113;
int dbch_selector = 114; int dbch_seh = 114;
int dbch_sem = 115; int dbch_selector = 115;
int dbch_sendmsg = 116; int dbch_sem = 116;
int dbch_server = 117; int dbch_sendmsg = 117;
int dbch_shell = 118; int dbch_server = 118;
int dbch_shm = 119; int dbch_shell = 119;
int dbch_snoop = 120; int dbch_shm = 120;
int dbch_sound = 121; int dbch_snoop = 121;
int dbch_static = 122; int dbch_sound = 122;
int dbch_statusbar = 123; int dbch_static = 123;
int dbch_storage = 124; int dbch_statusbar = 124;
int dbch_stress = 125; int dbch_storage = 125;
int dbch_string = 126; int dbch_stress = 126;
int dbch_syscolor = 127; int dbch_string = 127;
int dbch_system = 128; int dbch_syscolor = 128;
int dbch_tab = 129; int dbch_system = 129;
int dbch_tapi = 130; int dbch_tab = 130;
int dbch_task = 131; int dbch_tapi = 131;
int dbch_text = 132; int dbch_task = 132;
int dbch_thread = 133; int dbch_text = 133;
int dbch_thunk = 134; int dbch_thread = 134;
int dbch_timer = 135; int dbch_thunk = 135;
int dbch_toolbar = 136; int dbch_timer = 136;
int dbch_toolhelp = 137; int dbch_toolbar = 137;
int dbch_tooltips = 138; int dbch_toolhelp = 138;
int dbch_trackbar = 139; int dbch_tooltips = 139;
int dbch_treeview = 140; int dbch_trackbar = 140;
int dbch_ttydrv = 141; int dbch_treeview = 141;
int dbch_tweak = 142; int dbch_ttydrv = 142;
int dbch_updown = 143; int dbch_tweak = 143;
int dbch_ver = 144; int dbch_updown = 144;
int dbch_virtual = 145; int dbch_ver = 145;
int dbch_vxd = 146; int dbch_virtual = 146;
int dbch_wave = 147; int dbch_vxd = 147;
int dbch_win = 148; int dbch_wave = 148;
int dbch_win16drv = 149; int dbch_win = 149;
int dbch_win32 = 150; int dbch_win16drv = 150;
int dbch_wing = 151; int dbch_win32 = 151;
int dbch_winsock = 152; int dbch_wing = 152;
int dbch_wnet = 153; int dbch_winsock = 153;
int dbch_x11 = 154; int dbch_wnet = 154;
int dbch_x11drv = 155; int dbch_x11 = 155;
int dbch_x11drv = 156;
#define DEBUG_CHANNEL_COUNT 156 #define DEBUG_CHANNEL_COUNT 157
char __debug_msg_enabled[DEBUG_CHANNEL_COUNT][DEBUG_CLASS_COUNT] = { char __debug_msg_enabled[DEBUG_CHANNEL_COUNT][DEBUG_CLASS_COUNT] = {
{1, 1, 0, 0}, {1, 1, 0, 0},
...@@ -323,6 +324,7 @@ char __debug_msg_enabled[DEBUG_CHANNEL_COUNT][DEBUG_CLASS_COUNT] = { ...@@ -323,6 +324,7 @@ char __debug_msg_enabled[DEBUG_CHANNEL_COUNT][DEBUG_CLASS_COUNT] = {
{1, 1, 0, 0}, {1, 1, 0, 0},
{1, 1, 0, 0}, {1, 1, 0, 0},
{1, 1, 0, 0}, {1, 1, 0, 0},
{1, 1, 0, 0},
{1, 1, 0, 0} {1, 1, 0, 0}
}; };
...@@ -441,6 +443,7 @@ const char * const debug_ch_name[DEBUG_CHANNEL_COUNT] = { ...@@ -441,6 +443,7 @@ const char * const debug_ch_name[DEBUG_CHANNEL_COUNT] = {
"scroll", "scroll",
"security", "security",
"segment", "segment",
"seh",
"selector", "selector",
"sem", "sem",
"sendmsg", "sendmsg",
......
/* /*
* except.h * except.h
* Copyright (c) 1996, Onno Hovers (onno@stack.urc.tue.nl) * Copyright (c) 1996 Onno Hovers (onno@stack.urc.tue.nl)
* Copyright (c) 1999 Alexandre Julliard
*/ */
#ifndef __WINE_EXCEPT_H #ifndef __WINE_EXCEPT_H
#define __WINE_EXCEPT_H #define __WINE_EXCEPT_H
#include <setjmp.h>
#include "winnt.h" #include "winnt.h"
#include "thread.h"
/* /*
* the function pointer to a exception handler * the function pointer to a exception handler
...@@ -18,7 +21,7 @@ struct __EXCEPTION_FRAME; ...@@ -18,7 +21,7 @@ struct __EXCEPTION_FRAME;
typedef DWORD (CALLBACK *PEXCEPTION_HANDLER)( PEXCEPTION_RECORD pexcrec, typedef DWORD (CALLBACK *PEXCEPTION_HANDLER)( PEXCEPTION_RECORD pexcrec,
struct __EXCEPTION_FRAME *pestframe, struct __EXCEPTION_FRAME *pestframe,
PCONTEXT pcontext, PCONTEXT pcontext,
LPVOID pdispatcher); struct __EXCEPTION_FRAME **pdispatcher);
/* /*
* The exception frame, used for registering exception handlers * The exception frame, used for registering exception handlers
...@@ -33,22 +36,20 @@ typedef struct __EXCEPTION_FRAME ...@@ -33,22 +36,20 @@ typedef struct __EXCEPTION_FRAME
} EXCEPTION_FRAME, *PEXCEPTION_FRAME; } EXCEPTION_FRAME, *PEXCEPTION_FRAME;
/* void WINAPI RtlUnwind(PEXCEPTION_FRAME,LPVOID,PEXCEPTION_RECORD,DWORD);
* this undocumented function is called when an exception
* handler wants all the frames to be unwound. RtlUnwind static inline EXCEPTION_FRAME *EXC_push_frame( EXCEPTION_FRAME *frame )
* calls all exception handlers with the EH_UNWIND or {
* EH_EXIT_UNWIND flags set in the exception record TEB * teb = NtCurrentTeb();
* frame->Prev = teb->except;
* This prototype assumes RtlUnwind takes the same teb->except = frame;
* parameters as OS/2 2.0 DosUnwindException return frame;
* Disassembling RtlUnwind shows this is true, except for }
* the TargetEIP parameter, which is unused. There is
* a fourth parameter, that is used as the eax in the static inline EXCEPTION_FRAME *EXC_pop_frame( EXCEPTION_FRAME *frame )
* context. {
*/ NtCurrentTeb()->except = frame->Prev;
void WINAPI RtlUnwind( PEXCEPTION_FRAME pestframe, return frame->Prev;
LPVOID unusedEIP, }
PEXCEPTION_RECORD pexcrec,
DWORD contextEAX );
#endif /* __WINE_EXCEPT_H */ #endif /* __WINE_EXCEPT_H */
...@@ -573,8 +573,8 @@ BOOLEAN WINAPI RtlFreeHeap( ...@@ -573,8 +573,8 @@ BOOLEAN WINAPI RtlFreeHeap(
* misc * misc
*/ */
void __cdecl DbgPrint(LPCSTR fmt,LPVOID args); void __cdecl DbgPrint(LPCSTR fmt,LPVOID args);
DWORD NtRaiseException ( DWORD dwExceptionCode, DWORD dwExceptionFlags, DWORD nNumberOfArguments,CONST ULONG_PTR *lpArguments); DWORD WINAPI NtRaiseException(PEXCEPTION_RECORD,PCONTEXT,BOOL);
DWORD RtlRaiseException ( DWORD x); void WINAPI RtlRaiseException(PEXCEPTION_RECORD);
VOID WINAPI RtlAcquirePebLock(void); VOID WINAPI RtlAcquirePebLock(void);
VOID WINAPI RtlReleasePebLock(void); VOID WINAPI RtlReleasePebLock(void);
DWORD WINAPI RtlAdjustPrivilege(DWORD x1,DWORD x2,DWORD x3,DWORD x4); DWORD WINAPI RtlAdjustPrivilege(DWORD x1,DWORD x2,DWORD x3,DWORD x4);
......
...@@ -12,11 +12,12 @@ ...@@ -12,11 +12,12 @@
#include "selectors.h" /* for SET_FS */ #include "selectors.h" /* for SET_FS */
struct _PDB; struct _PDB;
struct __EXCEPTION_FRAME;
/* Thread exception block */ /* Thread exception block */
typedef struct _TEB typedef struct _TEB
{ {
void *except; /* 00 Head of exception handling chain */ struct __EXCEPTION_FRAME *except; /* 00 Head of exception handling chain */
void *stack_top; /* 04 Top of thread stack */ void *stack_top; /* 04 Top of thread stack */
void *stack_low; /* 08 Stack low-water mark */ void *stack_low; /* 08 Stack low-water mark */
HTASK16 htask16; /* 0c Win16 task handle */ HTASK16 htask16; /* 0c Win16 task handle */
......
...@@ -992,42 +992,30 @@ typedef DWORD (WINAPI *LPPROGRESS_ROUTINE)(LARGE_INTEGER, LARGE_INTEGER, LARGE_I ...@@ -992,42 +992,30 @@ typedef DWORD (WINAPI *LPPROGRESS_ROUTINE)(LARGE_INTEGER, LARGE_INTEGER, LARGE_I
#define FS_CASE_IS_PRESERVED FILE_CASE_PRESERVED_NAMES #define FS_CASE_IS_PRESERVED FILE_CASE_PRESERVED_NAMES
#define FS_UNICODE_STORED_ON_DISK FILE_UNICODE_ON_DISK #define FS_UNICODE_STORED_ON_DISK FILE_UNICODE_ON_DISK
#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION
#define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT
#define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT
#define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP
#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED
#define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND
#define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO
#define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT
#define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION
#define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW
#define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK
#define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW
#define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO
#define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW
#define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION
#define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR
#define EXCEPTION_ILLEGAL_INSTRUCTION STATUS_ILLEGAL_INSTRUCTION
#define EXCEPTION_NONCONTINUABLE_EXCEPTION STATUS_NONCONTINUABLE_EXCEPTION
#define EXCEPTION_STACK_OVERFLOW STATUS_STACK_OVERFLOW
#define EXCEPTION_INVALID_DISPOSITION STATUS_INVALID_DISPOSITION
#define EXCEPTION_GUARD_PAGE STATUS_GUARD_PAGE_VIOLATION
#define EXCEPTION_INVALID_HANDLE STATUS_INVALID_HANDLE
#define CONTROL_C_EXIT STATUS_CONTROL_C_EXIT
#define STATUS_SUCCESS 0x00000000
#define STATUS_WAIT_0 0x00000000
#define STATUS_ABANDONED_WAIT_0 0x00000080
#define STATUS_USER_APC 0x000000C0
#define STATUS_TIMEOUT 0x00000102
#define STATUS_PENDING 0x00000103
#define STATUS_GUARD_PAGE_VIOLATION 0x80000001
#define STATUS_DATATYPE_MISALIGNMENT 0x80000002
#define STATUS_BREAKPOINT 0x80000003
#define STATUS_SINGLE_STEP 0x80000004
#define STATUS_BUFFER_OVERFLOW 0x80000005
#define STATUS_ACCESS_VIOLATION 0xC0000005
#define STATUS_IN_PAGE_ERROR 0xC0000006
#define STATUS_INVALID_PARAMETER 0xC000000D
#define STATUS_NO_MEMORY 0xC0000017
#define STATUS_ILLEGAL_INSTRUCTION 0xC000001D
#define STATUS_BUFFER_TOO_SMALL 0xC0000023
#define STATUS_NONCONTINUABLE_EXCEPTION 0xC0000025
#define STATUS_INVALID_DISPOSITION 0xC0000026
#define STATUS_UNKNOWN_REVISION 0xC0000058
#define STATUS_INVALID_SECURITY_DESCR 0xC0000079
#define STATUS_ARRAY_BOUNDS_EXCEEDED 0xC000008C
#define STATUS_FLOAT_DENORMAL_OPERAND 0xC000008D
#define STATUS_FLOAT_DIVIDE_BY_ZERO 0xC000008E
#define STATUS_FLOAT_INEXACT_RESULT 0xC000008F
#define STATUS_FLOAT_INVALID_OPERATION 0xC0000090
#define STATUS_FLOAT_OVERFLOW 0xC0000091
#define STATUS_FLOAT_STACK_CHECK 0xC0000092
#define STATUS_FLOAT_UNDERFLOW 0xC0000093
#define STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094
#define STATUS_INTEGER_OVERFLOW 0xC0000095
#define STATUS_PRIVILEGED_INSTRUCTION 0xC0000096
#define STATUS_INVALID_PARAMETER_2 0xC00000F0
#define STATUS_STACK_OVERFLOW 0xC00000FD
#define STATUS_CONTROL_C_EXIT 0xC000013A
#define DUPLICATE_CLOSE_SOURCE 0x00000001 #define DUPLICATE_CLOSE_SOURCE 0x00000001
#define DUPLICATE_SAME_ACCESS 0x00000002 #define DUPLICATE_SAME_ACCESS 0x00000002
...@@ -1046,29 +1034,6 @@ typedef DWORD (WINAPI *LPPROGRESS_ROUTINE)(LARGE_INTEGER, LARGE_INTEGER, LARGE_I ...@@ -1046,29 +1034,6 @@ typedef DWORD (WINAPI *LPPROGRESS_ROUTINE)(LARGE_INTEGER, LARGE_INTEGER, LARGE_I
#define THREAD_PRIORITY_TIME_CRITICAL THREAD_BASE_PRIORITY_LOWRT #define THREAD_PRIORITY_TIME_CRITICAL THREAD_BASE_PRIORITY_LOWRT
#define THREAD_PRIORITY_IDLE THREAD_BASE_PRIORITY_IDLE #define THREAD_PRIORITY_IDLE THREAD_BASE_PRIORITY_IDLE
typedef struct
{
int type;
} wine_exception;
typedef struct
{
int pad[39];
int edi;
int esi;
int ebx;
int edx;
int ecx;
int eax;
int ebp;
int eip;
int cs;
int eflags;
int esp;
int ss;
} exception_info;
/* Could this type be considered opaque? */ /* Could this type be considered opaque? */
typedef struct { typedef struct {
LPVOID DebugInfo; LPVOID DebugInfo;
......
...@@ -216,20 +216,32 @@ typedef HANDLE *PHANDLE; ...@@ -216,20 +216,32 @@ typedef HANDLE *PHANDLE;
* Exception codes * Exception codes
*/ */
#define STATUS_SUCCESS 0x00000000
#define STATUS_WAIT_0 0x00000000 #define STATUS_WAIT_0 0x00000000
#define STATUS_ABANDONED_WAIT_0 0x00000080 #define STATUS_ABANDONED_WAIT_0 0x00000080
#define STATUS_USER_APC 0x000000C0 #define STATUS_USER_APC 0x000000C0
#define STATUS_TIMEOUT 0x00000102 #define STATUS_TIMEOUT 0x00000102
#define STATUS_PENDING 0x00000103 #define STATUS_PENDING 0x00000103
#define STATUS_GUARD_PAGE_VIOLATION 0x80000001
#define STATUS_DATATYPE_MISALIGNMENT 0x80000002 #define STATUS_DATATYPE_MISALIGNMENT 0x80000002
#define STATUS_BREAKPOINT 0x80000003 #define STATUS_BREAKPOINT 0x80000003
#define STATUS_SINGLE_STEP 0x80000004 #define STATUS_SINGLE_STEP 0x80000004
#define STATUS_BUFFER_OVERFLOW 0x80000005
#define STATUS_UNSUCCESSFUL 0xC0000001
#define STATUS_ACCESS_VIOLATION 0xC0000005 #define STATUS_ACCESS_VIOLATION 0xC0000005
#define STATUS_IN_PAGE_ERROR 0xC0000006 #define STATUS_IN_PAGE_ERROR 0xC0000006
#define STATUS_INVALID_PARAMETER 0xC000000D
#define STATUS_NO_MEMORY 0xC0000017 #define STATUS_NO_MEMORY 0xC0000017
#define STATUS_CONFLICTING_ADDRESSES 0xC0000018
#define STATUS_ILLEGAL_INSTRUCTION 0xC000001D #define STATUS_ILLEGAL_INSTRUCTION 0xC000001D
#define STATUS_BUFFER_TOO_SMALL 0xC0000023
#define STATUS_NONCONTINUABLE_EXCEPTION 0xC0000025 #define STATUS_NONCONTINUABLE_EXCEPTION 0xC0000025
#define STATUS_INVALID_DISPOSITION 0xC0000026 #define STATUS_INVALID_DISPOSITION 0xC0000026
#define STATUS_UNWIND 0xC0000027
#define STATUS_BAD_STACK 0xC0000028
#define STATUS_INVALID_UNWIND_TARGET 0xC0000029
#define STATUS_UNKNOWN_REVISION 0xC0000058
#define STATUS_INVALID_SECURITY_DESCR 0xC0000079
#define STATUS_ARRAY_BOUNDS_EXCEEDED 0xC000008C #define STATUS_ARRAY_BOUNDS_EXCEEDED 0xC000008C
#define STATUS_FLOAT_DENORMAL_OPERAND 0xC000008D #define STATUS_FLOAT_DENORMAL_OPERAND 0xC000008D
#define STATUS_FLOAT_DIVIDE_BY_ZERO 0xC000008E #define STATUS_FLOAT_DIVIDE_BY_ZERO 0xC000008E
...@@ -241,33 +253,10 @@ typedef HANDLE *PHANDLE; ...@@ -241,33 +253,10 @@ typedef HANDLE *PHANDLE;
#define STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094 #define STATUS_INTEGER_DIVIDE_BY_ZERO 0xC0000094
#define STATUS_INTEGER_OVERFLOW 0xC0000095 #define STATUS_INTEGER_OVERFLOW 0xC0000095
#define STATUS_PRIVILEGED_INSTRUCTION 0xC0000096 #define STATUS_PRIVILEGED_INSTRUCTION 0xC0000096
#define STATUS_INVALID_PARAMETER_2 0xC00000F0
#define STATUS_STACK_OVERFLOW 0xC00000FD #define STATUS_STACK_OVERFLOW 0xC00000FD
#define STATUS_CONTROL_C_EXIT 0xC000013A #define STATUS_CONTROL_C_EXIT 0xC000013A
#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION
#define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT
#define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT
#define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP
#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED
#define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND
#define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO
#define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT
#define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION
#define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW
#define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK
#define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW
#define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO
#define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW
#define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION
#define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR
#define EXCEPTION_ILLEGAL_INSTRUCTION STATUS_ILLEGAL_INSTRUCTION
#define EXCEPTION_NONCONTINUABLE_EXCEPTION STATUS_NONCONTINUABLE_EXCEPTION
#define EXCEPTION_STACK_OVERFLOW STATUS_STACK_OVERFLOW
#define EXCEPTION_INVALID_DISPOSITION STATUS_INVALID_DISPOSITION
#define EXCEPTION_GUARD_PAGE STATUS_GUARD_PAGE_VIOLATION
#define EXCEPTION_INVALID_HANDLE STATUS_INVALID_HANDLE
#define CONTROL_C_EXIT STATUS_CONTROL_C_EXIT
#define MAXIMUM_WAIT_OBJECTS 64 #define MAXIMUM_WAIT_OBJECTS 64
#define MAXIMUM_SUSPEND_COUNT 127 #define MAXIMUM_SUSPEND_COUNT 127
......
...@@ -582,7 +582,7 @@ init MAIN_KernelInit ...@@ -582,7 +582,7 @@ init MAIN_KernelInit
564 stdcall QueryPerformanceCounter(ptr) QueryPerformanceCounter 564 stdcall QueryPerformanceCounter(ptr) QueryPerformanceCounter
565 stdcall QueryPerformanceFrequency(ptr) QueryPerformanceFrequency 565 stdcall QueryPerformanceFrequency(ptr) QueryPerformanceFrequency
566 stdcall QueueUserAPC(ptr long long) QueueUserAPC 566 stdcall QueueUserAPC(ptr long long) QueueUserAPC
567 register RaiseException() RaiseException 567 stdcall RaiseException(long long long ptr) RaiseException
568 stdcall ReadConsoleA(long ptr long ptr ptr) ReadConsoleA 568 stdcall ReadConsoleA(long ptr long ptr ptr) ReadConsoleA
569 stdcall ReadConsoleInputA(long ptr long ptr) ReadConsoleInputA 569 stdcall ReadConsoleInputA(long ptr long ptr) ReadConsoleInputA
570 stdcall ReadConsoleInputW(long ptr long ptr) ReadConsoleInputW 570 stdcall ReadConsoleInputW(long ptr long ptr) ReadConsoleInputW
......
...@@ -180,7 +180,7 @@ type win32 ...@@ -180,7 +180,7 @@ type win32
172 stdcall NtQueryValueKey(long long long long long long) NtQueryValueKey 172 stdcall NtQueryValueKey(long long long long long long) NtQueryValueKey
173 stub NtQueryVirtualMemory 173 stub NtQueryVirtualMemory
174 stub NtQueryVolumeInformationFile 174 stub NtQueryVolumeInformationFile
175 stdcall NtRaiseException(long long long ptr) NtRaiseException 175 register NtRaiseException() NtRaiseException
176 stub NtRaiseHardError 176 stub NtRaiseHardError
177 stdcall NtReadFile(long long long long long long long long long) NtReadFile 177 stdcall NtReadFile(long long long long long long long long long) NtReadFile
178 stub NtReadRequestData 178 stub NtReadRequestData
...@@ -469,8 +469,8 @@ type win32 ...@@ -469,8 +469,8 @@ type win32
461 stub RtlQuerySecurityObject 461 stub RtlQuerySecurityObject
462 stub RtlQueryTagHeap 462 stub RtlQueryTagHeap
463 stub RtlQueryTimeZoneInformation 463 stub RtlQueryTimeZoneInformation
464 stdcall RtlRaiseException (long) RtlRaiseException 464 register RtlRaiseException() RtlRaiseException
465 stub RtlRaiseStatus 465 stdcall RtlRaiseStatus(long) RtlRaiseStatus
466 stub RtlRandom 466 stub RtlRandom
467 stub RtlReAllocateHeap 467 stub RtlReAllocateHeap
468 stub RtlRealPredecessor 468 stub RtlRealPredecessor
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* Win32 exception functions * Win32 exception functions
* *
* Copyright (c) 1996 Onno Hovers, (onno@stack.urc.tue.nl) * Copyright (c) 1996 Onno Hovers, (onno@stack.urc.tue.nl)
* Copyright (c) 1999 Alexandre Julliard
* *
* Notes: * Notes:
* What really happens behind the scenes of those new * What really happens behind the scenes of those new
...@@ -41,152 +42,31 @@ ...@@ -41,152 +42,31 @@
#include "except.h" #include "except.h"
#include "stackframe.h" #include "stackframe.h"
DECLARE_DEBUG_CHANNEL(relay) DEFAULT_DEBUG_CHANNEL(seh)
DECLARE_DEBUG_CHANNEL(win32)
#define TEB_EXCEPTION_FRAME(pcontext) \
((PEXCEPTION_FRAME)((TEB *)GET_SEL_BASE((pcontext)->SegFs))->except)
/*******************************************************************
* RtlUnwind (KERNEL32.443)
*
* This function is undocumented. This is the general idea of
* RtlUnwind, though. Note that error handling is not yet implemented.
*
* The real prototype is:
* void WINAPI EXC_RtlUnwind( PEXCEPTION_FRAME pEndFrame, LPVOID unusedEip,
* PEXCEPTION_RECORD pRecord, DWORD returnEax );
*/
REGS_ENTRYPOINT(RtlUnwind)
{
EXCEPTION_RECORD record;
DWORD dispatch;
int retval;
PEXCEPTION_FRAME pEndFrame;
PEXCEPTION_RECORD pRecord;
/* get the arguments from the stack */
DWORD ret = STACK32_POP(context); /* return addr */
pEndFrame = (PEXCEPTION_FRAME)STACK32_POP(context);
(void)STACK32_POP(context); /* unused arg */
pRecord = (PEXCEPTION_RECORD)STACK32_POP(context);
EAX_reg(context) = STACK32_POP(context);
STACK32_PUSH(context,ret); /* restore return addr */
/* build an exception record, if we do not have one */
if(!pRecord)
{
record.ExceptionCode = STATUS_INVALID_DISPOSITION;
record.ExceptionFlags = 0;
record.ExceptionRecord = NULL;
record.ExceptionAddress = (LPVOID)EIP_reg(context);
record.NumberParameters = 0;
pRecord = &record;
}
if(pEndFrame)
pRecord->ExceptionFlags|=EH_UNWINDING;
else
pRecord->ExceptionFlags|=EH_UNWINDING | EH_EXIT_UNWIND;
/* get chain of exception frames */
while ((TEB_EXCEPTION_FRAME(context) != NULL) &&
(TEB_EXCEPTION_FRAME(context) != ((void *)0xffffffff)) &&
(TEB_EXCEPTION_FRAME(context) != pEndFrame))
{
TRACE_(win32)("calling exception handler at 0x%x\n",
(int)TEB_EXCEPTION_FRAME(context)->Handler );
dispatch=0;
retval = TEB_EXCEPTION_FRAME(context)->Handler( pRecord,
TEB_EXCEPTION_FRAME(context),
context, &dispatch);
TRACE_(win32)("exception handler returns 0x%x, dispatch=0x%x\n",
retval, (int) dispatch);
if ( (retval == ExceptionCollidedUnwind) &&
(TEB_EXCEPTION_FRAME(context) != (LPVOID)dispatch)
)
TEB_EXCEPTION_FRAME(context) = (LPVOID)dispatch;
else if ( (TEB_EXCEPTION_FRAME(context) != pEndFrame) &&
(TEB_EXCEPTION_FRAME(context) != TEB_EXCEPTION_FRAME(context)->Prev)
)
TEB_EXCEPTION_FRAME(context) = TEB_EXCEPTION_FRAME(context)->Prev;
else
break;
}
}
/******************************************************************* /*******************************************************************
* RaiseException (KERNEL32.418) * RaiseException (KERNEL32.418)
*
* The real prototype is:
* void WINAPI EXC_RaiseException(DWORD dwExceptionCode,
* DWORD dwExceptionFlags,
* DWORD cArguments,
* const LPDWORD lpArguments );
*/ */
REGS_ENTRYPOINT(RaiseException) void WINAPI RaiseException( DWORD code, DWORD flags, DWORD nbargs, const LPDWORD args )
{ {
PEXCEPTION_FRAME pframe; EXCEPTION_RECORD record;
EXCEPTION_RECORD record;
DWORD dispatch; /* is this used in raising exceptions ?? */
int retval;
int i;
/* Get the arguments from the stack */
DWORD ret = STACK32_POP(context); /* return addr */
DWORD dwExceptionCode = STACK32_POP(context);
DWORD dwExceptionFlags = STACK32_POP(context);
DWORD cArguments = STACK32_POP(context);
const LPDWORD lpArguments = (LPDWORD)STACK32_POP(context);
STACK32_PUSH(context,ret); /* Restore the return address */
/* compose an exception record */ /* Compose an exception record */
record.ExceptionCode = dwExceptionCode; record.ExceptionCode = code;
record.ExceptionFlags = dwExceptionFlags; record.ExceptionFlags = flags & EH_NONCONTINUABLE;
record.ExceptionRecord = NULL; record.ExceptionRecord = NULL;
record.NumberParameters = cArguments; record.ExceptionAddress = RaiseException;
record.ExceptionAddress = (LPVOID)EIP_reg(context); if (nbargs && args)
if (lpArguments) for( i = 0; i < cArguments; i++)
record.ExceptionInformation[i] = lpArguments[i];
/* get chain of exception frames */
retval = ExceptionContinueSearch;
pframe = TEB_EXCEPTION_FRAME( context );
while((pframe!=NULL)&&(pframe!=((void *)0xFFFFFFFF)))
{ {
PEXCEPTION_FRAME prevframe; if (nbargs > EXCEPTION_MAXIMUM_PARAMETERS) nbargs = EXCEPTION_MAXIMUM_PARAMETERS;
TRACE_(win32)("calling exception handler at 0x%x\n", record.NumberParameters = nbargs;
(int) pframe->Handler); memcpy( record.ExceptionInformation, args, nbargs * sizeof(*args) );
dispatch=0; }
TRACE_(relay)("(except=%p,record=%p,frame=%p,context=%p,dispatch=%p)\n", else record.NumberParameters = 0;
pframe->Handler, &record, pframe, context, &dispatch );
prevframe = pframe->Prev;
retval=pframe->Handler(&record,pframe,context,&dispatch);
TRACE_(win32)("exception handler returns 0x%x, dispatch=0x%x\n",
retval, (int) dispatch);
if(retval==ExceptionContinueExecution)
break;
pframe=prevframe;
}
if (retval!=ExceptionContinueExecution) RtlRaiseException( &record );
{
/* FIXME: what should we do here? */
TRACE_(win32)("no handler wanted to handle the exception, exiting\n");
ExitProcess(dwExceptionCode); /* what status should be used here ? */
}
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment