Der Historical Debugger in VS2010

Schon vor einiger Zeit hat Microsoft angekündigt, dass Visual Studio 2010 einen neuen, speziellen Debugger namens Historical Debugger enthalten wird. Man findet z.B. hier eine Ankündigung aus dem Oktober 2008:

Are you tired of constantly setting breakpoints to hone in on a pesky bug? How would you like to be able to step „back in time“ through your debugger? The Historical Debugger in Visual Studio Team System 2010 promises to revolutionize your debugging experience.

Ich sagte mir, na das ist doch mal was Interessantes: Irgendwie rückwärts durch ein Programm debuggen? Weil ich für Revolutionen immer zu haben bin und als „Systemprogrammierer“ einfach wissen muss, wie man einen Debugger implementiert, der so etwas leistet, bin ich der Sache heute auf den Grund gegangen und kann nun berichten, worum es geht.

Zunächst musste ich eine Hürde aus dem Weg räumen: Der Historical Debugger ist tatsächlich nur im Visual Studio Team System 2010 verfügbar, das „normale“ Visual Studio ohne TS, das ich mir zuerst testweise installiert hatte, enthält ihn nicht. Man findet die VS2010-TS-Preview als ISO-Download hier.

Der Witz an der Sache ist der folgende: Der Historical Debugger schreibt selbständig zu bestimmten Zeitpunkten während der Programmausführung ein Log mit Informationen über den Zustand des Programms zum jeweiligen Zeitpunkt. Der angepriesene „Schritt zurück in der Zeit“ besteht darin, nach einem Stopp des Programms aus der Debug History, d.h. der Liste der Zeitpunkte, einen Eintrag auszuwählen und sich im Debugger den Zustand des Programms anzuschauen, wie er damals war.

Das kann natürlich – im Prinzip – ganz nützlich sein: Hat man z.B. einen Breakpoint erreicht und stellt fest, dass eine Variable einen falschen Wert aufweist, muss man nun nicht mehr mit dem Debugging von vorne beginnen und sich vorsichtig an den Zeitpunkt heranpirschen, wo der falsche Wert zum ersten Mal auftaucht, sondern kann bequem und entspannt die Debug History verwenden, um den Zeitpunkt zu finden oder mindestens stark einzugrenzen, wo die Sache aus dem Ruder läuft.

Man kann in 2 Stufen wählen, wie die Zeitpunkte bestimmt werden sollen: Log schreiben entweder bei „wichtigen Systemereignissen“ oder bei solchen Ereignissen plus bei jedem Methoden-Aufruf. Man kann hier erahnen, dass die Sache Potential hat auszuufern, denn Methoden-Aufrufe können ja sehr zahlreich sein.

Ins Log geschrieben werden der Call Stack zum Zeitpunkt und Variablen-Werte zum Zeitpunkt, wobei man bei Objekten nur noch das Resultat von ToString sieht, aber keinen Zugriff mehr bekommt auf die einzelnen Komponenten.

Ein paar Screenshots hierzu findet man im Blog Dariusz quatscht hier.

Meiner Meinung nach ist das ganz hübsch, aber ob es für eine Revolution reicht, ist fraglich. Insbesondere die doch sehr eingeschränkte historische Sicht auf Variablen-Werte enttäuscht. Mir ist schon klar, dass es schlicht unmöglich ist, zu Hunderten von Zeitpunkten den gesamten Heap ins Log zu schreiben, damit ich auch nachträglich noch Objekte mit all ihren Details anschauen kann, aber hey, es hätte ja sein können, dass jemand mit Hilfe einer genialen Idee ein Log implementiert hat, das viele Details mit praktikablem Aufwand speichern kann, z.B. mit einer Heap-Differenzen-Methode…

Was haben andere so gemacht in Sachen Debugger mit Historie? Hier ist von einem experimentellen Java-Debugger die Rede, der vor ein paar Jahren implementiert wurde und der offenbar alle Variablen-Zuweisungen während eines Programmlaufs protokolliert, indem er sich in die Pseudocode-Ausführung der JVM einklinkt. Er nennt sich denn auch treffend Omniscient Debugger („allwissender Debugger“) und erlaubt offenbar die volle Sicht zu einem beliebigen Zeitpunkt.

In einer PDF-Datei, welche den Debugger genauer beschreibt, findet sich die Information, dass Apache Ant etwa 24 Millionen Variablen-Zuweisungen macht, während das Tool seine eigene Kompilation steuert. Das sind eine ganze Menge, aber nicht so viele, dass sie den Ansatz an sich gleich zu Fall bringen.

VMWare hat etwas im Angebot, das die Firma Replay Debugging nennt, beschrieben auf der Website hier. Unterstützt wird Debugging für C/C++, wie man im Artikel hier nachlesen kann. Das ganze funktioniert mit Hilfe der Virtual Machine, wo man natürlich wie bei der JVM eine zentrale Stelle hat, wo man sich einklinken kann, um zu protokollieren, was läuft. Das Debugging, sprich der Blick auf das Log findet statt in einem Visual Studio, das um ein VMWare-Plugin ergänzt wurde.

Anhand der Beschreibung vermute ich, dass komplett protokolliert wird und man so in einzelnen Schritten vorwärts und sogar rückwärts durch das Programm gehen kann. Die Suche nach dem Punkt im Programm, wo eine Datenstruktur „zerstört“ wird, finde man so: Zeitpunkt finden, wo sie falsch ist, dann Programm „rückwärts laufen lassen“ mit Daten-Breakpoint auf der Struktur und einfach auf den Break durch Veränderung warten.

Hier meldet sich natürlich wieder meine Neugier, die mich veranlasst hat, überhaupt erst den Historical Debugger von Microsoft anzuschauen und die sich nun fragt: Wie macht VMWare das? Ich vermute, dass die komplette Abfolge aller CPU-Befehle, welche das Programm ausführte, der zentrale Bestandteil des Logs ist, und dass das „Debugging“ darin besteht, mit Hilfe der Virtual Machine das Programm irgendwie entlang dieser Abfolge zu führen, vielleicht gestützt auf Komplett-Speicherabzüge in gewissen Zeitabständen.

Und ich vermute ebenfalls, dass die Sache derart auf die Ausführung direkter CPU-Anweisungen zentriert ist, dass die Ausdehnung des Prinzips auf C# mit seinem JIT-Compiler eine schwierige bis unmögliche Sache werden dürfte.

Veröffentlicht in Keine Kategorie. Schlagwörter: , . 1 Comment »

Eine Antwort to “Der Historical Debugger in VS2010”

  1. Adrian Lienhard Says:

    Danke für den interessanten Artikel!

    Aus der Sicht der aktuellen Forschung lässt sich ergänzen:

    Nach dem „Omniscient Debugger“ wurde im Jahr 2007 (auf der OOPSLA Konferenz) ein neuer Back-In-Time Debugger vorgestellt, der besser skaliert: http://pleiad.dcc.uchile.cl/tod/. Die Daten werden dabei in eine relationale DB abgelegt und das ganze ist cluster-fähig (falls man die Hardware dazu hat ;)).

    Eine neuartige Idee, wie man sehr effizient die History aufzeichnen kann (und von Objekten nicht nur eine String-Repräsentation sondern die vollständige History aller Variablen-Zuweisungen speichert) habe ich hier publiziert: http://scg.unibe.ch/archive/papers/Lien08bBackInTimeDebugging.pdf


Hinterlasse einen Kommentar