Einzelnen Beitrag anzeigen

Benutzerbild von Lemmy1
Lemmy1

Registriert seit: 28. Nov 2004
Ort: Ismaning
184 Beiträge
 
Delphi 2006 Professional
 
#3

Re: Exceptionhandling wie in C++ möglich?

  Alt 3. Nov 2005, 23:54
Na also es hat geklappt. Bin jetzt soweit, dass ich im Falle einer Exception den ContextRecord via Standard-Pascal routinen modifizieren kann. Ein Beispielprojekt habe ich angehängt. Da ich hoffe, dass das noch weitere Leute brauchen können, hier die Erklärung (Assemblerkenntnisse sind hier leider notwendig):

Über
Delphi-Quellcode:
procedure CallProcedure(TargetProcedure: TParameterlessProcedure;
  ExceptionHandler : TExceptionHandlerProc);
kann eine procedure aufgerufen werden.
Es gibt zwei Parameter:
- TargetProcedure ist der aufzurufende Code
- ExceptionHandler ist der Exceptionhandler

Beispiel für einen Aufruf:
Delphi-Quellcode:
var
  Dummy : Cardinal;

procedure Test; register;
begin
  asm
    // do something that crashs
    mov eax, 0
    mov eax, [eax]
  end;
end;

function ExceptionHandlerProc(
  var ExceptionInfo : Windows.TExceptionRecord;
  EstablisherFrame : Pointer;
  var ContextRecord : Windows.TContext;
  DispatchedContext : Pointer) : TExceptionContinue; cdecl;
begin
  ContextRecord.Eax := Cardinal(@Dummy);
  Result := ecContinueExecution;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  try
    CallProcedure(Test, ExceptionHandlerProc);
    Caption := 'yes';
  except
    Caption := 'no';
  end;
end;
Was passiert hierbei? Beim Click auf Button1 wird der Funktion CallProcedure mitgeteilt, dass Sie "Test" ausführen soll. Im Falle eines Fehlers soll sie zu ExceptionHandlerProc springen. "Test" ist nun absichtlich so geschrieben, dass sie crasht. Aus diesem Grunde springt ExceptionHandlerProc ein. Sie behebt den Fehler (korrigiert das Register EAX) und sagt dem System, dass es an der gleichen Stelle weitermachen soll.

Man könnte in so einem Handler auch diverse andere Sachen tun:
- Loggen ohne den Programmfluss zu zerstören (allerdings sind die Daten im Handler dazu recht dürftig)
- EIP erhöhen, und damit die Assembler-Funktion überspringen
- Statt ecContinueExecution könnte man auch ecContinueSearch zurückgeben. In diesem Fall kann der Delphi-Exceptionhandler verwendet werden, um den Fehler zu verarbeiten.

Es gibt an dem Code noch zwei verbesserungswürdige Stellen:
  • Statt einer parameterlosen Procedure wäre es schöner, komplexere procedures aufzurufen. Mir fehlt da aber etwas die Idee, wie so etwas elegant geht, ohne 100 Überladungen zu bauen.
  • Wäre schön, wenn man TExceptionHandlerProc vereinfachen könnte. Die aktuelle Version wird direkt so vom Betriebssystem aufgerufen, womit ich keinen Einfluss auf die Signatur habe. Schöner wäre es also, innerhalb der Unit erst eine private Funktion aufzurufen, die das ganze etwas kapselt. Das würde durch Verwendung von Unit-Variablen funktionieren (man muss sich ja irgendwie den echten Handler merken), womit die Threadfähigkeit etwas im Eimer wäre. Alternativ könnte man es mit Codegenerierung zur Laufzeit versuchen, was allerdings immer mit Mühe verbunden ist.

Falls jemanden interessiert, was derzeit intern abläuft:
Delphi-Quellcode:
procedure CallProcedure(TargetProcedure: TEmptyProcedure;
  ExceptionHandler : TExceptionHandlerProc);
asm
  // Install Exception Frame
  PUSH ExceptionHandler
  PUSH FS:[0]
  MOV FS:[0], ESP

  // Call procedure
  CALL TargetProcedure

  // Restore exception handler
  MOV EAX, [ESP]
  MOV FS:[0], EAX
  ADD ESP, 8
end;
Da ich das Interface des Exceptionhandlers übersetzt habe, wurde der ASM Code selbst ziemlich klein.

Für alle, die dieses Thema interessiert: Hier gibt es einen sehr ausführlichen Crashcourse, der mir sehr geholfen hat.
Angehängte Dateien
Dateityp: zip exceptionhandling_395.zip (4,8 KB, 5x aufgerufen)
Daniel
www.nemu.com - The N64 Emulator
  Mit Zitat antworten Zitat