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 ;-)