; $Id: exceptutil.asm,v 1.26 2004-01-20 13:41:11 sandervl Exp $

;/*
; * Project Odin Software License can be found in LICENSE.TXT
; * Win32 Exception handling + misc functions for OS/2
; *
; * Copyright 1998 Sander van Leeuwen
; *
; */
.386p
                NAME    except

DATA32	segment dword use32 public 'DATA'
DATA32	ends
CONST32_RO	segment dword use32 public 'CONST'
CONST32_RO	ends
BSS32	segment dword use32 public 'BSS'
BSS32	ends
DGROUP	group BSS32, DATA32
	assume	cs:FLAT, ds:FLAT, ss:FLAT, es:FLAT

DATA32	segment dword use32 public 'DATA'

CONST32_RO	segment
	align 04h
@CBE8	db "KERNEL32: Calling handle"
db "r at %p code=%lx flags=%"
db "lx",0ah,0h
@CBE9	db "KERNEL32: Handler return"
db "ed %lx",0ah,0h
CONST32_RO	ends
DATA32	ends

CODE32          SEGMENT DWORD PUBLIC USE32 'CODE'


        public  _RaiseException@16
        extrn   _OS2RaiseException : near

_RaiseException@16 proc near

        ; _OS2RaiseException is _cdecl

        push ebp
        mov  ebp, esp
        push eax

        mov  eax, 0
        mov  eax, ss
        push eax
        mov  eax, gs
        push eax
        mov  eax, fs
        push eax
        mov  eax, es
        push eax
        mov  eax, ds
        push eax
        mov  eax, cs
        push cs
        push esi
        push edi
        push edx
        push ecx
        push ebx
        push dword ptr [ebp-4]      ; original eax
        pushfd
        push dword ptr [ebp]        ; original ebp
        push ebp
        add  dword ptr [esp], 4     ; original esp
        push dword ptr [ebp + 4]    ; original eip (return address)

        push dword ptr [ebp + 20]   ; arg 4 (DWORD *lpArguments)
        push dword ptr [ebp + 16]   ; arg 3 (DWORD cArguments)
        push dword ptr [ebp + 12]   ; arg 2 (DWORD dwExceptionFlags)
        push dword ptr [ebp + 8]    ; arg 1 (DWORD dwExceptionCode)

        call _OS2RaiseException

        add esp, 20 * 4

        pop eax
        pop ebp

        ret 16      ;__stdcall

_RaiseException@16 endp


        public  _RtlUnwind@16
        extrn   _OS2RtlUnwind : near

_RtlUnwind@16 proc near

        ; OS2RtlUnwind is _cdecl

        push ebp
        mov  ebp, esp
        push eax

        mov  eax, 0
        mov  eax, ss
        push eax
        mov  eax, gs
        push eax
        mov  eax, fs
        push eax
        mov  eax, es
        push eax
        mov  eax, ds
        push eax
        mov  eax, cs
        push cs
        push esi
        push edi
        push edx
        push ecx
        push ebx
        push dword ptr [ebp-4]      ; original eax
        pushfd
        push dword ptr [ebp]        ; original ebp
        push ebp
        add  dword ptr [esp], 4     ; original esp
        push dword ptr [ebp + 4]    ; original eip (return address)

        push dword ptr [ebp + 20]   ; arg 4 (DWORD returnEax)
        push dword ptr [ebp + 16]   ; arg 3 (PWINEXCEPTION_RECORD pRecord)
        push dword ptr [ebp + 12]   ; arg 2 (LPVOID unusedEip)
        push dword ptr [ebp + 8]    ; arg 1 (PWINEXCEPTION_FRAME pEndFrame)

        call _OS2RtlUnwind

        add esp, 20 * 4

        pop eax
        pop ebp

        ret 16      ;__stdcall

_RtlUnwind@16 endp


        PUBLIC OS2ExceptionHandler
        EXTRN  OS2ExceptionHandler2ndLevel:NEAR

OS2ExceptionHandler proc near
        ;Clear the direction flag (as specified by the _System calling convention)
        ;(OS/2 doesn't bother checking before calling our exception handler)
        cld
        jmp OS2ExceptionHandler2ndLevel
OS2ExceptionHandler endp


        PUBLIC OSLibDispatchException
        EXTRN  OSLibDispatchExceptionWin32:NEAR
        EXTRN  ___seh_handler_filter:NEAR

; BOOL APIENTRY OSLibDispatchException(PEXCEPTIONREPORTRECORD pReportRec,
;                                      PEXCEPTIONREGISTRATIONRECORD pRegistrationRec,
;                                      PCONTEXTRECORD pContextRec, PVOID p,
;                                      BOOL fSEH);
OSLibDispatchException proc near
        cmp dword ptr [esp + 20], 0 ; fSEH == FALSE?
        jz  OSLibDispatchExceptionWin32
        jmp ___seh_handler_filter
OSLibDispatchException endp


        PUBLIC _QueryExceptionChain

_QueryExceptionChain proc near
        mov  eax, fs:[0]
        ret
_QueryExceptionChain endp

        PUBLIC GetExceptionRecord
GetExceptionRecord proc near
        push ebp
        mov  ebp, esp
        push fs
        push ebx

        mov  eax, [ebp+8]
        mov  fs, eax
        mov  ebx, [ebp+12]
        mov  eax, fs:[ebx]

        pop  ebx
        pop  fs
        pop  ebp
        ret
GetExceptionRecord endp

                PUBLIC ChangeTIBStack
ChangeTIBStack proc near
;       xor  eax, eax
        push ebx
        mov  eax, fs:[4]
        mov  ebx, fs:[8]
        add  ebx, 8
        mov  fs:[4], ebx
        mov  fs:[8], eax
        pop  ebx
        ret
ChangeTIBStack endp

        PUBLIC _SetExceptionChain

_SetExceptionChain proc near
        mov eax, dword ptr [esp+4]
        mov fs:[0], eax
        ret
_SetExceptionChain endp


;;ULONG CDECL AsmCallThreadHandler(BOOL fAlignStack, ULONG handler, LPVOID parameter);
        PUBLIC  _AsmCallThreadHandler
_AsmCallThreadHandler proc near
        push	ebp
        mov	ebp, esp

;first check if we have 128kb stack or more; if not, then skip the stack alignment code
        mov     eax, [ebp+8]
        cmp     eax, 0
        je      @goodthreadstack

;We're asking for problems if our stack start near a 64kb boundary
;Some OS/2 thunking procedures can choke if there's not enough stack left
        mov     eax, esp
        and     eax, 0FFFFh
        cmp     eax, 0E000h
        jge     @goodthreadstack

        ;set ESP to the top of the next 64kb block and touch each
        ;page to make sure the guard page exception handler commits
        ;those pages
        mov     edx, esp
        sub     edx, eax

        and     esp, 0FFFFF000h
        dec     esp

@touchthreadstackpages:
        mov     al, byte ptr [esp]

        sub     esp, 1000h

        cmp     esp, edx
        jg      @touchthreadstackpages

        mov     esp, edx
        sub     esp, 16

        ;also touch this page
        mov     eax, dword ptr [esp]

@goodthreadstack:

        mov     eax, esp
        sub     eax, 16
        and     eax, 0FFFFFFF0h
;now we make sure the stack is aligned at 16 bytes when the entrypoint is called
;(8+4+4(return address) = 16)
        add     eax, 8
        mov     esp, eax

        push    dword ptr [ebp+16]
        mov     eax, dword ptr [ebp+12]
        call    eax

        mov     esp, ebp
        pop     ebp
        ret
_AsmCallThreadHandler endp

        PUBLIC _CallEntryPoint
_CallEntryPoint proc near
        push	ebp
        mov	ebp, esp

;We're asking for problems if our stack start near a 64kb boundary
;Some OS/2 thunking procedures can choke if there's not enough stack left
        mov     eax, esp
        and     eax, 0FFFFh
        cmp     eax, 0E000h
        jge     @goodmainstack

        ;set ESP to the top of the next 64kb block and touch each
        ;page to make sure the guard page exception handler commits
        ;those pages
        mov     edx, esp
        sub     edx, eax

        and     esp, 0FFFFF000h
        dec     esp

@touchmainstackpages:
        mov     al, byte ptr [esp]

        sub     esp, 1000h

        cmp     esp, edx
        jg      @touchmainstackpages

        mov     esp, edx
        sub     esp, 16

        ;also touch this page
        mov     eax, dword ptr [esp]

@goodmainstack:

        mov     eax, esp
        sub     eax, 16
        and     eax, 0FFFFFFF0h
;now we make sure the stack is aligned at 16 bytes when the entrypoint is called
;(8+4+4(return address) = 16)
        add     eax, 8
        mov     esp, eax

        push    dword ptr [ebp+12]
        mov     eax, dword ptr [ebp+8]
        call    eax

        mov     esp, ebp
        pop     ebp
        ret
_CallEntryPoint endp

ifndef __EMX__

        EXTRN WriteLog:PROC
        EXTRN _GetThreadTEB@0:PROC
IFDEF DEBUG
        EXTRN _DbgEnabledKERNEL32:DWORD
ENDIF

; 129 static inline WINEXCEPTION_FRAME * EXC_push_frame( WINEXCEPTION_FRAME *frame )
        align 04h

EXC_push_frame	proc
	push	ebp
	mov	ebp,esp
	sub	esp,04h
	mov	[ebp+08h],eax;	frame

; 132     TEB *teb = GetThreadTEB();
	call	_GetThreadTEB@0
	mov	[ebp-04h],eax;	teb

; 133     frame->Prev = (PWINEXCEPTION_FRAME)teb->except;
	mov	ecx,[ebp-04h];	teb
	mov	ecx,[ecx]
	mov	eax,[ebp+08h];	frame
	mov	[eax],ecx

; 134     teb->except = frame;
	mov	eax,[ebp-04h];	teb
	mov	ecx,[ebp+08h];	frame
	mov	[eax],ecx

; 135     return frame->Prev;
	mov	eax,[ebp+08h];	frame
	mov	eax,[eax]
	leave	
	ret	
EXC_push_frame	endp

; 138 static inline WINEXCEPTION_FRAME * EXC_pop_frame( WINEXCEPTION_FRAME *frame )
	align 04h

EXC_pop_frame	proc
	push	ebp
	mov	ebp,esp
	sub	esp,04h
	mov	[ebp+08h],eax;	frame

; 141     TEB *teb = GetThreadTEB();
	call	_GetThreadTEB@0
	mov	[ebp-04h],eax;	teb

; 142     teb->except = frame->Prev;
	mov	ecx,[ebp+08h];	frame
	mov	ecx,[ecx]
	mov	eax,[ebp-04h];	teb
	mov	[eax],ecx

; 143     return frame->Prev;
	mov	eax,[ebp+08h];	frame
	mov	eax,[eax]
	leave	
	ret	
EXC_pop_frame	endp

; 281 static extern "C" DWORD EXC_CallHandler( WINEXCEPTION_RECORD *record, WINEXCEPTION_FRAME *frame,
	align 04h
        PUBLIC _EXC_CallHandler

_EXC_CallHandler	proc
	push	ebp
	mov	ebp,esp
	sub	esp,010h
	sub	esp,04h
	mov	[ebp+08h],eax;	record
	mov	[ebp+0ch],edx;	frame
	mov	[ebp+010h],ecx;	context

; 296     newframe.frame.Handler = nested_handler;
	mov	eax,[ebp+01ch];	nested_handler
	mov	[ebp-08h],eax;	newframe

; 297     newframe.prevFrame     = frame;
	mov	eax,[ebp+0ch];	frame
	mov	[ebp-04h],eax;	newframe

; 298     EXC_push_frame( &newframe.frame );
	lea	eax,[ebp-0ch];	newframe
	call	EXC_push_frame

; 299     dprintf(("KERNEL32: Calling handler at %p code=%lx flags=%lx\n",
IFDEF DEBUG
	cmp	word ptr  _DbgEnabledKERNEL32+020h,01h
	jne	@BLBL20
	mov	eax,[ebp+08h];	record
	push	dword ptr [eax+04h]
	mov	eax,[ebp+08h];	record
	push	dword ptr [eax]
	push	dword ptr [ebp+018h];	handler
	push	offset FLAT:@CBE8
	call	WriteLog
	add	esp,010h
ENDIF

; 300            handler, record->ExceptionCode, record->ExceptionFlags));
@BLBL20:

; 301     ret = handler( record, frame, context, dispatcher );
	push	dword ptr [ebp+014h];	dispatcher
	push	dword ptr [ebp+010h];	context
	push	dword ptr [ebp+0ch];	frame
	push	dword ptr [ebp+08h];	record
	call	dword ptr [ebp+018h];	handler
	mov	[ebp-010h],eax;	ret

IFDEF DEBUG
; 302     dprintf(("KERNEL32: Handler returned %lx\n", ret));
	cmp	word ptr  _DbgEnabledKERNEL32+020h,01h
	jne	@BLBL21
	push	dword ptr [ebp-010h];	ret
	push	offset FLAT:@CBE9
	call	WriteLog
	add	esp,08h
@BLBL21:
ENDIF

; 303     EXC_pop_frame( &newframe.frame );
	lea	eax,[ebp-0ch];	newframe
	call	EXC_pop_frame

; 304     return ret;
	mov	eax,[ebp-010h];	ret
	add	esp,04h
	leave	
	ret	
_EXC_CallHandler	endp

endif ; ifndef __EMX__

CODE32          ENDS

                END
