1996-03-14 19:08:34 +01:00
|
|
|
/*
|
|
|
|
* Win32 exception functions
|
|
|
|
*
|
|
|
|
* Copyright (c) 1996 Onno Hovers, (onno@stack.urc.tue.nl)
|
|
|
|
*
|
|
|
|
* Notes:
|
|
|
|
* What really happens behind the scenes of those new
|
|
|
|
* __try{...}__except(..){....} and
|
|
|
|
* __try{...}__finally{...}
|
|
|
|
* statements is simply not documented by Microsoft. There could be different
|
|
|
|
* reasons for this:
|
|
|
|
* One reason could be that they try to hide the fact that exception
|
|
|
|
* handling in Win32 looks almost the same as in OS/2 2.x.
|
|
|
|
* Another reason could be that Microsoft does not want others to write
|
|
|
|
* binary compatible implementations of the Win32 API (like us).
|
|
|
|
*
|
|
|
|
* Whatever the reason, THIS SUCKS!! Ensuring portabilty or future
|
|
|
|
* compatability may be valid reasons to keep some things undocumented.
|
|
|
|
* But exception handling is so basic to Win32 that it should be
|
|
|
|
* documented!
|
|
|
|
*
|
|
|
|
* Fixmes:
|
|
|
|
* -Most functions need better parameter checking.
|
|
|
|
* -I do not know how to handle exceptions within an exception handler.
|
|
|
|
* or what is done when ExceptionNestedException is returned from an
|
|
|
|
* exception handler
|
|
|
|
* -Real exceptions are not yet implemented. only the exception functions
|
|
|
|
* are implemented. A real implementation needs some new code in
|
|
|
|
* loader/signal.c. There would also be a need for showing debugging
|
|
|
|
* information in UnhandledExceptionFilter.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
1997-02-02 20:01:52 +01:00
|
|
|
#include <assert.h>
|
1996-03-14 19:08:34 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include "windows.h"
|
|
|
|
#include "winerror.h"
|
1997-02-02 20:01:52 +01:00
|
|
|
#include "ldt.h"
|
|
|
|
#include "process.h"
|
|
|
|
#include "thread.h"
|
1996-03-14 19:08:34 +01:00
|
|
|
#include "stddebug.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "except.h"
|
|
|
|
|
1997-02-02 20:01:52 +01:00
|
|
|
#define TEB_EXCEPTION_FRAME(pcontext) \
|
|
|
|
((PEXCEPTION_FRAME)((TEB *)GET_SEL_BASE((pcontext)->SegFs))->except)
|
1996-03-31 18:40:13 +02:00
|
|
|
|
1997-08-24 18:00:30 +02:00
|
|
|
/*******************************************************************
|
|
|
|
* _local_unwind2 (CRTDLL)
|
|
|
|
*/
|
|
|
|
void WINAPI CRTDLL__local_unwind2(PEXCEPTION_FRAME endframe,DWORD nr,
|
|
|
|
PCONTEXT pcontext)
|
|
|
|
{
|
|
|
|
fprintf(stderr,"CRTDLL__local_unwind2(%p,%ld)\n",endframe,nr);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
* _global_unwind2 (CRTDLL)
|
|
|
|
*/
|
|
|
|
void WINAPI CRTDLL__global_unwind2(PEXCEPTION_FRAME endframe,PCONTEXT pcontext)
|
|
|
|
{
|
|
|
|
RtlUnwind(endframe,NULL/*should point to the return;*/,NULL,0,pcontext);
|
|
|
|
return;
|
|
|
|
}
|
1996-03-14 19:08:34 +01:00
|
|
|
|
1997-02-02 20:01:52 +01:00
|
|
|
/*******************************************************************
|
|
|
|
* RtlUnwind (KERNEL32.443)
|
1996-03-14 19:08:34 +01:00
|
|
|
*
|
|
|
|
* This function is undocumented. This is the general idea of
|
1997-02-02 20:01:52 +01:00
|
|
|
* RtlUnwind, though. Note that error handling is not yet implemented.
|
1996-03-14 19:08:34 +01:00
|
|
|
*/
|
1997-08-24 18:00:30 +02:00
|
|
|
void WINAPI RtlUnwind( PEXCEPTION_FRAME pEndFrame, LPVOID unusedEip,
|
|
|
|
PEXCEPTION_RECORD pRecord, DWORD returnEax,
|
|
|
|
PCONTEXT pcontext /* Wine additional parameter */ )
|
1996-03-14 19:08:34 +01:00
|
|
|
{
|
|
|
|
EXCEPTION_RECORD record;
|
|
|
|
DWORD dispatch;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
pcontext->Eax=returnEax;
|
|
|
|
|
|
|
|
/* build an exception record, if we do not have one */
|
|
|
|
if(!pRecord)
|
|
|
|
{
|
1997-02-02 20:01:52 +01:00
|
|
|
record.ExceptionCode = STATUS_INVALID_DISPOSITION;
|
|
|
|
record.ExceptionFlags = 0;
|
|
|
|
record.ExceptionRecord = NULL;
|
|
|
|
record.ExceptionAddress = (LPVOID)pcontext->Eip;
|
|
|
|
record.NumberParameters = 0;
|
|
|
|
pRecord = &record;
|
1996-03-14 19:08:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if(pEndFrame)
|
|
|
|
pRecord->ExceptionFlags|=EH_UNWINDING;
|
|
|
|
else
|
|
|
|
pRecord->ExceptionFlags|=EH_UNWINDING | EH_EXIT_UNWIND;
|
|
|
|
|
|
|
|
/* get chain of exception frames */
|
1997-02-02 20:01:52 +01:00
|
|
|
while ((TEB_EXCEPTION_FRAME(pcontext) != NULL) &&
|
|
|
|
(TEB_EXCEPTION_FRAME(pcontext) != ((void *)0xffffffff)) &&
|
|
|
|
(TEB_EXCEPTION_FRAME(pcontext) != pEndFrame))
|
1996-03-14 19:08:34 +01:00
|
|
|
{
|
1997-02-02 20:01:52 +01:00
|
|
|
dprintf_win32( stddeb, "calling exception handler at 0x%x\n",
|
|
|
|
(int)TEB_EXCEPTION_FRAME(pcontext)->Handler );
|
1996-03-14 19:08:34 +01:00
|
|
|
|
|
|
|
dispatch=0;
|
1997-02-02 20:01:52 +01:00
|
|
|
retval = TEB_EXCEPTION_FRAME(pcontext)->Handler( pRecord,
|
|
|
|
TEB_EXCEPTION_FRAME(pcontext),
|
|
|
|
pcontext, &dispatch);
|
1996-03-14 19:08:34 +01:00
|
|
|
|
|
|
|
dprintf_win32(stddeb,"exception handler returns 0x%x, dispatch=0x%x\n",
|
|
|
|
retval, (int) dispatch);
|
|
|
|
|
1997-08-24 18:00:30 +02:00
|
|
|
if ( (retval == ExceptionCollidedUnwind) &&
|
|
|
|
(TEB_EXCEPTION_FRAME(pcontext) != (LPVOID)dispatch)
|
|
|
|
)
|
1997-02-02 20:01:52 +01:00
|
|
|
TEB_EXCEPTION_FRAME(pcontext) = (LPVOID)dispatch;
|
1997-08-24 18:00:30 +02:00
|
|
|
else if ( (TEB_EXCEPTION_FRAME(pcontext) != pEndFrame) &&
|
|
|
|
(TEB_EXCEPTION_FRAME(pcontext) != TEB_EXCEPTION_FRAME(pcontext)->Prev)
|
|
|
|
)
|
1997-02-02 20:01:52 +01:00
|
|
|
TEB_EXCEPTION_FRAME(pcontext) = TEB_EXCEPTION_FRAME(pcontext)->Prev;
|
1996-03-14 19:08:34 +01:00
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-02-02 20:01:52 +01:00
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
* RaiseException (KERNEL32.418)
|
1996-03-14 19:08:34 +01:00
|
|
|
*/
|
1997-08-24 18:00:30 +02:00
|
|
|
void WINAPI RaiseException(DWORD dwExceptionCode,
|
|
|
|
DWORD dwExceptionFlags,
|
|
|
|
DWORD cArguments,
|
|
|
|
const LPDWORD lpArguments,
|
|
|
|
PCONTEXT pcontext /* Wine additional parameter */ )
|
1996-03-14 19:08:34 +01:00
|
|
|
{
|
|
|
|
PEXCEPTION_FRAME pframe;
|
|
|
|
EXCEPTION_RECORD record;
|
|
|
|
DWORD dispatch; /* is this used in raising exceptions ?? */
|
|
|
|
int retval;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* compose an exception record */
|
|
|
|
|
|
|
|
record.ExceptionCode = dwExceptionCode;
|
|
|
|
record.ExceptionFlags = dwExceptionFlags;
|
|
|
|
record.ExceptionRecord = NULL;
|
|
|
|
record.NumberParameters = cArguments;
|
Release 960611
Tue Jun 11 15:20:43 1996 Alexandre Julliard <julliard@lrc.epfl.ch>
* [debugger/break.c] [loader/signal.c]
Fixed breakpoints in 32-bit code.
* [include/windows.h]
Added many more Win32 versions of standard structures.
* [include/winreg.h] [misc/registry.c]
Moved private types into registry.c.
* [memory/string.c] (New file)
Moved most string functions from misc/lstr.c; added Win32 version
of all functions.
* [misc/wsprintf.c]
Implemented Win32 wsprintf functions.
* [objects/bitmap.c]
Implemented Win32 bitmap functions.
* [windows/dialog.c]
Don't set dialog procedure before the controls are created. This
avoids a crash in Winhelp.
Tue Jun 11 14:10:06 1996 Martin von Loewis <loewis@informatik.hu-berlin.de>
* [controls/menu.c] [if1632/user.spec] [windows/message.c]
Replace PeekMessage with PeekMessage16.
* [if1632/kernel32.spec][misc/main.c]
GetVersion32,GetVersionEx32A,GetVersionEx32W: new functions.
MAIN_ParseVersion: new function, new command line option -winver.
GetVersion: modified to take command line argument into account.
* [if1632/kernel32.spec] [win32/process.c]
FreeLibrary32: new function.
TlsAlloc: initialize Tls to zero.
InterlockedIncrement,InterlockedDecrement,InterlockedExchange: new
functions.
* [if1632/kernel32.spec]
SetErrorMode,GetActiveWindow: new relays to existing functions.
* [if1632/kernel32.spec][win32/user32.c]
PeekMessage32A,PeekMessage32W: new functions.
* [include/struct32.h][include/windows.h]
Moved MSG32 to windows.h.
Renamed MSG to MSG16.
Modified prototypes to use MSG16
* [include/winbase.h]
OSVERSIONINFO32A,OSVERSIONINFO32W: new structures.
Sun Jun 9 20:53:30 1996 Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>
* [if1632/Makefile.in] [loader/builtin.c]
version.dll,lz32.dll added.
* [include/lzexpand.h] [if1632/lz32.spec] [if1632/lzexpand.spec]
[misc/lzexpand.c]
lz32.dll added.
Modified to new function naming standard.
* [include/ver.h] [if1632/ver.spec] [if1632/version.spec] [misc/ver.c]
version.dll added (win32 version of ver.dll).
Modified to new function naming standard.
Use registry to look up a LOCALE langids too.
(VerInstallFile,VerFindFile still stubs)
Fri Jun 7 20:40:20 1996 Albrecht Kleine <kleine@ak.sax.de>
* [files/file.c]
Added a warning if GetTempFileName() gets a bad drive parameter.
* [misc/commdlg.c]
Changed file listbox color to gray in SaveFile dialog
(just like Windows does this).
1996-06-11 18:02:08 +02:00
|
|
|
record.ExceptionAddress = (LPVOID) pcontext->Eip;
|
1996-03-14 19:08:34 +01:00
|
|
|
|
1997-02-02 20:01:52 +01:00
|
|
|
if (lpArguments) for( i = 0; i < cArguments; i++)
|
|
|
|
record.ExceptionInformation[i] = lpArguments[i];
|
1996-03-14 19:08:34 +01:00
|
|
|
|
|
|
|
/* get chain of exception frames */
|
|
|
|
|
1997-02-02 20:01:52 +01:00
|
|
|
retval = ExceptionContinueSearch;
|
|
|
|
pframe = TEB_EXCEPTION_FRAME( pcontext );
|
1996-03-14 19:08:34 +01:00
|
|
|
|
|
|
|
while((pframe!=NULL)&&(pframe!=((void *)0xFFFFFFFF)))
|
|
|
|
{
|
|
|
|
dprintf_win32(stddeb,"calling exception handler at 0x%x\n",
|
|
|
|
(int) pframe->Handler);
|
|
|
|
dispatch=0;
|
|
|
|
retval=pframe->Handler(&record,pframe,pcontext,&dispatch);
|
|
|
|
|
|
|
|
dprintf_win32(stddeb,"exception handler returns 0x%x, dispatch=0x%x\n",
|
|
|
|
retval, (int) dispatch);
|
|
|
|
|
|
|
|
if(retval==ExceptionContinueExecution)
|
|
|
|
break;
|
|
|
|
pframe=pframe->Prev;
|
|
|
|
}
|
|
|
|
|
1997-02-02 20:01:52 +01:00
|
|
|
if (retval!=ExceptionContinueExecution)
|
1996-03-14 19:08:34 +01:00
|
|
|
{
|
1997-02-02 20:01:52 +01:00
|
|
|
/* FIXME: what should we do here? */
|
|
|
|
dprintf_win32(stddeb,"no handler wanted to handle the exception, exiting\n");
|
|
|
|
ExitProcess(dwExceptionCode); /* what status should be used here ? */
|
|
|
|
}
|
1996-03-14 19:08:34 +01:00
|
|
|
}
|
|
|
|
|
1997-02-02 20:01:52 +01:00
|
|
|
|
1996-03-14 19:08:34 +01:00
|
|
|
/*******************************************************************
|
1997-02-02 20:01:52 +01:00
|
|
|
* UnhandledExceptionFilter (KERNEL32.537)
|
1996-03-14 19:08:34 +01:00
|
|
|
*/
|
1997-08-24 18:00:30 +02:00
|
|
|
DWORD WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS epointers)
|
1996-03-14 19:08:34 +01:00
|
|
|
{
|
1997-02-02 20:01:52 +01:00
|
|
|
char message[80];
|
|
|
|
|
|
|
|
/* FIXME: Should check if the process is being debugged */
|
|
|
|
|
|
|
|
if (pCurrentProcess && pCurrentProcess->top_filter)
|
|
|
|
{
|
|
|
|
DWORD ret = pCurrentProcess->top_filter( epointers );
|
|
|
|
if (ret != EXCEPTION_CONTINUE_SEARCH) return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME: Should check the current error mode */
|
|
|
|
|
|
|
|
sprintf( message, "Unhandled exception 0x%08lx at address 0x%08lx.",
|
|
|
|
epointers->ExceptionRecord->ExceptionCode,
|
|
|
|
(DWORD)epointers->ExceptionRecord->ExceptionAddress );
|
|
|
|
MessageBox32A( 0, message, "Error", MB_OK | MB_ICONHAND );
|
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
1996-03-14 19:08:34 +01:00
|
|
|
}
|
|
|
|
|
1997-02-02 20:01:52 +01:00
|
|
|
|
1996-03-14 19:08:34 +01:00
|
|
|
/*************************************************************
|
1997-02-02 20:01:52 +01:00
|
|
|
* SetUnhandledExceptionFilter (KERNEL32.516)
|
1996-03-14 19:08:34 +01:00
|
|
|
*/
|
1997-08-24 18:00:30 +02:00
|
|
|
LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter(
|
1997-02-02 20:01:52 +01:00
|
|
|
LPTOP_LEVEL_EXCEPTION_FILTER filter )
|
|
|
|
{
|
|
|
|
LPTOP_LEVEL_EXCEPTION_FILTER old = pCurrentProcess->top_filter;
|
|
|
|
pCurrentProcess->top_filter = filter;
|
|
|
|
return old;
|
1996-03-14 19:08:34 +01:00
|
|
|
}
|