Delphi 的 Exception 机制浅探

2019-08-30 15:37

Delphi 的 Exception 机制浅探

savetime2k@yahoo.com 2004.4.24 http://savetime.delphibbs.com

目 录

=============================================================================== ⊙

===============================================================================

本文排版格式为:

正文由窗口自动换行;所有代码以 80 字符为边界;中英文字符以空格符分隔。

(作者保留对本文的所有权利,未经作者同意请勿在在任何公共媒体转载。)

=============================================================================== ⊙ 问题

=============================================================================== EXCEPTION_DISPOSITION __cdecl _except_handler ( struct _EXCEPTION_RECORD *ExceptionRecord, void * EstablisherFrame,

struct _CONTEXT *ContextRecord, void * DispatcherContext ); /*

* Exception disposition return values. */

typedef enum _EXCEPTION_DISPOSITION { ExceptionContinueExecution, ExceptionContinueSearch, ExceptionNestedException, ExceptionCollidedUnwind } EXCEPTION_DISPOSITION;

Exception 是线程相关的

{$IFDEF PIC}

{$IFDEF PC_MAPPED_EXCEPTIONS}

RaiseExceptionProc := @RaiseException; 被执行了两次 _StartExe,initialization中都有

正 文

=============================================================================== ⊙ 数据结构

=============================================================================== cContinuable = 0; cNonContinuable = 1; cUnwinding = 2; cUnwindingForExit = 4;

cUnwindInProgress = cUnwinding or cUnwindingForExit; cDelphiException = $0EEDFADE; cDelphiReRaise = $0EEDFADF; cDelphiExcept = $0EEDFAE0;

cDelphiFinally = $0EEDFAE1; cDelphiTerminate = $0EEDFAE2; cDelphiUnhandled = $0EEDFAE3; cNonDelphiException = $0EEDFAE4; cDelphiExitFinally = $0EEDFAE5;

cCppException = $0EEFFACE; { used by BCB } EXCEPTION_CONTINUE_SEARCH = 0; EXCEPTION_EXECUTE_HANDLER = 1; EXCEPTION_CONTINUE_EXECUTION = -1;

JmpInstruction = packed record opCode: Byte; distance: Longint; end;

TExcDescEntry = record vTable: Pointer; handler: Pointer; end;

PExcDesc = ^TExcDesc; TExcDesc = packed record jmp: JmpInstruction; case Integer of

0: (instructions: array [0..0] of Byte);

1{...}: (cnt: Integer; excTab: array [0..0{cnt-1}] of TExcDescEntry); end;

PExcFrame = ^TExcFrame; TExcFrame = record next: PExcFrame; desc: PExcDesc; hEBP: Pointer; case Integer of 0: ( );

1: ( ConstructedObject: Pointer ); 2: ( SelfOfMethod: Pointer ); end;

PExceptionRecord = ^TExceptionRecord; TExceptionRecord = record

ExceptionCode : LongWord; ExceptionFlags : LongWord;

OuterException : PExceptionRecord; ExceptionAddress : Pointer; NumberParameters : Longint; case {IsOsException:} Boolean of

True: (ExceptionInformation : array [0..14] of Longint); // 15 * 4 bytes False: (ExceptAddr: Pointer; ExceptObject: Pointer); // 16 bytes end;

typedef struct _EXCEPTION_RECORD { DWORD ExceptionCode; DWORD ExceptionFlags;

struct _EXCEPTION_RECORD* ExceptionRecord; PVOID ExceptionAddress; DWORD NumberParameters;

ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];

} EXCEPTION_RECORD, *PEXCEPTION_RECORD;

=============================================================================== ⊙ InitExceptions procedure

=============================================================================== SysUtils.pas 的 initialization 中 InitExceptions;

{ SysUtils.InitExceptions } procedure InitExceptions; begin

OutOfMemory := EOutOfMemory.CreateRes(@SOutOfMemory);

InvalidPointer := EInvalidPointer.CreateRes(@SInvalidPointer); ErrorProc := ErrorHandler; ExceptProc := @ExceptHandler; ExceptionClass := Exception;

ExceptClsProc := @GetExceptionClass; ExceptObjProc := @GetExceptionObject;

AssertErrorProc := @AssertErrorHandler; AbstractErrorProc := @AbstractErrorHandler; end;

{ SysUtils.ErrorHandler }

procedure ErrorHandler(ErrorCode: Byte; ErrorAddr: Pointer); export; var

E: Exception; begin

case ErrorCode of Ord(reOutOfMemory): E := OutOfMemory; Ord(reInvalidPtr): E := InvalidPointer;

Ord(reDivByZero)..Ord(High(TRuntimeError)): begin

with ExceptMap[ErrorCode] do E := EClass.Create(EIdent); end; else

E := CreateInOutError; end;

raise E at ErrorAddr; end;

{ SysUtils.ExceptHandler }

procedure ExceptHandler(ExceptObject: TObject; ExceptAddr: Pointer); far; begin

ShowException(ExceptObject, ExceptAddr); Halt(1); end;

=============================================================================== ⊙ DoneExceptions procedure

=============================================================================== procedure DoneExceptions; begin

if Assigned(OutOfMemory) then

begin

OutOfMemory.AllowFree := True; OutOfMemory.FreeInstance; OutOfMemory := nil; end;

if Assigned(InvalidPointer) then begin

InvalidPointer.AllowFree := True; InvalidPointer.Free; InvalidPointer := nil; end;

ErrorProc := nil; ExceptProc := nil; ExceptionClass := nil; ExceptClsProc := nil; ExceptObjProc := nil; AssertErrorProc := nil; end;

=============================================================================== ⊙ SetExceptionHandler procedure

=============================================================================== System._StartExe 中启动 SetExceptionHandler 过程设置缺省的异常处理函数(System._ExceptionHandler)。

{ System.SetExceptionHandler }

procedure SetExceptionHandler; asm

XOR EDX,EDX { using [EDX] saves some space over [0] } LEA EAX,[EBP-12] // EBP-12 是 TExcFrame.desc

MOV ECX,FS:[EDX] { ECX := head of chain } MOV FS:[EDX],EAX { head of chain := @exRegRec }

MOV [EAX].TExcFrame.next,ECX

MOV [EAX].TExcFrame.desc,offset _ExceptionHandler MOV [EAX].TExcFrame.hEBP,EBP MOV InitContext.ExcFrame,EAX end;

=============================================================================== ⊙ _ExceptionHandler procedure

===============================================================================

{ System._ExceptionHandler }

procedure _ExceptionHandler; asm

MOV EAX,[ESP+4]

TEST [EAX].TExceptionRecord.ExceptionFlags,cUnwindInProgress JNE @@exit

CMP BYTE PTR DebugHook,0 JA @@ExecuteHandler LEA EAX,[ESP+4] PUSH EAX

CALL UnhandledExceptionFilter

CMP EAX,EXCEPTION_CONTINUE_SEARCH JNE @@ExecuteHandler JMP @@exit

@@ExecuteHandler:

MOV EAX,[ESP+4] CLD

CALL _FpuInit MOV EDX,[ESP+8]

PUSH 0 PUSH EAX

PUSH offset @@returnAddress PUSH EDX

CALL RtlUnwindProc

@@returnAddress:

MOV EBX,[ESP+4]

CMP [EBX].TExceptionRecord.ExceptionCode,cDelphiException MOV EDX,[EBX].TExceptionRecord.ExceptAddr MOV EAX,[EBX].TExceptionRecord.ExceptObject JE @@DelphiException2

MOV EDX,ExceptObjProc TEST EDX,EDX

JE MapToRunError MOV EAX,EBX CALL EDX TEST EAX,EAX

JE MapToRunError

MOV EDX,[EBX].TExceptionRecord.ExceptionAddress

@@DelphiException2:

CALL NotifyUnhandled MOV ECX,ExceptProc TEST ECX,ECX

JE @@noExceptProc

CALL ECX { call ExceptProc(ExceptObject, ExceptAddr) }

@@noExceptProc:

MOV ECX,[ESP+4] MOV EAX,217

MOV EDX,[ECX].TExceptionRecord.ExceptAddr MOV [ESP],EDX JMP _RunError

@@exit:

XOR EAX,EAX end;

=============================================================================== ⊙ _RaiseExcept procedure

===============================================================================

{ System._RaiseExcept }

procedure _RaiseExcept; asm

{ When making changes to the way Delphi Exceptions are raised, } { please realize that the C++ Exception handling code reraises } { some exceptions as Delphi Exceptions. Of course we want to }


Delphi 的 Exception 机制浅探.doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:滇池调研报告

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: