11

I want use JCLDebug to log all exceptions raised, including the ones that are handled.

Is it possible to do that?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rafael Cruz
  • 677
  • 8
  • 18

2 Answers2

12

It's not JCL based, but it's full Open Source and works from Delphi 5 up to XE.

This logging mechanism is able to intercept any exception.

In fact, since Delphi 6, you can define a global procedure in RtlUnwindProc to be lauched when any exception is raised:

{$ifdef DELPHI5OROLDER}
procedure RtlUnwind; external kernel32 name 'RtlUnwind';
{$else}
var
  oldUnWindProc: pointer;
{$endif}

procedure SynRtlUnwind(TargetFrame, TargetIp: pointer;
  ExceptionRecord: PExceptionRecord; ReturnValue: Pointer); stdcall;
asm
  pushad
  cmp  byte ptr SynLogExceptionEnabled,0
  jz   @oldproc
  mov  eax,TargetFrame
  mov  edx,ExceptionRecord
  call LogExcept
@oldproc:
  popad
  pop ebp // hidden push ebp at asm level
{$ifdef DELPHI5OROLDER}
  jmp RtlUnwind
{$else}
  jmp oldUnWindProc
{$endif}
end;


oldUnWindProc := RTLUnwindProc;
RTLUnwindProc := @SynRtlUnwind;

This code will launch the following function:

type
  PExceptionRecord = ^TExceptionRecord;
  TExceptionRecord = record
    ExceptionCode: DWord;
    ExceptionFlags: DWord;
    OuterException: PExceptionRecord;
    ExceptionAddress: PtrUInt;
    NumberParameters: Longint;
    case {IsOsException:} Boolean of
    True:  (ExceptionInformation : array [0..14] of PtrUInt);
    False: (ExceptAddr: PtrUInt; ExceptObject: Exception);
  end;
  GetExceptionClass = function(const P: TExceptionRecord): ExceptClass;

const
  cDelphiExcept = $0EEDFAE0;
  cDelphiException = $0EEDFADE;

procedure LogExcept(stack: PPtrUInt; const Exc: TExceptionRecord);
begin
  LastError := GetLastError;
     (...) intercept the exception
  SetLastError(LastError); // code above could have changed this
end;

For Delphi 5, I had to patch the VCL in-process, because there is no global exception interceptor.

Arnaud Bouchez
  • 42,305
  • 3
  • 71
  • 159
  • Latest versions are supporting XE4/XE5, and Win32/Win64 platforms. – Arnaud Bouchez Oct 01 '13 at 14:39
  • @Arnaud Bouchez: what do I exactly need to download for Delphi2006? I would like try your SynLog helper, writing logfile on unhandled exceptions. Your link did not exactly say what .pas files are required. – Whome Sep 19 '14 at 10:28
  • 1
    The easiest is to download the [mORMot nightly build archive](http://synopse.info/files/mORMotNightlyBuild.zip), then use *SynCommons.pas / SynLZ.pas / Synopse.inc / SynopseCommit.inc*. To build the Log Viewer, you would need the whole mORMot framework, since it uses it for remote debugging. Or you can download a compiled version of the LogView tool from http://synopse.info/files/LogView.zip – Arnaud Bouchez Sep 19 '14 at 15:43
  • Using this code I am able to intercept the exception but how I can get the stack trace information of stack: PPtrUInt? – Miguel Febres Oct 04 '18 at 17:20
  • @MiguelFebres You have several methods - see how [SynLog.pas](https://github.com/synopse/mORMot/blob/9fe7d6197674648208516f886ff922f90f3b8e07/SynLog.pas#L4640) does it. – Arnaud Bouchez Oct 22 '18 at 07:10
3

Take a look at JclAddExceptNotifier in the JclHookExcept unit.

Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477