2013-04-08 5 views
5

Ich versuche herauszufinden, wie eine Stack-Trace erhalten, nachdem eine Ausnahme in Delphi geworfen wird. Wenn ich jedoch versuche, den Stapel im Application.OnException-Ereignis mithilfe der Funktion unten zu lesen, scheint der Stapel bereits gelöscht zu werden und durch die Wurftechniken ersetzt zu werden.Delphi erhalten Stack-Trace nach Ausnahme

function GetStackReport: AnsiString; 
var 
    retaddr, walker: ^pointer; 
begin 

    // ... 

    // History of stack, ignore esp frame 
    asm 
     mov walker, ebp 
    end; 

    // assume return address is present above ebp 
    while Cardinal(walker^) <> 0 do begin 
     retaddr := walker; 
     Inc(retaddr); 
     result := result + AddressInfo(Cardinal(retaddr^)); 
     walker := walker^; 
    end; 
end; 

Hier ist was für Ergebnisse Ich erhalte:

001A63E3: TApplication.HandleException (Forms) 
00129072: StdWndProc (Classes) 
001A60B0: TApplication.ProcessMessage (Forms) 

Das ist offensichtlich nicht das, was ich suche, obwohl es korrekt ist. Ich möchte den Stapel so abrufen, wie er gerade war, bevor die Ausnahme ausgelöst wurde, oder mit anderen Worten, den Inhalt vor dem OnException-Aufruf.

Gibt es eine Möglichkeit, das zu tun?

Ich bin mir bewusst, dass ich das Rad neu erfinde, weil die Leute bei madExcept/Eurekalog/jclDebug dies bereits getan haben, aber ich würde gerne wissen, wie es gemacht wird.

+0

Wie gut lesen Sie Assembler? ;-) –

+6

Ich habe nie verstanden warum der RTL das nicht eingebaut hat ... –

+0

@WarrenP: einigermaßen gut, oder zumindest gut genug, um das beheben zu können, dachte ich, aber ich habe kein Glück, wie es scheint . :( – Orwell

Antwort

12

Es ist nicht möglich, innerhalb des OnException Ereignisses manuell eine brauchbare Stapelprotokollierung zu erhalten. Wie Sie bereits bemerkt haben, ist der Stapel zum Zeitpunkt des Fehlers bereits verschwunden, als das Ereignis ausgelöst wurde. Was Sie suchen, erfordert das Abrufen des Stack-Trace zum Zeitpunkt der Ausnahmebedingung. Fremd-Ausnahme-Protokollierer, wie MadExcept, EurekaLog usw., behandeln diese Details für Sie, indem sie sich in Schlüsselfunktionen und Kernausnahmehandler innerhalb der RTL selbst einklinken.

In der letzten Delphi-Versionen, die SysUtils.Exception Klasse jetzt öffentlich StackTrace und StackInfo Eigenschaften hat, die in dem OnException Ereignisse außer die Tatsache, nützlich wäre, dass Embarcadero NICHT diese Eigenschaften nativ aus unbekannten Gründen zu implementieren gewählt hat. Es erfordert, dass Dritt-Ausnahmeprotokollierer Handler verschiedenen Callbacks zuweisen, die von der Klasse Exception ausgesetzt werden, um Stapelverfolgungsdaten für die Eigenschaften zu generieren.Wenn Sie jedoch beispielsweise JclDebug installiert haben, können Sie eigene Callback-Handler in Ihrem eigenen Code bereitstellen, die die Stapelverfolgungsfunktionen von JCL verwenden, um die Stapeldaten für die Eigenschaften zu generieren.

+0

Die Gründe sind überhaupt nicht unbekannt. Die Felder wurden als ein Service hinzugefügt, um die Werkzeuge von Drittanbietern zu helfen. Die Felder stellen einen allgemeinen Platz für sie zur Verfügung, um ihre Informationen zu platzieren. Emba füllte sie nicht, weil das der ist Job der Bibliotheken von Drittanbietern –

+0

Der Grund könnte denen bekannt sein, die den Newsgroups oder anderen Quellen folgen, aber die Online-Hilfe erwähnt es nicht: http://docwiki.embarcadero.com/Libraries/XE3/en/System.SysUti ls.Exception.StackTrace – dummzeuch

+14

Embarcadero ist am besten geeignet, Stack-Tracing zu implementieren, da es den Compiler überhaupt erst erstellt. Bevor die Callbacks offengelegt wurden, war das Hooking von Drittanbietern die einzige Option. Wenn die Callbacks vorhanden sind und keine native Lösung zur Verfügung steht, handelt es sich um einen IMHO-Cop-out. Embarcadero könnte und sollte, aber sie scheinen sich dafür entschieden zu haben. –

3

Ich mag würde den Stack erhalten, wie es kurz vor die Ausnahme ausgelöst wurde war, oder mit anderen Worten der Inhalt vor (nach auch tun würde), um den OnException Anruf.

Eigentlich möchten Sie nicht den Stapel vor dem Aufruf OnException. Das hast du schon. Sie möchten den Stapel an dem Punkt, an dem die Ausnahme ausgelöst wurde. Und das erfordert, dass die Stapelverfolgung so schnell wie möglich stattfindet. Es ist zu spät im OnException-Aufruf, da die Ausnahme bis zum Top-Level-Handler weitergegeben wurde.

madExcept funktioniert durch Anhängen aller RTL-Funktionen, die Ausnahmen behandeln. Und es hakt die niedrigsten Funktionen ein. Dies erfordert einige ernsthafte Anstrengungen. Wenn diese Routinen süchtig sind, kann der Code Stack-Traces erfassen und so weiter. Beachten Sie, dass das Hooking versionsspezifisch ist und Reverse Engineering des RTL erfordert.

Darüber hinaus ist das Stack Walking sehr viel fortgeschrittener als Ihr Basiscode. Ich meine das nicht in einer abfälligen Art und Weise, es ist nur so, dass der Stack, der auf x86 läuft, ein kniffliges Geschäft ist und der Code von madExcept sehr gut ist.

Das ist die Grundidee. Wenn Sie mehr erfahren möchten, können Sie den Quellcode von JclDebug kostenlos erhalten. Oder kaufen Sie madExcept und erhalten Sie die Quelle.