Dies sind die ersten Versuche ein für .NET 2.0 geschriebenes EXE mit einem Debugger zu untersuchen.

Das Ziel dieses Beispieles ist, alle CLR Exception die in einer .NET Assembly geworfen werden, aber vielleicht durch Exception Handling für den Betreiber des Assembly nicht sichtbar sind, zu untersuchen.

Dafür erstellen wir zuerst eine einfache Konsolen Anwendung mit Visual Studio.

Auszug aus program.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace ExceptionThrowerCon
{
    class Program
    {
        static void Main(string[] args)
        {
            String txtRead="";
            Console.WriteLine("Enter your custom exception text. Exit with string \"quit\" or Ctrl+C");
            while (!(txtRead = Console.ReadLine()).ToLower().Equals("quit"))
            {
                try
                {
                    throw new Exception("Some custom exception text: " + txtRead);
                }
                catch (Exception ex)
                {
                    ex = ex;
                    //do nothing
                }
            }

        }
    }
}

Wie man sieht, wir in diesem Program eine Exception durch einen try - catch Block abgefangen und ist somit von "aussen" nicht mehr sichtbar. In diesem Beispiel wird die Exception nicht weiter behandelt aber ein parktisches Beispiel wäre z.B. eine Timeout Exception beim Verwenden einer TCP Verbindung die abgefangen wird (z.B. nach 30 sec) und dazu führt, das im catch Block die Verbindung wiederhergestellt wird. Wenn man dieses Applikation nun ausführt und regelmässig Verzögerungen von ~30 Sekunden auftreten, möchte man schon gern wissen, wo das herkommt, da eine grössere Anwendung oft nicht nur eine Netzwerkabhängigkeit hat.

Wir verwenden dafür aber unser einfaches Beispiel um das Prinzip dahinter leichter zu verstehen.

Nach dem das Konsolen Programm kompiliert wurde und als ausführbare EXE zur Verfügung steht können wir nun mit einem Debugger untersuchen. In diesem Beispiel verwenden wir den Windows Debugger WinDBG aus den "Debugging Tools for Windows" (siehe dazu Debugging Tools for Windows online; weitere Informationen und Download)

Debugging Tools for Windows müssen einmal auf einem Rechner installiert werden und können dann weiters per Copy&Paste verteilt werden.

Wir starten nun WinDBG (z.B. "C:\Program Files\Debugging Tools for Windows\windbg.exe")

Nun öffnen wir im Menü "File" den Punkt "Open Executable..." und wählen das kompilierte Executable aus (z.B. D:\Public\Debugging\DOTNET Exceptions\ExceptionThrowerCon\ExceptionThrowerCon\bin\Debug\ExceptionThrowerCon.exe)

Das Executable und ein paar Module werden geladen und der Debugger stoppt dann sofort mit einer "Break instruction exception". Bis hier hin wurden noch keine .NET Module geladen.

Nun geben wir folgende Kommandos in der unteren Zeile neben 0:000> ein:
sxr [ENTER] ... Reset Debugger Aktionen für Exceptions/Events
sxe CLR [ENTER] ... Stop in Debugger when CLR Exceptions auftreten
g [ENTER] ... GO ==> Program wird ausgeführt

Nach dem GO Kommando werden weitere Module geladen. Besonders interessant ist hier das Modul C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll (Microsoft .NET Runtime Common Language Runtime).

In unserem Consolen Programm können wir nun einen Text eingeben und mit Enter abschliessen.

Der Debugger bleibt nun bei einer CLR Exception hängen.

Leider sehen wir hier nur ein paar Registerinformationen mit denen wir nicht viel anfangen. Um die Exception aber leserlicher zu machen, gibt es ein Modul SOS.dll mit dem weitere Kommandos zum Debugger hinzugefügt werden, mit denen wir lesbare Informationen gewinnen können.

Dazu wird folgendes eingegeben:
.loadby sos mscorwks
Damit wird das Modul sos.dll aus dem selben Verzeichnis wie das Modul mscorwks geladen.

Folgende Kommandos helfen uns nun mehr Informationen zu bekommen
!pe [ENTER] ... Abkürzung für !PrintException
!clrstack [ENTER] ... Ausgabe des Thread Stacks in dem die Exception passiert ist

Damit wissen wir nun alles, was wir wissen wollten.
Exception type
Message
und den Stacktrace des Threads, der die Exception verursacht hat.

Nun kann es aber noch sein, dass viele Exceptions auftreten, bevor wir eine brauchbare finden. Und immer mit g (=GO) den Debugger wieder weiterlaufen zu lassen ist nicht bequem.

Folgendes Kommando schafft Abhilfe:
sxe -c "!pe;!clrstack;gc" clr [ENTER] ... Enable Debugger break für CLR Exception und führt dann die Befehle nach -c aus
        !pe ... Print Exception
        !clrstack ... Print Thread Stack
        gc ... GO
Dadurch wird automatisch durch das GO am Ende das Programm nachdem die Ausgaben im Debugger erfolgt sind, weiter ausgeführt.

Nähere Informationen zu den Kommandos gibt's in der Hilfe zu WINdbg die man mit F1 starten kann. Für die SOS Hilfe muss man das Kommando !clr10/sos.help eingeben.

Happy coding ;-)