{ keep exception raising compatible between Delphi and C++, so } { when you make changes here, consult with the relevant C++ } { exception handling engineer. The C++ code is in xx.cpp, in } { the RTL sources, in function tossAnException. }
{ -> EAX Pointer to exception object } { [ESP] Error address }
OR EAX, EAX JNE @@GoAhead
MOV EAX, 216 // reMap 数组: 216 = reAccessViolation CALL _RunError @@GoAhead:
POP EDX // ESP 的值 ??
PUSH ESP PUSH EBP PUSH EDI PUSH ESI PUSH EBX
PUSH EAX { pass class argument } PUSH EDX { pass address argument }
PUSH ESP { pass pointer to arguments } PUSH 7 { there are seven arguments } PUSH cNonContinuable { we can't continue execution } PUSH cDelphiException { our magic exception code } PUSH EDX { pass the user's return address } JMP RaiseExceptionProc // 实际上是呼叫 RaiseException API end;
=============================================================================== ⊙ _RaiseAgain procedure
=============================================================================== procedure _RaiseAgain; asm
{ -> [ESP ] return address to user program } { [ESP+ 4 ] raise list entry (4 dwords) } { [ESP+ 4+ 4*4] saved topmost frame } { [ESP+ 4+ 5*4] saved registers (4 dwords) } { [ESP+ 4+ 9*4] return address to OS } { -> [ESP+ 4+10*4] excPtr: PExceptionRecord } { [ESP+ 8+10*4] errPtr: PExcFrame }
{ Point the error handler of the exception frame to something harmless }
MOV EAX,[ESP+8+10*4]
MOV [EAX].TExcFrame.desc,offset @@exit
{ Pop the RaiseList }
CALL SysInit.@GetTLS
MOV EDX,[EAX].RaiseListPtr
MOV ECX,[EDX].TRaiseFrame.NextRaise MOV [EAX].RaiseListPtr,ECX
{ Destroy any objects created for non-delphi exceptions }
MOV EAX,[EDX].TRaiseFrame.ExceptionRecord
AND [EAX].TExceptionRecord.ExceptionFlags,NOT cUnwinding CMP [EAX].TExceptionRecord.ExceptionCode,cDelphiException JE @@delphiException
MOV EAX,[EDX].TRaiseFrame.ExceptObject CALL TObject.Free CALL NotifyReRaise
@@delphiException:
XOR EAX,EAX ADD ESP,5*4
MOV EDX,FS:[EAX] POP ECX
MOV EDX,[EDX].TExcFrame.next MOV [ECX].TExcFrame.next,EDX
POP EBP POP EDI POP ESI POP EBX @@exit:
MOV EAX,1 end;
=============================================================================== ⊙ _HandleFinally procedure
===============================================================================
{ System.pas }
procedure _HandleFinally; asm
{ -> [ESP+ 4] excPtr: PExceptionRecord } { [ESP+ 8] errPtr: PExcFrame } { [ESP+12] ctxPtr: Pointer } { [ESP+16] dspPtr: Pointer } { <- EAX return value - always one }
MOV EAX,[ESP+4] // EAX <- TExceptionRecord 指针 MOV EDX,[ESP+8] // EDX <- TExcFrame 指针 TEST [EAX].TExceptionRecord.ExceptionFlags,cUnwindInProgress JE @@exit
MOV ECX,[EDX].TExcFrame.desc // ECX <- 异常处理函数地址 MOV [EDX].TExcFrame.desc,offset @@exit
// 替换当前异常处理函数为 @@exit // 说明已经 finally 块已经调用过
PUSH EBX // 保存堆栈 PUSH ESI PUSH EDI PUSH EBP
MOV EBP,[EDX].TExcFrame.hEBP // 恢复异常发生前的 EBP
ADD ECX,TExcDesc.instructions // ECX <- finally 跳转的地址 CALL NotifyExceptFinally
CALL ECX // 调用 finally 函数块中的指针
POP EBP // 恢复堆栈 POP EDI POP ESI
POP EBX
@@exit:
MOV EAX,1 end;
=============================================================================== ⊙ _HandleAnyException procedure
===============================================================================
procedure _HandleAnyException; asm
{$IFDEF PC_MAPPED_EXCEPTIONS}
CMP ECX, UW_EXC_CLASS_BORLANDCPP // C++ exception? JNE @@handleIt // nope, handle it // C++ exceptions aren't wanted here. Retoss them as is CALL SysRaiseCPPException
@@handleIt:
PUSH EAX PUSH EDX
CALL UnblockOSExceptions POP EDX POP EAX
// If the exception is a Delphi exception thrown from C++, coopt it. CALL MaybeCooptException
OR [EAX].TRaisedException.Flags, excIsBeingHandled CALL LinkException MOV ESI, EBX MOV EDX, [ESP] CALL NotifyExcept MOV EBX, ESI {$ENDIF}
{$IFNDEF PC_MAPPED_EXCEPTIONS}
{ -> [ESP+ 4] excPtr: PExceptionRecord } { [ESP+ 8] errPtr: PExcFrame } { [ESP+12] ctxPtr: Pointer } { [ESP+16] dspPtr: Pointer } { <- EAX return value - always one }
MOV EAX,[ESP+4]
TEST [EAX].TExceptionRecord.ExceptionFlags,cUnwindInProgress JNE @@exit
CMP [EAX].TExceptionRecord.ExceptionCode,cDelphiException MOV EDX,[EAX].TExceptionRecord.ExceptObject MOV ECX,[EAX].TExceptionRecord.ExceptAddr JE @@DelphiException CLD
CALL _FpuInit
MOV EDX,ExceptObjProc TEST EDX,EDX JE @@exit CALL EDX TEST EAX,EAX JE @@exit
MOV EDX,[ESP+12]
MOV ECX,[ESP+4]
CMP [ECX].TExceptionRecord.ExceptionCode,cCppException JE @@CppException
CALL NotifyNonDelphiException {$IFDEF MSWINDOWS}
CMP BYTE PTR JITEnable,0 JBE @@CppException
CMP BYTE PTR DebugHook,0
JA @@CppException // Do not JIT if debugging LEA ECX,[ESP+4] PUSH EAX PUSH ECX
CALL UnhandledExceptionFilter
CMP EAX,EXCEPTION_CONTINUE_SEARCH POP EAX JE @@exit MOV EDX,EAX MOV EAX,[ESP+4]
MOV ECX,[EAX].TExceptionRecord.ExceptionAddress JMP @@GoUnwind {$ENDIF}
@@CppException:
MOV EDX,EAX MOV EAX,[ESP+4]
MOV ECX,[EAX].TExceptionRecord.ExceptionAddress
@@DelphiException: {$IFDEF MSWINDOWS}
CMP BYTE PTR JITEnable,1 JBE @@GoUnwind
CMP BYTE PTR DebugHook,0 { Do not JIT if debugging } JA @@GoUnwind PUSH EAX
LEA EAX,[ESP+8] PUSH EDX PUSH ECX PUSH EAX
CALL UnhandledExceptionFilter
CMP EAX,EXCEPTION_CONTINUE_SEARCH POP ECX POP EDX POP EAX JE @@exit {$ENDIF}
@@GoUnwind:
OR [EAX].TExceptionRecord.ExceptionFlags,cUnwinding
PUSH EBX XOR EBX,EBX PUSH ESI PUSH EDI PUSH EBP
MOV EBX,FS:[EBX]
PUSH EBX { Save pointer to topmost frame } PUSH EAX { Save OS exception pointer } PUSH EDX { Save exception object } PUSH ECX { Save exception address }
MOV EDX,[ESP+8+8*4]
PUSH 0 PUSH EAX
PUSH offset @@returnAddress PUSH EDX
CALL RtlUnwindProc @@returnAddress:
MOV EDI,[ESP+8+8*4]
{ Make the RaiseList entry on the stack }
CALL SysInit.@GetTLS PUSH [EAX].RaiseListPtr
MOV [EAX].RaiseListPtr,ESP
MOV EBP,[EDI].TExcFrame.hEBP MOV EBX,[EDI].TExcFrame.desc
MOV [EDI].TExcFrame.desc,offset @@exceptFinally
ADD EBX,TExcDesc.instructions CALL NotifyAnyExcept JMP EBX
@@exceptFinally:
JMP _HandleFinally
@@destroyExcept:
{ we come here if an exception handler has thrown yet another exception } { we need to destroy the exception object and pop the raise list. }
CALL SysInit.@GetTLS
MOV ECX,[EAX].RaiseListPtr
MOV EDX,[ECX].TRaiseFrame.NextRaise MOV [EAX].RaiseListPtr,EDX
MOV EAX,[ECX].TRaiseFrame.ExceptObject JMP TObject.Free
@@exit:
MOV EAX,1
{$ENDIF} { not PC_MAPPED_EXCEPTIONS } end;
=============================================================================== ⊙ _HandleOnException procedure
=============================================================================== { System._HandleOnException }
procedure _HandleOnException; asm
{ -> [ESP+ 4] excPtr: PExceptionRecord } { [ESP+ 8] errPtr: PExcFrame } { [ESP+12] ctxPtr: Pointer } { [ESP+16] dspPtr: Pointer } { <- EAX return value - always one }
// 如果 ExceptionFlags 是 cUnwindInProgress 则退出