![]() |
In welcher Methode bin ich?
Ich muss in meinen Klassen Exceptions auslösen. Jetzt wäre es schön, wenn ich den Namen der Methode und der Klasse herausfinden könnte, wo diese Exception ausgelöst wurde, um mir die Fehlersuche zu erleichtern. Ich weiß, dass es dazu umfangreiche Komponenten-Sammlungen gibt, wie zum Beispiel Mad-Except usw. Aber das ist mir etwas zu viel Overhead. Ich bräuchte nur den Methodennamen und den Klassennamen, der ist aber nicht so wichtig.
|
Re: In welcher Methode bin ich?
Es mag Overhead sein, die entsprechenden Units z.B. aus der JCL zu benutzen - aber warum guckst Du da nicht mal kurz in die entsprechende Unit um rauszufinden, wie die den Namen rausfinden?
Ich habs auch mal gesucht und nach knapp 10 Minuten gefunden. Du bist da wahrscheinlich sogar schneller als ich, weil ich sie erst wieder runterladen müsste ;-) |
Re: In welcher Methode bin ich?
Moin Michael,
Soweit ich weiß ist das ganze nicht so einfach den methodennamen irgendwie heraus zu bekommen. daher biete ich dir mal das an wie ich es immer mache. einfach und über die macros recht schnell :-)
Delphi-Quellcode:
implementation uses Windows.....; const // PVCS Header csUnitVersion = '$Workfile: Brabelschneck.pas $ ' + '$Revision: 1.8 $ ' + '$Modtime: 10 May 2007 13:53:44 $ ' + '$Author: Relicted $';
Delphi-Quellcode:
procedure TBrabelschneck.Test(Sender: TObject);
const csFuncName = 'TBrabelschneck.Test'; begin try //do something except on E : Exception do HandleException( E, csFuncName, csUnitVersion, E.Message ); end; end; hier noch die standardmäßige implementierung bei forms die ne exception werfen..
Delphi-Quellcode:
procedure TExceptionForm.HandleException( coException : Exception;
sFuncName : String; sUnitVersion : String; sMessage : String ); begin if Assigned( OnPrintException ) then begin OnPrintException( Format( csPrtException, [ sFuncName, DelCharFromStr( [ #13, #10 ], coException.Message ), UnitVersionToStr( sUnitVersion ) ] ) ); end; raise Exception.Create( Format( csFmtException, [ sFuncName, sMessage ] ) ); end; vielleicht kannst damit ja was anfangen. gruß reli |
Re: In welcher Methode bin ich?
Zitat:
|
Re: In welcher Methode bin ich?
gibt es vielleicht eine Möglichkeit, ohne die Jedi's zu nutzen?
Gruß Frank |
Re: In welcher Methode bin ich?
Zitat:
Zitat:
|
Re: In welcher Methode bin ich?
Mit den Jedis geht es so:
In den Jedi-Optionen beim Debuginfo Converter den debug Experten aktivieren und die Debugdaten in die Exe schreiben lassen. Dann im Code die Unit JCLDebug hinzufügen und über die Funktion ProcByLevel bekommt man dann Unit, Klasse und Methode in folgender Form als Zeichenkette: "Unit.Klasse.Methode". |
Re: In welcher Methode bin ich?
@Luckie,
es gibt Wege den Unit Namen und Methoden Namen auch zur Laufzeit zu ermitteln, ohne Debug Infos. Aber das sind tiefste Tricks die auf die RTTI aufbauen und nicht mit jeder Methode funktionieren. So bald eine Methode published ist speichert der Compiler in der RTTI diese Informationen, eben Name und Aufrufparameter. Den Unit Namen kann man ermitteln relativ zum Codesegement in dem man sich befindet. Der Compiler speichert die RTTI's immer zum Codesegement das diese Unit belegt. Bei Klassen/Interface-RTTIs steht der Unit-Name mit in dieser RTTI. Dann speichert der Compiler auch noch die Einsprungspunkte in die Initialization/Finalization Sektionen der Units und über diese kann man in einer speziellen Resource den Unit Namen ermitteln, das trifft besonderst bei Packages zu bzw. dafür wurde es auch konstruiert. Gruß Hagen |
Re: In welcher Methode bin ich?
Ich meine natürlich die JCL und nicht die Jedis. ;?
@Hagen: Ich habe in meiner Klasse keine published Properties, nur private und public. ;) |
Re: In welcher Methode bin ich?
Es geht doch nicht um published Properties, sondern um published Methods :P
Ganz ohne Zusatzinfos nicht ganz einfach (wie Hagen schon sagte). Ich habe noch eine "unsichere" Möglichkeit (auch gleich getestet). Im Prinzip bekommst du aus einer Exception als wichtige Infos die Addresse des Auftretens der Exception und den Zustand aller Register zu diesem Zeitpunkt. Dummerweise funkt dir als erstes schonmal Delphi dazwischen der bei "Except" gleich einen Handler aufruft, welcher den Stack durcheinanderwirbelt ($38 Bytes untendran hängt). Man könnte jetzt über die Adresse versuchen die RTTI zu durchlaufen um eine published Methode zu finden. Ich bin allerdings noch zusätzlich davon ausgegangen, dass Delphi den self-Pointer meist in ebx legt. Einfacher wärs, wenn man die Methoden mit stdcall aufrufen würde, dann könnte man sich relativ zu ebp bewegen. Also: Ich versuche nach der Exception das Register ebx zu "retten" und mir die Adresse des Auftretens der Exception zu holen. Das sieht bei mir so aus:
Delphi-Quellcode:
Die Funktion speichert (bis zum aufruf von getMethodCode) die oben genannten Werte in TMethod. Der self-Pointer, der mutmaßlich in ebx lag, wird in TMethod.Data gelegt und die Adresse des Auftretens des Fehler in TMethod.Code. Letzteres ist allerdings noch nicht die Anfangsadresse der Methode. Dazu gehe ich in die RTTI und such nach dem Einsprungpunkt einer published Method, welcher vor Method.code liegt:
function getMethod:TMethod;
const cDelphiException = $0EEDFADE; //from Unit System asm //clear xor ecx,ecx xor edx,edx //push result push eax //try (Exception-Handling of getMethod) push ebp push offset @Exc push fs:[edx] mov fs:[edx],esp //get pointer to Exception-Context-Structure //[esp + $c + $38] //$38 because of system._HandleAnyException mov edx,[esp+$44] //old ebx is in Context.structure + $A4 mov eax,[edx+$A4] //get pointer to Exception-Structure //[esp + $4 + $38] //$38 because of system._HandleAnyException mov edx,[esp+$3C] //is Delphi Exception (=Exception created by "Raise Exception.create...") cmp [edx],cDelphiException je @@1 //non Delphi Exception mov ecx,[edx+$0C] //get Exception-Address from Exception-Structure jmp @@2 @@1: //Delphi Exception mov ecx,[edx+$14] //get Exception-Adress from data of Exception-Structure @@2: //test if eax is self-pointer mov edx,[eax] cmp edx,[edx+vmtSelfPtr] jz @mbclass xor eax,eax //if not then clear eax @mbclass: //clear own Exception-Handling xor edx,edx pop fs:[edx] pop edx pop edx jmp @fend @Exc: //handle own Exception (+ clear eax) mov esp,[esp+8] pop edx pop edx pop ebp xor eax,eax @fend: pop edx //pop result mov [edx],ecx //TMethod.code <-- ecx mov [edx+4],eax //TMethod.data <-- eax //call getMethod (if TMethod.data<>nil) test eax,eax mov eax,edx jz @end call getMethodCode @end: end;
Delphi-Quellcode:
Soweit funktioniert es bei mir. Dies alles unter den Vorraussetzungen, dass:
procedure getMethodCode(var Method:TMethod);
var mt:pointer; size:Pword; count:Pword; i,j,p:integer; adr:cardinal; adrlist:array of cardinal; found:boolean; begin if cardinal(Method.code)>=cardinal(getprocaddress(getmodulehandle('kernel32'),'RaiseException')) then exit; mt:=ppointer(integer(method.data^)+vmtMethodtable)^; if mt<>nil then begin count:=mt; mt:=pointer(cardinal(mt)+2); setlength(adrlist,count^); for i:=0 to count^-1 do adrlist[i]:=0; for i:=1 to count^ do begin size:=mt; adr:=pcardinal(cardinal(mt)+2)^; j:=count^-1; while adrlist[j] > adr do dec(j); if j>=0 then for p:=0 to j do adrlist[p]:=adrlist[p+1]; adrlist[j]:=adr; mt:=pointer(cardinal(mt)+size^); end; if cardinal(method.Code)>adrlist[0] then begin found:=false; for i:=1 to count^-1 do begin if cardinal(method.Code)<adrlist[i] then begin method.Code:=pointer(adrlist[i-1]); found:=true; break; end; end; if not found then method.Code:=pointer(adrlist[count^-1]); end else method.Code:=nil; end; end; 1. getMethod direkt nach "Except" aufgerufen wird 2. HandleAnyException nicht noch mehr "Unfug" macht (Exception-Klasse suchen, etc.), oder anderen als bei mir 3. Der self-Pointer zum Zeitpunkt der Excepton in ebx lag Punkt 1 kann man ja recht gut sicherstellen. Für Punkt 2 hilft ein eigener Exceptionhandler (in ASM) oder die Hoffnung das HandleAnyException nicht anderes reagiert und zu 3. hilft wahrscheinlich stdcall bei den Methoden, da dann der self-Pointer auf dem Stack übergeben wird.
Delphi-Quellcode:
var Method:TMethod
obj:Tobject; begin try //... except Method:=getMethod; obj:=TObject(Method.Data); if obj is TObject then begin edit1.text:=obj.ClassName+' '+ obj.MethodName(method.Code); end else edit1.Text:='Kenne ich nicht'; end; end; Edit: Bei stdcall für deine Methoden kannst du die Zeile
Delphi-Quellcode:
durch das hier ersetzen:
//old ebx is in Context.structure + $A4
mov eax,[edx+$A4]
Delphi-Quellcode:
.
//old ebp is in Context.structure + $B4
mov eax,[edx+$B4] mov eax,[eax+$08] //=self Das dürfte etwas "sicherer" sein, als sich auf ebx zu verlassen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:48 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz