/* 
   Copyright 1994-2003 Free Software Foundation, Inc.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
   USA

   You may contact the author at:

   mailto::camille@bluegrass.net

   or by snail mail at:

   David Lindauer
   850 Washburn Ave Apt 99
   Louisville, KY 40222
*/
#include <windows.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
extern int _win32 ;
static int *_xceptblkptr;
static PCONTEXT xx ;
LONG (* ___cppxcept)(PEXCEPTION_RECORD p, void *record , CONTEXT *context, void *param ) ;

LONG ___cppxceptionhandle(PEXCEPTION_RECORD p, void *record, CONTEXT *context, void *param) ;

static void regdump(char *text, PCONTEXT p)
{
   char buf[1024] ;
      sprintf(buf,"\n%s\n\n",text);
      sprintf(buf+strlen(buf),"CS:EIP %04X:%08X  SS:ESP %04X:%08X\n",p->SegCs,p->Eip,p->SegSs,p->Esp);
      sprintf(buf+strlen(buf),"EAX: %08X  EBX: %08X  ECX: %08X  EDX: %08X  flags: %08X\n",
            p->Eax, p->Ebx, p->Ecx, p->Edx, p->EFlags);
      sprintf(buf+strlen(buf),"EBP: %08X  ESI: %08X  EDI: %08X\n",p->Ebp,p->Esi,p->Edi);
      sprintf(buf+strlen(buf)," DS:     %04X   ES:     %04X   FS:     %04X   GS:     %04X\n",
         p->SegDs,p->SegEs,p->SegFs,p->SegGs);
   if (!_win32) {
      fprintf(stderr,buf) ;
   } else {
      MessageBox(0,buf,text,0) ;
   }
}
void __ll_sigsegv(int aa)
{
   regdump("Access Violation",xx) ;
   _exit(1) ;
}
LONG ___xceptionhandle(PEXCEPTION_RECORD p, void *record, PCONTEXT context, void *param) 
{

   int signum = -1,rv = 1;
   if (p->ExceptionFlags == 2) // unwinding
   		return 1 ;
   if (___cppxcept)
   	(*___cppxcept)(p,record,context,param) ; // won't return if it was a throw raise
   switch(p->ExceptionCode) {
		case EXCEPTION_ACCESS_VIOLATION:
		case EXCEPTION_DATATYPE_MISALIGNMENT:
		case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
		case EXCEPTION_GUARD_PAGE:
			signum = SIGSEGV;
			break ;
//		case EXCEPTION_INVALID_INSTRUCTION:
		case EXCEPTION_PRIV_INSTRUCTION:
			signum = SIGILL;
			break ;
		case EXCEPTION_SINGLE_STEP:
	         return EXCEPTION_CONTINUE_EXECUTION ;
		case EXCEPTION_FLT_DENORMAL_OPERAND:
		case EXCEPTION_FLT_DIVIDE_BY_ZERO:
		case EXCEPTION_FLT_INEXACT_RESULT:
		case EXCEPTION_FLT_INVALID_OPERATION:
		case EXCEPTION_FLT_OVERFLOW:
		case EXCEPTION_FLT_STACK_CHECK:
		case EXCEPTION_FLT_UNDERFLOW:
		case EXCEPTION_INT_DIVIDE_BY_ZERO:
			signum = SIGFPE ;
			break ;
		case EXCEPTION_INT_OVERFLOW:
			break ;
		case EXCEPTION_NONCONTINUABLE_EXCEPTION:
		case EXCEPTION_INVALID_DISPOSITION:
			break ;
		case EXCEPTION_STACK_OVERFLOW:
			break ;
	}
	xx = context ;
	if (signum != -1)
      if (!raise(signum))
         return 0 ; // continue execution

   return 1 ; // continue search
}
void PASCAL __xceptinit(int *block)
{
	asm {
		mov		eax,[block]
		mov		[eax+4],___xceptionhandle
		mov		ecx,fs:[0]
		mov		[eax],ecx
		mov		fs:[0],eax
	} ;
}
void PASCAL __xceptrundown(void)
{
	asm {
		mov	eax,fs:[0]
		cmp	eax,___xceptionhandle // C++ frames should be unloaded by now
		jnz	none				  // this is a sanity check
		mov	eax,[eax]
		mov	fs:[0],eax
none:
	} ;
}
